还是先上效果图:

看完了上一篇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 FadeInThemeAnimationson 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 weapproximate 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
                            {//unloadedif (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 suddenlyif (rect.Bottom < 0 || rect.Top > this.ActualHeight){}//in view portelse{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 frameexpression.SetReferenceParameter("ScrollViewerManipProps", scrollViewerManipProps);visual.StartAnimation("Offset.Y", expression);//Windows.UI.Xaml.Media.CompositionTarget.Rendering += OnCompositionTargetRendering;}

加上之后:

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

开源有益,源码GitHub地址。

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

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

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

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

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

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

转载于:https://www.cnblogs.com/FaDeKongJian/p/5630414.html

UWP Composition API - GroupListView(二)相关推荐

  1. UWP Composition API - GroupListView(一)

    需求: 光看标题大家肯定不知道是什么东西,先上效果图: 这不就是ListView的Group效果吗?? 看上去是的.但是请听完需求. 1.Group中的集合需要支持增量加载ISupportIncrem ...

  2. UWP Composition API - 锁定列的FlexGrid

    原文:UWP Composition API - 锁定列的FlexGrid 需求是第一列锁定,那么怎么让锁定列不跟着滚动条向做移动呢? 其实很简单,让锁定列跟scrollviewer的滚动做反方向移动 ...

  3. UWP Composition API - PullToRefresh

    原文:UWP Composition API - PullToRefresh 背景: 之前用ScrollViewer 来做过 PullToRefresh的控件,在项目一些特殊的条件下总有一些问题,比如 ...

  4. UWP Composition API - RadialMenu

    原文:UWP Composition API - RadialMenu 用Windows 8.1的童鞋应该知道OneNote里面有一个RadialMenu.如下图,下图是WIn10应用Drawboar ...

  5. Vue3 Composition API(二)——computed、watchEffect、setup中使用ref

    一.computed 在前面我们讲解过计算属性computed:当我们的某些属性是依赖其他状态时,我们可以使用计算属性来处理 在前面的Options API中,我们是使用computed选项来完成的: ...

  6. vue3学习笔记 Composition API setup

    一.Composition API优势 相对于vue2的option API Vue3的Composition API设计更有优势 Composition(组合式)Api 功能分组 Compositi ...

  7. Vue3 Composition API(三)——生命周期钩子、Provide函数 和 Inject函数、封装Hook案例、setup顶层编写方式

    一.生命周期钩子 我们前面说过 setup 可以用来替代 data . methods . computed .watch 等等这些选项,也可以替代 生命周期钩子. 那么setup中如何使用生命周期函 ...

  8. Vue3 Composition API(一)——setup、reactive、ref、readonly

    一.Options API的弊端 在Vue2中,我们编写组件的方式是Options API: Options API的一大特点就是在对应的属性中编写对应的功能模块: 比如data定义数据.method ...

  9. Vue3.0 Composition API与Vue2.x 使用的 Options API

    Vue3.0 所采用的 Composition API 与 Vue2.x 使用的 Options API 有什么不同 开始之前 Composition API 可以说是Vue3最大的特点,那么为什么要 ...

最新文章

  1. Kazoo安装和使用
  2. 高并发大流量专题---8、动态语言的并发处理
  3. 阿里打破自然语言理解世界纪录,AI常识推理水平正在逼近人类
  4. Java中对象的销毁
  5. MySQL返回多行错误怎么处理_结果包含多个行错误mysql
  6. Python Flask-表单提交方式
  7. 【原】页面跳转以及表单提交中有中文的解决办法
  8. 查看docker容器日志
  9. 禁止sethc.exe运行 防止3389的sethc后门
  10. Java 线程池详解及实例代码
  11. C#基础 基本语法4
  12. 十个个必装的火狐插件
  13. 伍德里奇计量经济学第四章课后计算机作业,伍德里奇---计量经济学第4章部分计算机习题详解(MATLAB).pdf...
  14. uni-app简单介绍
  15. 2021年程序员个人年终工作总结10篇
  16. 【数据库原理及应用教程(第4版|微课版)陈志泊】【第一章习题】
  17. 【对比Java学Kotlin】类型别名
  18. js一键复制并调起微信客户端
  19. SaltStack技术入门与实践
  20. 一键安装google服务框架(更新最新版google市场)

热门文章

  1. Under the Hoods of Cache Fusion, GES, GRD and GCS
  2. 如何在一个月内让QQ农场冲上40级
  3. 前端本地使用线上数据
  4. 中小企业监控体系构建实战
  5. GDI+ 学习记录(23): 输出文本
  6. Entity Framework 4 in Action读书笔记——第六章:理解实体的生命周期(三)
  7. 转贴:从现在电力短缺看今后劳动力短缺和高校破产
  8. Puppet 笔记 模板
  9. 对于技术焦虑的一点想法
  10. Material Theme