UWP Composition API - GroupListView(二)

简介: 原文:UWP Composition API - GroupListView(二)还是先上效果图: 看完了上一篇UWP Composition API - GroupListView(一)的童鞋会问,这不是跟上一篇一样的吗??? 骗点击的?? No,No,其实相对上一个有更简单粗暴的方案,因为上篇是为了研究Composition API,所以含着泪都要做完(有没有被骗的赶脚)。
原文: 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>
View Code
                            <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有这种动画的。。

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

目录
相关文章
|
2月前
|
缓存 JavaScript 算法
活用 Composition API 核心函数,打造卓越应用(下)
活用 Composition API 核心函数,打造卓越应用(下)
|
2月前
|
存储 JavaScript API
活用 Composition API 核心函数,打造卓越应用(上)
活用 Composition API 核心函数,打造卓越应用(上)
|
2月前
|
JavaScript 前端开发 API
深入浅出:Vue 3 Composition API 的魅力与实践
【2月更文挑战第13天】 本文将探索 Vue 3 的核心特性之一——Composition API。通过对比 Options API,本文旨在揭示 Composition API 如何提高代码的组织性和可复用性,并通过实际案例展示其在现代前端开发中的应用。不同于传统的技术文章摘要,我们将通过一个具体的开发场景,引领读者步入 Composition API 的世界,展现它如何优雅地解决复杂组件逻辑的管理问题,从而激发读者探索和运用 Vue 3 新特性的热情。
25 1
|
2月前
|
JavaScript 前端开发 API
深入浅出:Vue 3 Composition API 的魅力
【2月更文挑战第13天】 在前端开发的世界里,Vue.js 一直占据着重要的地位。随着 Vue 3 的推出,Composition API 成为了开发者热议的焦点。本文将从一个独特的视角探讨 Composition API 的核心优势,通过对比 Options API,解析其如何优化代码组织和提升项目的可维护性。我们将通过实际案例,深入理解 Composition API 的使用方法和最佳实践,帮助开发者更好地把握这一新工具,激发前端开发的无限可能。
|
2月前
|
JavaScript API
vue 3.0 所采用的 Composition Api 和 vue 2.0 使用的 Option Api 区别
vue 3.0 所采用的 Composition Api 和 vue 2.0 使用的 Option Api 区别
37 0
|
17天前
|
JavaScript 前端开发 API
组合API:掌握Vue的组合式API(Composition API)
【4月更文挑战第24天】Vue.js的组合式API是Vue 3中的新特性,旨在提供更灵活的组件逻辑组织方式。它允许开发者像React Hooks一样定义和复用逻辑单元——组合函数。通过组合函数,可以跨组件共享和管理状态,提升代码复用和维护性。本文介绍了如何开始使用组合式API,包括安装Vue CLI、引入API、使用组合函数以及组织和复用逻辑。掌握组合式API能增强开发复杂应用的能力,改善代码结构和可读性。
|
1月前
|
JavaScript API UED
Vue3.0新特性解析与实战:Composition API、Teleport与Suspense
【4月更文挑战第6天】Vue3.0引入了颠覆性的Composition API,通过函数式方法提升代码可读性和复用性,例如`setup()`、`ref`等,便于逻辑模块化。实战中,自定义的`useUser`函数可在多个组件中共享用户信息逻辑。另外,Teleport允许组件渲染到DOM特定位置,解决模态框等场景的上下文问题。再者,Suspense提供异步组件加载的延迟渲染,使用fallback内容改善用户体验。这些新特性显著优化了开发和性能,适应现代Web需求。
23 0
|
1月前
|
JavaScript API
Composition Api 与 Options Api 有什么区别?
Composition Api 与 Options Api 有什么区别?
16 0
|
2月前
|
JavaScript 前端开发 API
深入浅出Vue 3 Composition API:重塑前端开发范式
【2月更文挑战第12天】 本文旨在深入探讨Vue 3中的Composition API,一种全新的组件和逻辑复用方式。相较于传统的Options API,Composition API提供了更为灵活和高效的代码组织机制。通过实例和对比分析,我们将揭示其如何优化代码结构,提升项目的可维护性和扩展性。文章不仅为初学者铺平进入Vue 3世界的道路,也为有经验的开发者提供了深度思考的视角,探索前端开发的新范式。
|
2月前
|
JavaScript 前端开发 API
深入浅出:Vue 3 Composition API 的革新之旅
【2月更文挑战第11天】本文将带你深入探索 Vue 3 中的 Composition API,一项革命性的特性,旨在提高代码的组织性和可复用性。我们将通过实际案例,对比传统的 Options API,深入理解 Composition API 如何优化组件逻辑的组织和重用,从而让前端开发变得更加高效和灵活。文章不仅仅是技术指南,更是对前端开发模式思考的一次探索之旅。