博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
UWP Composition API - GroupListView(二)
阅读量:5975 次
发布时间:2019-06-20

本文共 9333 字,大约阅读时间需要 31 分钟。

还是先上效果图:

看完了上一篇的童鞋会问,这不是跟上一篇一样的吗??? 骗点击的??

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

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

我再啰嗦下需求:

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

2.支持UI Virtualization

这个简单的方案就是改ListViewItem的模板,其实我在有讲过ListViewItem有2套模板-

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

View Code

注意上图,我把默认模板里面的内容放到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;            }        }    }

当然不要忘记了在里面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;                                                }                                            }                                        }                                    }                                }                            }                        }                    }                }            }        }

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

当然这个里面也有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;        }

加上之后:

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

开源有益,。

 

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

下图是,当时我就是拿ScrollViewer做的,当时找了半天也没找到禁止下面动画的方法。

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

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

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

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

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

你可能感兴趣的文章
SQL Server Reporting Services:无法检索应用程序文件。部署中的文件已损坏
查看>>
hive中partition如何使用
查看>>
查看mysql数据库版本方法总结
查看>>
大牛手把手教你做日历(建议你看看,你会有收获的)
查看>>
Django中的ORM
查看>>
iOS开发UI篇—Quartz2D使用(图片剪切)
查看>>
spring学习笔记(20)数据库事务并发与锁详解
查看>>
关于Simple_html_dom的小应用
查看>>
鲁肃:蚂蚁金服的三个梦想
查看>>
华为程序员:加6天班!加班费1.4万元!网友:我能加到它破产
查看>>
Linux入门基础之grep命令详解及正则表达式
查看>>
Linux之Find命令详解
查看>>
crysis2 video&cryengine3 editor show
查看>>
Hibernate学习之SessionFactory的opensession 和 getCu...
查看>>
web网站服务(二)
查看>>
【第一期】网站打开错误问题解决方法集合
查看>>
j2ee开发防范URL攻击是个重要话题
查看>>
RSync实现文件备份同步
查看>>
如何判断一个服务是否正在运行
查看>>
精品软件 推荐 相当优秀的轻量级文本编辑器 Notepad2
查看>>