UWP Composition API - GroupListView(二)

还是先上效果图:

看完了上一篇UWP Composition API - GroupListView(一)的童鞋会问,这不是跟上一篇一样的吗??? 骗点击的??

No,No,其实相对上一个有更简单粗暴的方案,因为上篇是为了研究Composition API,所以含着泪都要做完(有没有被骗的赶脚)。。( ╯□╰ )

那是有没有简单点的方法呢?? 嗯,看到这篇,那答案肯定是Yes。

我再啰嗦下需求:

1.Group中的集合需要支持增量加载ISupportIncrementalLoading

2.支持UI Virtualization

这个简单的方案就是改ListViewItem的模板,其实我在UWP VirtualizedVariableSizedGridView 支持可虚拟化可变大小Item的View(二)有讲过ListViewItem有2套模板-官方地址

看一下我修改之后的模板:

        <Style TargetType="local:GroupListViewItem" >
        <Setter Property="FontFamily" Value="{ThemeResource ContentControlThemeFontFamily}" />
        <Setter Property="FontSize" Value="{ThemeResource ControlContentThemeFontSize}" />
        <Setter Property="Background" Value="Transparent"/>
        <Setter Property="TabNavigation" Value="Local"/>
        <Setter Property="IsHoldingEnabled" Value="True"/>
        <Setter Property="Margin" Value="0,0,18,2"/>
        <Setter Property="HorizontalContentAlignment" Value="Left"/>
        <Setter Property="VerticalContentAlignment" Value="Top"/>
        <Setter Property="Template">
            <Setter.Value>
                <ControlTemplate TargetType="local:GroupListViewItem">
                    <Border x:Name="OuterContainer">
                        <VisualStateManager.VisualStateGroups>
                            <VisualStateGroup x:Name="CommonStates">
                                <VisualState x:Name="Normal"/>
                                <VisualState x:Name="PointerOver">
                                    <Storyboard>
                                        <DoubleAnimation Storyboard.TargetName="PointerOverBorder"
                                                     Storyboard.TargetProperty="Opacity"
                                                     Duration="0"
                                                     To="1" />
                                        <ObjectAnimationUsingKeyFrames Storyboard.TargetName="SelectionBackground"
                                                                    Storyboard.TargetProperty="Fill">
                                            <DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource ListViewItemSelectedPointerOverBackgroundThemeBrush}" />
                                        </ObjectAnimationUsingKeyFrames>
                                        <ObjectAnimationUsingKeyFrames Storyboard.TargetName="SelectedBorder"
                                                                    Storyboard.TargetProperty="Stroke">
                                            <DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource ListViewItemSelectedPointerOverBorderThemeBrush}" />
                                        </ObjectAnimationUsingKeyFrames>
                                        <ObjectAnimationUsingKeyFrames Storyboard.TargetName="SelectedEarmark"
                                                                   Storyboard.TargetProperty="Fill">
                                            <DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource ListViewItemSelectedPointerOverBackgroundThemeBrush}" />
                                        </ObjectAnimationUsingKeyFrames>
                                    </Storyboard>
                                </VisualState>
                                <VisualState x:Name="Pressed">
                                    <Storyboard>
                                        <PointerDownThemeAnimation TargetName="ContentContainer" />
                                    </Storyboard>
                                </VisualState>
                                <VisualState x:Name="PointerOverPressed">
                                    <Storyboard>
                                        <PointerDownThemeAnimation TargetName="ContentContainer" />
                                        <DoubleAnimation Storyboard.TargetName="PointerOverBorder"
                                                     Storyboard.TargetProperty="Opacity"
                                                     Duration="0"
                                                     To="1" />
                                        <ObjectAnimationUsingKeyFrames Storyboard.TargetName="SelectionBackground"
                                                                    Storyboard.TargetProperty="Fill">
                                            <DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource ListViewItemSelectedPointerOverBackgroundThemeBrush}" />
                                        </ObjectAnimationUsingKeyFrames>
                                        <ObjectAnimationUsingKeyFrames Storyboard.TargetName="SelectedBorder"
                                                                    Storyboard.TargetProperty="Stroke">
                                            <DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource ListViewItemSelectedPointerOverBorderThemeBrush}" />
                                        </ObjectAnimationUsingKeyFrames>
                                        <ObjectAnimationUsingKeyFrames Storyboard.TargetName="SelectedEarmark"
                                                                   Storyboard.TargetProperty="Fill">
                                            <DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource ListViewItemSelectedPointerOverBackgroundThemeBrush}" />
                                        </ObjectAnimationUsingKeyFrames>
                                    </Storyboard>
                                </VisualState>
                                <VisualState x:Name="Disabled">
                                    <Storyboard>
                                        <DoubleAnimation Storyboard.TargetName="contentPresenter"
                                                     Storyboard.TargetProperty="Opacity"
                                                     Duration="0"
                                                     To="{ThemeResource ListViewItemDisabledThemeOpacity}" />
                                    </Storyboard>
                                </VisualState>
                            </VisualStateGroup>
                            <VisualStateGroup x:Name="FocusStates">
                                <VisualState x:Name="Focused">
                                    <Storyboard>
                                        <DoubleAnimation Duration="0" To="1" Storyboard.TargetProperty="Opacity" Storyboard.TargetName="FocusVisual" />
                                    </Storyboard>
                                </VisualState>
                                <VisualState x:Name="Unfocused"/>
                                <VisualState x:Name="PointerFocused"/>
                            </VisualStateGroup>
                            <VisualStateGroup x:Name="SelectionHintStates">
                                <VisualState x:Name="VerticalSelectionHint">
                                    <Storyboard>
                                        <SwipeHintThemeAnimation TargetName="SelectionBackground" ToVerticalOffset="15" ToHorizontalOffset="0" />
                                        <SwipeHintThemeAnimation TargetName="ContentBorder" ToVerticalOffset="15" ToHorizontalOffset="0" />
                                        <SwipeHintThemeAnimation TargetName="SelectedBorder" ToVerticalOffset="15" ToHorizontalOffset="0" />
                                        <SwipeHintThemeAnimation TargetName="SelectedCheckMark" ToVerticalOffset="15" ToHorizontalOffset="0" />
                                        <DoubleAnimationUsingKeyFrames Storyboard.TargetName="HintGlyph"
                                                                   Storyboard.TargetProperty="Opacity"
                                                                   Duration="0:0:0.500">
                                            <DiscreteDoubleKeyFrame Value="0.5" KeyTime="0:0:0" />
                                            <DiscreteDoubleKeyFrame Value="0" KeyTime="0:0:0.500" />
                                        </DoubleAnimationUsingKeyFrames>
                                    </Storyboard>
                                </VisualState>
                                <VisualState x:Name="HorizontalSelectionHint">
                                    <Storyboard>
                                        <SwipeHintThemeAnimation TargetName="SelectionBackground" ToHorizontalOffset="-23" ToVerticalOffset="0" />
                                        <SwipeHintThemeAnimation TargetName="ContentBorder" ToHorizontalOffset="-23" ToVerticalOffset="0" />
                                        <SwipeHintThemeAnimation TargetName="SelectedBorder" ToHorizontalOffset="-23" ToVerticalOffset="0" />
                                        <SwipeHintThemeAnimation TargetName="SelectedCheckMark" ToHorizontalOffset="-23" ToVerticalOffset="0" />
                                        <DoubleAnimationUsingKeyFrames Storyboard.TargetName="HintGlyph"
                                                                   Storyboard.TargetProperty="Opacity"
                                                                   Duration="0:0:0.500">
                                            <DiscreteDoubleKeyFrame Value="0.5" KeyTime="0:0:0" />
                                            <DiscreteDoubleKeyFrame Value="0" KeyTime="0:0:0.500" />
                                        </DoubleAnimationUsingKeyFrames>
                                    </Storyboard>
                                </VisualState>
                                <VisualState x:Name="NoSelectionHint" />
                                <VisualStateGroup.Transitions>
                                    <VisualTransition To="NoSelectionHint" GeneratedDuration="0:0:0.65"/>
                                </VisualStateGroup.Transitions>
                            </VisualStateGroup>
                            <VisualStateGroup x:Name="SelectionStates">
                                <VisualState x:Name="Unselecting">
                                    <Storyboard>
                                        <DoubleAnimation Storyboard.TargetName="HintGlyphBorder"
                                                     Storyboard.TargetProperty="Opacity"
                                                     Duration="0"
                                                     To="1" />
                                    </Storyboard>
                                </VisualState>
                                <VisualState x:Name="Unselected">
                                    <Storyboard>
                                        <DoubleAnimation Storyboard.TargetName="HintGlyphBorder"
                                                     Storyboard.TargetProperty="Opacity"
                                                     Duration="0"
                                                     To="1" />
                                    </Storyboard>
                                </VisualState>
                                <VisualState x:Name="UnselectedPointerOver">
                                    <Storyboard>
                                        <DoubleAnimation Storyboard.TargetName="HintGlyphBorder"
                                                     Storyboard.TargetProperty="Opacity"
                                                     Duration="0"
                                                     To="1" />
                                        <ObjectAnimationUsingKeyFrames Storyboard.TargetName="contentPresenter"
                                                                   Storyboard.TargetProperty="Foreground">
                                            <DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource ListViewItemSelectedForegroundThemeBrush}" />
                                        </ObjectAnimationUsingKeyFrames>
                                    </Storyboard>
                                </VisualState>
                                <VisualState x:Name="UnselectedSwiping">
                                    <Storyboard>
                                        <DoubleAnimation Storyboard.TargetName="SelectingGlyph"
                                                     Storyboard.TargetProperty="Opacity"
                                                     Duration="0"
                                                     To="0.5" />
                                        <DoubleAnimation Storyboard.TargetName="HintGlyphBorder"
                                                     Storyboard.TargetProperty="Opacity"
                                                     Duration="0"
                                                     To="1" />
                                    </Storyboard>
                                </VisualState>
                                <VisualState x:Name="Selecting">
                                    <Storyboard>
                                        <DoubleAnimation Storyboard.TargetName="SelectionBackground"
                                                     Storyboard.TargetProperty="Opacity"
                                                     Duration="0"
                                                     To="1" />
                                        <DoubleAnimation Storyboard.TargetName="SelectedBorder"
                                                     Storyboard.TargetProperty="Opacity"
                                                     Duration="0"
                                                     To="1" />
                                        <DoubleAnimation Storyboard.TargetName="SelectingGlyph"
                                                     Storyboard.TargetProperty="Opacity"
                                                     Duration="0"
                                                     To="1" />
                                        <DoubleAnimation Storyboard.TargetName="HintGlyphBorder"
                                                     Storyboard.TargetProperty="Opacity"
                                                     Duration="0"
                                                     To="1" />
                                        <ObjectAnimationUsingKeyFrames Storyboard.TargetName="contentPresenter"
                                                                   Storyboard.TargetProperty="Foreground">
                                            <DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource ListViewItemSelectedForegroundThemeBrush}" />
                                        </ObjectAnimationUsingKeyFrames>
                                    </Storyboard>
                                </VisualState>
                                <VisualState x:Name="Selected">
                                    <Storyboard>
                                        <DoubleAnimation Storyboard.TargetName="SelectionBackground"
                                                     Storyboard.TargetProperty="Opacity"
                                                     Duration="0"
                                                     To="1" />
                                        <DoubleAnimation Storyboard.TargetName="SelectedBorder"
                                                     Storyboard.TargetProperty="Opacity"
                                                     Duration="0"
                                                     To="1" />
                                        <DoubleAnimation Storyboard.TargetName="SelectedCheckMark"
                                                     Storyboard.TargetProperty="Opacity"
                                                     Duration="0"
                                                     To="1" />
                                        <ObjectAnimationUsingKeyFrames Storyboard.TargetName="contentPresenter"
                                                                   Storyboard.TargetProperty="Foreground">
                                            <DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource ListViewItemSelectedForegroundThemeBrush}" />
                                        </ObjectAnimationUsingKeyFrames>
                                    </Storyboard>
                                </VisualState>
                                <VisualState x:Name="SelectedSwiping">
                                    <Storyboard>
                                        <DoubleAnimation Storyboard.TargetName="SelectionBackground"
                                                     Storyboard.TargetProperty="Opacity"
                                                     Duration="0"
                                                     To="1" />
                                        <DoubleAnimation Storyboard.TargetName="SelectedBorder"
                                                     Storyboard.TargetProperty="Opacity"
                                                     Duration="0"
                                                     To="1" />
                                        <DoubleAnimation Storyboard.TargetName="SelectedCheckMark"
                                                     Storyboard.TargetProperty="Opacity"
                                                     Duration="0"
                                                     To="1" />
                                        <ObjectAnimationUsingKeyFrames Storyboard.TargetName="contentPresenter"
                                                                   Storyboard.TargetProperty="Foreground">
                                            <DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource ListViewItemSelectedForegroundThemeBrush}" />
                                        </ObjectAnimationUsingKeyFrames>
                                    </Storyboard>
                                </VisualState>
                                <VisualState x:Name="SelectedUnfocused">
                                    <Storyboard>
                                        <DoubleAnimation Storyboard.TargetName="SelectionBackground"
                                                     Storyboard.TargetProperty="Opacity"
                                                     Duration="0"
                                                     To="1" />
                                        <DoubleAnimation Storyboard.TargetName="SelectedBorder"
                                                     Storyboard.TargetProperty="Opacity"
                                                     Duration="0"
                                                     To="1" />
                                        <DoubleAnimation Storyboard.TargetName="SelectedCheckMark"
                                                     Storyboard.TargetProperty="Opacity"
                                                     Duration="0"
                                                     To="1" />
                                        <ObjectAnimationUsingKeyFrames Storyboard.TargetName="contentPresenter"
                                                                   Storyboard.TargetProperty="Foreground">
                                            <DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource ListViewItemSelectedForegroundThemeBrush}" />
                                        </ObjectAnimationUsingKeyFrames>
                                    </Storyboard>
                                </VisualState>
                            </VisualStateGroup>
                            <VisualStateGroup x:Name="DragStates">
                                <VisualState x:Name="NotDragging" />
                                <VisualState x:Name="Dragging">
                                    <Storyboard>
                                        <DoubleAnimation Storyboard.TargetName="InnerDragContent"
                                                     Storyboard.TargetProperty="Opacity"
                                                     Duration="0"
                                                     To="{ThemeResource ListViewItemDragThemeOpacity}" />
                                        <DragItemThemeAnimation TargetName="InnerDragContent" />
                                        <FadeOutThemeAnimation TargetName="SelectedCheckMarkOuter" />
                                        <FadeOutThemeAnimation TargetName="SelectedBorder" />
                                    </Storyboard>
                                </VisualState>
                                <VisualState x:Name="DraggingTarget">
                                    <Storyboard>
                                        <DropTargetItemThemeAnimation TargetName="OuterContainer" />
                                    </Storyboard>
                                </VisualState>
                                <VisualState x:Name="MultipleDraggingPrimary">
                                    <Storyboard>
                                        <!-- These two Opacity animations are required - the FadeInThemeAnimations
                                         on the same elements animate an internal Opacity. -->
                                        <DoubleAnimation Storyboard.TargetName="MultiArrangeOverlayBackground"
                                                     Storyboard.TargetProperty="Opacity"
                                                     Duration="0"
                                                     To="1" />
                                        <DoubleAnimation Storyboard.TargetName="MultiArrangeOverlayText"
                                                     Storyboard.TargetProperty="Opacity"
                                                     Duration="0"
                                                     To="1" />

                                        <DoubleAnimation Storyboard.TargetName="ContentBorder"
                                                     Storyboard.TargetProperty="Opacity"
                                                     Duration="0"
                                                     To="{ThemeResource ListViewItemDragThemeOpacity}" />
                                        <FadeInThemeAnimation TargetName="MultiArrangeOverlayBackground" />
                                        <FadeInThemeAnimation TargetName="MultiArrangeOverlayText" />
                                        <DragItemThemeAnimation TargetName="ContentBorder" />
                                        <FadeOutThemeAnimation TargetName="SelectionBackground" />
                                        <FadeOutThemeAnimation TargetName="SelectedCheckMarkOuter" />
                                        <FadeOutThemeAnimation TargetName="SelectedBorder" />
                                        <FadeOutThemeAnimation TargetName="PointerOverBorder" />
                                    </Storyboard>
                                </VisualState>
                                <VisualState x:Name="MultipleDraggingSecondary">
                                    <Storyboard>
                                        <FadeOutThemeAnimation TargetName="ContentContainer" />
                                    </Storyboard>
                                </VisualState>
                                <VisualStateGroup.Transitions>
                                    <VisualTransition To="NotDragging" GeneratedDuration="0:0:0.2"/>
                                </VisualStateGroup.Transitions>
                            </VisualStateGroup>
                            <VisualStateGroup x:Name="ReorderHintStates">
                                <VisualState x:Name="NoReorderHint"/>
                                <VisualState x:Name="BottomReorderHint">
                                    <Storyboard>
                                        <DragOverThemeAnimation TargetName="ReorderHintContent" ToOffset="{ThemeResource ListViewItemReorderHintThemeOffset}" Direction="Bottom" />
                                    </Storyboard>
                                </VisualState>
                                <VisualState x:Name="TopReorderHint">
                                    <Storyboard>
                                        <DragOverThemeAnimation TargetName="ReorderHintContent" ToOffset="{ThemeResource ListViewItemReorderHintThemeOffset}" Direction="Top" />
                                    </Storyboard>
                                </VisualState>
                                <VisualState x:Name="RightReorderHint">
                                    <Storyboard>
                                        <DragOverThemeAnimation TargetName="ReorderHintContent" ToOffset="{ThemeResource ListViewItemReorderHintThemeOffset}" Direction="Right" />
                                    </Storyboard>
                                </VisualState>
                                <VisualState x:Name="LeftReorderHint">
                                    <Storyboard>
                                        <DragOverThemeAnimation TargetName="ReorderHintContent" ToOffset="{ThemeResource ListViewItemReorderHintThemeOffset}" Direction="Left" />
                                    </Storyboard>
                                </VisualState>
                                <VisualStateGroup.Transitions>
                                    <VisualTransition To="NoReorderHint" GeneratedDuration="0:0:0.2"/>
                                </VisualStateGroup.Transitions>
                            </VisualStateGroup>
                            <VisualStateGroup x:Name="DataVirtualizationStates">
                                <VisualState x:Name="DataAvailable"/>
                                <VisualState x:Name="DataPlaceholder">
                                    <Storyboard>
                                        <ObjectAnimationUsingKeyFrames Storyboard.TargetName="PlaceholderTextBlock"
                                                                   Storyboard.TargetProperty="Visibility"
                                                                   Duration="0">
                                            <DiscreteObjectKeyFrame KeyTime="0">
                                                <DiscreteObjectKeyFrame.Value>
                                                    <Visibility>Visible</Visibility>
                                                </DiscreteObjectKeyFrame.Value>
                                            </DiscreteObjectKeyFrame>
                                        </ObjectAnimationUsingKeyFrames>
                                        <ObjectAnimationUsingKeyFrames Storyboard.TargetName="PlaceholderRect"
                                                                   Storyboard.TargetProperty="Visibility"
                                                                   Duration="0">
                                            <DiscreteObjectKeyFrame KeyTime="0">
                                                <DiscreteObjectKeyFrame.Value>
                                                    <Visibility>Visible</Visibility>
                                                </DiscreteObjectKeyFrame.Value>
                                            </DiscreteObjectKeyFrame>
                                        </ObjectAnimationUsingKeyFrames>
                                    </Storyboard>
                                </VisualState>
                            </VisualStateGroup>
                        </VisualStateManager.VisualStateGroups>
                        <Grid x:Name="ReorderHintContent" Background="Transparent">
                            <Grid.RowDefinitions>
                                <RowDefinition Height="auto"/>
                                <RowDefinition Height="auto"/>
                            </Grid.RowDefinitions>
                            <ContentPresenter x:Name="headerPresenter" Grid.Row="0"
                                                          ContentTransitions="{TemplateBinding ContentTransitions}"
                                                          ContentTemplate="{TemplateBinding HeaderTemplate}"
                                                          Content="{TemplateBinding Header}"
                                                          HorizontalAlignment="Stretch"
                                                          VerticalAlignment="Stretch"
                                                          />
                            <Grid Grid.Row="1">
                                <Path x:Name="SelectingGlyph" Opacity="0" Data="F1 M133.1,17.9 L137.2,13.2 L144.6,19.6 L156.4,5.8 L161.2,9.9 L145.6,28.4 z" Fill="{ThemeResource ListViewItemCheckSelectingThemeBrush}" Height="13" Stretch="Fill" Width="15" HorizontalAlignment="Right" Margin="0,9.5,9.5,0" VerticalAlignment="Top" FlowDirection="LeftToRight"/>
                                <Border x:Name="HintGlyphBorder"
                                Height="40"
                                Width="40"
                                HorizontalAlignment="Right"
                                VerticalAlignment="Top"
                                Opacity="0"
                                Margin="4">
                                    <Path x:Name="HintGlyph" Opacity="0" Data="F1 M133.1,17.9 L137.2,13.2 L144.6,19.6 L156.4,5.8 L161.2,9.9 L145.6,28.4 z" Fill="{ThemeResource ListViewItemCheckHintThemeBrush}" Height="13" Stretch="Fill"  Width="15" HorizontalAlignment="Right" Margin="0,5.5,5.5,0" VerticalAlignment="Top" FlowDirection="LeftToRight"/>
                                </Border>
                                <Border x:Name="ContentContainer">
                                    <Grid x:Name="InnerDragContent">
                                        <Rectangle x:Name="PointerOverBorder"
                                           IsHitTestVisible="False"
                                           Opacity="0"
                                           Fill="{ThemeResource ListViewItemPointerOverBackgroundThemeBrush}"
                                           Margin="1" />
                                        <Rectangle x:Name="FocusVisual"
                                           IsHitTestVisible="False"
                                           Opacity="0"
                                           StrokeThickness="2"
                                           Stroke="{ThemeResource ListViewItemFocusBorderThemeBrush}" />
                                        <Rectangle x:Name="SelectionBackground"
                                           Margin="4"
                                           Fill="{ThemeResource ListViewItemSelectedBackgroundThemeBrush}"
                                           Opacity="0" />
                                        <Border x:Name="ContentBorder"
                                        Background="{TemplateBinding Background}"
                                        BorderBrush="{TemplateBinding BorderBrush}"
                                        BorderThickness="{TemplateBinding BorderThickness}"
                                        Margin="4">
                                            <Grid>
                                                <ContentPresenter x:Name="contentPresenter"
                                                          ContentTransitions="{TemplateBinding ContentTransitions}"
                                                          ContentTemplate="{TemplateBinding ContentTemplate}"
                                                          Content="{TemplateBinding Content}"
                                                          HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}"
                                                          VerticalAlignment="{TemplateBinding VerticalContentAlignment}"
                                                          Margin="{TemplateBinding Padding}" />
                                                <!-- The ‘Xg‘ text simulates the amount of space one line of text will occupy.
                                             In the DataPlaceholder state, the Content is not loaded yet so we
                                             approximate the size of the item using placeholder text. -->
                                                <TextBlock x:Name="PlaceholderTextBlock"
                                                   Opacity="0"
                                                   Text="Xg"
                                                   Foreground="{x:Null}"
                                                   Margin="{TemplateBinding Padding}"
                                                   IsHitTestVisible="False"
                                                   AutomationProperties.AccessibilityView="Raw"/>
                                                <Rectangle x:Name="PlaceholderRect"
                                                   Visibility="Collapsed"
                                                   Fill="{ThemeResource ListViewItemPlaceholderBackgroundThemeBrush}"/>
                                                <Rectangle x:Name="MultiArrangeOverlayBackground"
                                                   IsHitTestVisible="False"
                                                   Opacity="0"
                                                   Fill="{ThemeResource ListViewItemDragBackgroundThemeBrush}" />
                                            </Grid>
                                        </Border>
                                        <Rectangle x:Name="SelectedBorder"
                                           IsHitTestVisible="False"
                                           Opacity="0"
                                           Stroke="{ThemeResource ListViewItemSelectedBackgroundThemeBrush}"
                                           StrokeThickness="{ThemeResource ListViewItemSelectedBorderThemeThickness}"
                                           Margin="4" />
                                        <Border x:Name="SelectedCheckMarkOuter"
                                        IsHitTestVisible="False"
                                        HorizontalAlignment="Right"
                                        VerticalAlignment="Top"
                                        Margin="4">
                                            <Grid x:Name="SelectedCheckMark" Opacity="0" Height="40" Width="40">
                                                <Path x:Name="SelectedEarmark" Data="M0,0 L40,0 L40,40 z"  Fill="{ThemeResource ListViewItemSelectedBackgroundThemeBrush}" Stretch="Fill"/>
                                                <Path Data="F1 M133.1,17.9 L137.2,13.2 L144.6,19.6 L156.4,5.8 L161.2,9.9 L145.6,28.4 z" Fill="{ThemeResource ListViewItemCheckThemeBrush}" Height="13" Stretch="Fill" Width="15" HorizontalAlignment="Right" Margin="0,5.5,5.5,0" VerticalAlignment="Top" FlowDirection="LeftToRight"/>
                                            </Grid>
                                        </Border>
                                        <TextBlock x:Name="MultiArrangeOverlayText"
                                           Text="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=TemplateSettings.DragItemsCount}"
                                           Foreground="{ThemeResource ListViewItemDragForegroundThemeBrush}"
                                           FontFamily="{ThemeResource ContentControlThemeFontFamily}"
                                           FontSize="26.667"
                                           IsHitTestVisible="False"
                                           Opacity="0"
                                           TextWrapping="Wrap"
                                           TextTrimming="WordEllipsis"
                                           Margin="18,9,0,0"
                                           AutomationProperties.AccessibilityView="Raw"/>
                                    </Grid>
                                </Border>
                            </Grid>
                        </Grid>
                    </Border>
                </ControlTemplate>
            </Setter.Value>
        </Setter>
    </Style>

                            <Grid.RowDefinitions>
                                <RowDefinition Height="auto"/>
                                <RowDefinition Height="auto"/>
                            </Grid.RowDefinitions>
                            <ContentPresenter x:Name="headerPresenter" Grid.Row="0"
                                                          ContentTransitions="{TemplateBinding ContentTransitions}"
                                                          ContentTemplate="{TemplateBinding HeaderTemplate}"
                                                          Content="{TemplateBinding Header}"
                                                          HorizontalAlignment="Stretch"
                                                          VerticalAlignment="Stretch"
                                                          />
                            <Grid Grid.Row="1">

注意上图,我把默认模板里面的内容放到Grid.Row=1的Gird里面了,然后加了一个HeaderPresenter在上面。

是不是思路清晰了,就是说如果这个Item是Group的第一个,我们就给HeaderPresenter设置Header和HeaderTemplate。

这里我们需要继承ListViewItem,增加Header和HeaderTemplate 2个属性。

    [TemplatePart(Name = "headerPresenter", Type = typeof(ContentPresenter))]
    public class GroupListViewItem : ListViewItem
    {
        ContentPresenter headerPresenter;
        public object Header
        {
            get { return (object)GetValue(HeaderProperty); }
            set { SetValue(HeaderProperty, value); }
        }

        // Using a DependencyProperty as the backing store for Header.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty HeaderProperty =
            DependencyProperty.Register("Header", typeof(object), typeof(GroupListViewItem), new PropertyMetadata(null, new PropertyChangedCallback(OnHeaderChanged)));

        private static void OnHeaderChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            (d as GroupListViewItem).SetHeader();

        }

        public DataTemplate HeaderTemplate
        {
            get { return (DataTemplate)GetValue(HeaderTemplateProperty); }
            set { SetValue(HeaderTemplateProperty, value); }
        }

        // Using a DependencyProperty as the backing store for HeaderTemplate.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty HeaderTemplateProperty =
            DependencyProperty.Register("HeaderTemplate", typeof(DataTemplate), typeof(GroupListViewItem), new PropertyMetadata(null));

        public GroupListViewItem()
        {
            this.DefaultStyleKey = typeof(GroupListViewItem);
        }

        protected override void OnApplyTemplate()
        {
            base.OnApplyTemplate();

            headerPresenter = GetTemplateChild("headerPresenter") as ContentPresenter;
            if (headerPresenter != null)
            {
                headerPresenter.RegisterPropertyChangedCallback(ContentPresenter.ContentProperty, new DependencyPropertyChangedCallback(OnHeaderPresenterContentChanged));
            }
            else
            {
                Debug.Assert(false, "headerpresenter is missing.");
            }
        }

        private void OnHeaderPresenterContentChanged(DependencyObject sender, DependencyProperty dp)
        {
            if (headerPresenter.Content != Header)
            {
                headerPresenter.Content = Header;
            }
        }

        protected override Size ArrangeOverride(Size finalSize)
        {
            if (headerPresenter != null)
            {
                headerPresenter.Margin = new Thickness(-this.Margin.Left, -this.Margin.Top, -this.Margin.Right, this.Margin.Bottom);
            }
            return base.ArrangeOverride(finalSize);
        }

        public void ClearHeader()
        {
            Header = null;
            ClearValue(GroupListViewItem.HeaderTemplateProperty);
        }

        public void SetHeader()
        {
            if (headerPresenter != null)
            {
                headerPresenter.Content = Header;
            }
        }
    }

当然不要忘记了在GroupListView1里面override 下面2个方法。

        protected override bool IsItemItsOwnContainerOverride(object item)
        {
            return item is GroupListViewItem;
        }
        protected override DependencyObject GetContainerForItemOverride()
        {
            return new GroupListViewItem();
        }

其他就很简单了,只需要处理下置顶的Header就好了,注意红色字的部分。

        private void UpdateGroupHeaders()
        {
            if (groupCollection != null)
            {
                var firstVisibleItemIndex = this.GetFirstVisibleIndex();
                if (firstVisibleItemIndex < 0)
                {
                    return;
                }
                foreach (var item in groupCollection.GroupHeaders)
                {
                    if (item.FirstIndex == -1)
                    {
                        continue;
                    }
                    if (item.FirstIndex <= firstVisibleItemIndex && (firstVisibleItemIndex <= item.LastIndex || item.LastIndex == -1))
                    {
                        currentTopGroupHeader.Visibility = Visibility.Visible;
                        currentTopGroupHeader.Margin = new Thickness(0);
                        currentTopGroupHeader.Clip = null;
                        currentTopGroupHeader.DataContext = item;
                    }
                    else
                    {
                        ListViewItem listViewItem = ContainerFromIndex(item.FirstIndex) as ListViewItem;

                        if (listViewItem == null && item.LastIndex != -1)
                        {
                            listViewItem = ContainerFromIndex(item.LastIndex) as ListViewItem;
                        }
                        if (listViewItem != null)
                        {
                            //handle moving header
                            {
                                //unloaded
                                if (listViewItem.ActualHeight == 0 || listViewItem.ActualWidth == 0)
                                {
                                    listViewItem.Loaded += ListViewItem_Loaded;
                                }
                                else
                                {
                                    GeneralTransform gt = listViewItem.TransformToVisual(this);
                                    var rect = gt.TransformBounds(new Rect(0, 0, listViewItem.ActualWidth, listViewItem.ActualHeight));
                                    //add delta,so that it does not look like suddenly
                                    if (rect.Bottom < 0 || rect.Top > this.ActualHeight)
                                    {

                                    }
                                    //in view port
                                    else
                                    {
                                        if (currentTopGroupHeader != null)
                                        {
                                            var delta = currentTopGroupHeader.ActualHeight - (rect.Top);
                                            if (delta > 0)
                                            {
                                                currentTopGroupHeader.Margin = new Thickness(0, -delta, 0, 0);
                                                currentTopGroupHeader.Clip = new RectangleGeometry() { Rect = new Rect(0, delta, currentTopGroupHeader.ActualWidth, currentTopGroupHeader.ActualHeight) };
                                                if (delta >= currentTopGroupHeader.ActualHeight)
                                                {
                                                    currentTopGroupHeader.Visibility = Visibility.Visible;
                                                    currentTopGroupHeader.Margin = new Thickness(0);
                                                    currentTopGroupHeader.Clip = null;
                                                    currentTopGroupHeader.DataContext = item;
                                                }
                                            }

                                        }
                                    }
                                }
                            }
                        }
                    }
                }
            }
        }

查看一下GroupListView1里面的代码,是不是感觉比之前GroupListView里面的代码简单更好理解(我的错。。。别要问我控件名字怎么这么随意 ,我想不更好的。。( ╯□╰ ))

当然这个GroupListView1里面也有Composition API,这样你们就不会说我是标题党了。。

因为置顶的Header是新加的东东,它不是ScrollViewer的ScrollContentPresenter(在这里我猜想,ScrollContentPresenter是做了Composition 动画的),它不会顺着ScrollViewer向下拖动的时候向下移动,它依然在它自己的位置上,有木有觉得它很孤独。。

如下图:

那么我们把它和ScrollViewer联系起来就好了。。让它和ScrollViewer一起动就好了。注意记得限定下它的值。

        private void CreateVisual()
        {
            visual = ElementCompositionPreview.GetElementVisual(currentTopGroupHeader);

            var scrollViewerManipProps = ElementCompositionPreview.GetScrollViewerManipulationPropertySet(scrollViewer);

            Compositor compositor = scrollViewerManipProps.Compositor;

            expression = compositor.CreateExpressionAnimation("max(0,ScrollViewerManipProps.Translation.Y)");

            // set "dynamic" reference parameter that will be used to evaluate the current position of the scrollbar every frame
            expression.SetReferenceParameter("ScrollViewerManipProps", scrollViewerManipProps);
            visual.StartAnimation("Offset.Y", expression);
            //Windows.UI.Xaml.Media.CompositionTarget.Rendering += OnCompositionTargetRendering;
        }

加上之后:

好了,这个控件也讲完咯,真的没有了。

开源有益,源码GitHub地址

其实有心的朋友也发现,原来ScrollViewer的超出界限动画,估计也是这样实现的吧??。我在网上也发现很多人问怎么才能禁掉它。

下图是UWP 图片剪切旋转工具,当时我就是拿ScrollViewer做的,当时找了半天也没找到禁止下面动画的方法。

找了一圈,ElementCompositeMode 这个属性有点像。微软的解释是:

没看懂。。试了下,没有用。

另外也没在ScrollViewer或者ScrollContentPresenter 上找到相关的属性。希望微软在之后能暴露相关属性,毕竟不是每个人都希望ScrollViewer有这种动画的。。

如果有童鞋已经知道怎么搞了,请留言下下,让更多的童鞋知道。万分感谢

时间: 2024-11-10 10:54:30

UWP Composition API - GroupListView(二)的相关文章

UWP Composition API - GroupListView(一)

需求: 光看标题大家肯定不知道是什么东西,先上效果图: 这不就是ListView的Group效果吗?? 看上去是的.但是请听完需求.1.Group中的集合需要支持增量加载ISupportIncrementalLoading 2.支持UI Virtualization oh,no.ListView 自带的Group都不支持这2个需求.好吧,只有靠自己撸Code了.. 实现前思考: 仔细想了下,其实要解决的主要问题有2个数据源的处理 和 GroupHeader的UI的处理 1.数据源的处理  因为之

UWP Composition API - New FlexGrid 锁定行列

原文:UWP Composition API - New FlexGrid 锁定行列 如果之前看了 UWP Jenkins + NuGet + MSBuild 手把手教你做自动UWP Build 和 App store包 这篇的童鞋,针对VS2017,需要对应更新一下配置,需要的童鞋点击查看一下,在文章最后. 之前写过一篇 锁定列的FlexGrid,没看过的童鞋可以去先看一下那一篇. 先放上效果图 制作新控件的背景是SDK升级到了14393,Composition API 有了相应的改变. 对我

UWP Composition API - RadialMenu

原文:UWP Composition API - RadialMenu 用Windows 8.1的童鞋应该知道OneNote里面有一个RadialMenu.如下图,下图是WIn10应用Drawboard PDF的RadialMenu,Win8.1的机器不好找了.哈哈,由于整个文章比较长,大家可以放<给我一首歌的时间> 边听边看.<滑稽> 从设计到开发包括修复一些bug,大概用了不连续的2个月,想看源代码的童鞋可以先到 RadialMenu 查看效果和代码. 先放上项目里面的最终效果

UWP Composition API - PullToRefresh

背景: 之前用ScrollViewer 来做过 PullToRefresh的控件,在项目一些特殊的条件下总有一些问题,比如ScrollViewer不会及时到达指定位置.于是便有了使用Composition API来重新实现PullToRefresh控件.本控件的难点不是实现,而是对Composition API的一些探索. 本文的一些观点或者说结论不一定是全对的,都是通过实验得到的,Composition API 可用的资料实在是太少了. 成品效果图: 资料: Composition API 资

UWP中使用Composition API实现吸顶(2)

原文:UWP中使用Composition API实现吸顶(2) 在上一篇中我们讨论了不涉及Pivot的吸顶操作,但是一般来说,吸顶的部分都是Pivot的Header,所以在此我们将讨论关于Pivot多个Item关联同一个Header的情况. 老样子,先做一个简单的页面,页面有一个Grid当Header,一个去掉了头部的Pivot,Pivot内有三个ListView,ListView设置了和页面Header高度一致的空白Header. <Page x:Class="TestListViewH

【高德地图API】从零开始学高德JS API(二)地图控件与插件——测距、圆形编辑器、鼠标工具、地图类型切换、鹰眼鱼骨

摘要:无论是控件还是插件,都是在一级API接口的基础上,进行二次开发,封装的一系列更加便于开发者使用,减少开发者工作量的二级API接口.除了官方通用的鱼骨.鹰眼控件,还有大量官方开发的地图插件,类似谷歌的lib.当然本文还会介绍自定义插件的使用. ------------------------------------------------------------------------------------------------- 第一部分 控件 目前官方支持的控件包含:缩放控制条-地图

使用IOS7原生API进行二维码条形码的扫描

使用IOS7原生API进行二维码条形码的扫描 IOS7之前,开发者进行扫码编程时,一般会借助第三方库.常用的是ZBarSDK,IOS7之后,系统的AVMetadataObject类中,为我们提供了解析二维码的接口.经过测试,使用原生API扫描和处理的效率非常高,远远高于第三方库. 一.使用方法示例 官方提供的接口非常简单,代码如下: ? 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30

在云平台上基于Go语言+Google图表API提供二维码生成应用

二维码能够说已经深深的融入了我们的生活其中.到处可见它的身影:但通常我们都是去扫二维码, 曾经我们分享给朋友一个网址直接把Url发过去,如今我们能够把自己的信息生成二维码再分享给他人. 这里就分享一下基于Go语言+Google图表API提供二维码生成功能的小应用,并演示怎样把它公布到云平台上, 让每一个人都能够通过网络訪问使用它. Google图表API Google在http://chart.apis.google.com 上提供了一个将表单数据自己主动转换为图表的服务. 只是,该服务非常难交

用产品思维设计API(二)——数据解耦,才是前后分离的本质

用产品思维设计API(二)--数据解耦,才是前后分离的本质 前言 最近公司内部在重构项目代码,包括API方向的重构,期间遇到了很多的问题,不由得让我重新思考了下. - 一个优雅的API该如何设计? - 前后端分离之后,API真的解耦分离了吗? - 不断的版本迭代,API的兼容性该如何做? ps.这里所说的API仅为Web API,提供APP\WEB开发使用. 年前,我司内部的接口已经进入了一个完全的重构阶段,参考了市面上各大平台的API和文档,自己也总结出了很多的心得.这里向大家分享一下,接下来