uwp ListView列表滑动特效_.NET_编程开发_程序员俱乐部

中国优秀的程序员网站程序员频道CXYCLUB技术地图
热搜:
更多>>
 
您所在的位置: 程序员俱乐部 > 编程开发 > .NET > uwp ListView列表滑动特效

uwp ListView列表滑动特效

 2017/11/23 16:10:25  吃饭/睡觉  程序员俱乐部  我要评论(0)
  • 摘要:在看过一篇文章WPF自定义控件之列表滑动特效PowerListBoxhttp://www.cnblogs.com/ShenNan/p/4993374.html#3619585实现了滑动的特效(就是动画)之后,觉得很有趣也想在UWP里面实现。最好效果如下接下来就说说是怎么实现的吧:一.添加Behaviors右键项目选中“管理NuGet程序包”然后搜索Behaviors添加二.添加一个新的类这个类就叫ListViewBehavior吧继承DependencyObject
  • 标签:view list 滑动

   在看过一篇文章  

WPF自定义控件之列表滑动特效 PowerListBox  http://www.cnblogs.com/ShenNan/p/4993374.html#3619585 实现了滑动的特效(就是动画)之后 ,觉得很有趣 也想在 UWP里面实现。最好效果如下

接下来就说说是怎么实现的吧:

一. 添加 Behaviors

  右键项目 选中 “管理 NuGet 程序包”

然后搜索 Behaviors 添加

 

 二 . 添加一个新的类

      这个类就叫

ListViewBehavior 

吧 继承 DependencyObject, 继承接口 IBehavior 然后显示继承这个接口的两个方法

  public class ListViewBehavior : DependencyObject, IBehavior
    {
        public DependencyObject AssociatedObject { get; set; }

        public void Attach(DependencyObject associatedObject)
        {
            throw new NotImplementedException();
        }

        public void Detach()
        {
            throw new NotImplementedException();
        }
    }

然后在这个类里面添加一些属性,等会会用到

  public DependencyObject AssociatedObject { get; set; }

        /// <summary>
        /// 需要做动画的列表
        /// </summary>
        public ListView ListView;

        /// <summary>
        /// listView 里面的滚动条
        /// </summary>
        public ScrollViewer scroll;

          /// <summary>
          /// 容器的布局方向
           /// </summary>
            private Orientation _panelOrientation;


/// <summary> /// 当前可视化视图的第一项 /// </summary> private int firstVisibleIndex; /// <summary> /// 当前可视化视图的最后一项 /// </summary> private int lastVisibleIndex; /// <summary> /// 上次滚动时可视化视图的第一项 /// </summary> private int oldFirstVisibleIndex; /// <summary> /// 上次滚动时可视化视图的最后一项 /// </summary> private int oldLastVisibleIndex; /// <summary> /// 标识,是否已找到第一项 /// </summary> private bool isFindFirst; /// <summary> /// 当前累计已遍历过的Item高度或宽度的值,用于寻找第一项和最后一项 /// </summary> private double cumulativeNum; public void Attach(DependencyObject associatedObject) { } public void Detach() { }

属性都准备好了那我们现在开始进入正式的后续吧 , 在 Attach 方法里面添加代码

public void Attach(DependencyObject associatedObject)
        {
           //获取 ListView 列表对象
            ListView = associatedObject as ListView;

            if (ListView ==null )
            {
                return;
            }

            //传进来的 对象不为空,我们就对这个对象注册一个事件
            ListView.Loaded += ListView_Loaded;
        }

ListView_Lodaded 代码:

 /// <summary>
        /// 列表对象加载完成后的逻辑代码
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void ListView_Loaded(object sender, RoutedEventArgs e)
        {
            //查找滚动视图,并赋值到我们刚刚添加的属性里
            scroll = FindVisualChild<ScrollViewer>(ListView, "ScrollViewer");
            //判断是否为空,不为空的话就添加一个事件
            if (scroll == null)
            {
                return;
            }
            else
            {
                //监听滚动事件
                scroll.ViewChanged += Scroll_ViewChanged;
            }

             ItemsPresenter v = FindVisualChild<ItemsPresenter>(ListView, "");


             ItemsStackPanel items = FindVisualChild<ItemsStackPanel>(v,"");


             _panelOrientation = items.Orientation;



        }
 /// <summary>
        /// 获取模板控件
        /// </summary>
        /// <typeparam name="T">获取的类型</typeparam>
        /// <param name="obj">控件对象</param>
        /// <returns></returns>
        protected T FindVisualChild<T>(DependencyObject obj, string name) where T : DependencyObject
        {
            //获取控件可视化树中的子对象数量
            int count = VisualTreeHelper.GetChildrenCount(obj);

            //根据索引遍历每一个对象
            for (int i = 0; i < count; i++)
            {
                var child = VisualTreeHelper.GetChild(obj, i);
                //根据参数判断是不是我们要找的对象,如果是 就返回,并退出该方法,
                //如果不是则再递归到下一层查找
                if (child is T && ((FrameworkElement)child).Name == name)
                {
                    return (T)child;
                }
                else
                {
                    var child1 = FindVisualChild<T>(child, name);

                    if (child1 != null)
                    {
                        return (T)child1;
                    }


                }
            }

            return null;

        }

 

现在已经获取到了 列表的 ScrollViewer 对象了 就可以执行这个 动画最核心的部分了,就是通过监听 滚动事件 来获取我们需要做动画的控件了。

 /// <summary>
        /// 监听滚动事件
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void Scroll_ViewChanged(object sender, ScrollViewerViewChangedEventArgs e)
        {
            //每次滚动时都计算当前可视化区域的首尾项
            CalculationIndex();
        }

再添加两个字段

 /// <summary>
        /// 列表子控件的高度
        /// </summary>
        private double itemsHeight;
        //平移特效对象
        private TranslateTransform tt;
  /// <summary>
        /// 计算可视化区域的第一项和最后一项
        /// </summary>
        private void CalculationIndex()
        {
            //赋值旧的第一个可视化视图
            oldFirstVisibleIndex = firstVisibleIndex;
            //赋值最后一个可视化视图
            oldLastVisibleIndex = lastVisibleIndex;

            ;
            //标记第一项是否找到了
            isFindFirst = false;
            //判断列表的方向
            if (_panelOrientation == Orientation.Vertical)
            {
                cumulativeNum = 0.0;


                //遍历列表的全部可视化视图,寻找第一项和最后一项
                for (int i = 0; i < ListView.Items.Count; i++)
                {


                    //转换成 ListViewItem 对象,用于操作
                    var _item = ListView.ContainerFromIndex(i) as ListViewItem;

                    //这里有个坑,应为 ListView 支持虚拟化的,所以每次获取列表的
                    //子项最多只会有20项左右,所以我们要记录一下 高度,将所遍历到的
                    //可视化视图的高度累加。

                    if (_item == null)
                    {
                        
                        cumulativeNum += itemsHeight;
                    }
                    else
                    {
                        itemsHeight = _item.ActualHeight;
                        cumulativeNum += _item.ActualHeight + _item.Margin.Top + _item.Margin.Bottom;

                    }
                    //判断当前所累加的高度大于我们滚动的距离找到 现在显示在屏幕上的第一项
                    if (!isFindFirst && cumulativeNum >= scroll.VerticalOffset)
                    {
                        //记录第一项的索性
                        firstVisibleIndex = i;
                        //表明第一项已经找到了
                        isFindFirst = true;

                        Up();
                    }

                    //当前所累加的高度 大于 当前移动的距离和 滚动视图的可见高度,找出最后一项
                    if (cumulativeNum >= (scroll.VerticalOffset + scroll.ViewportHeight))
                    {
                        //记录最后一项的索引
                        lastVisibleIndex = i;

                        Down();

                        //已经找到的第一项和最后一项了 跳出循环
                        break;
                    }


                    ;

                }
            }

        }

 

最后 两个进行动画的方法:

  /// <summary>
        /// 滚动条向下,类容向上移动
        /// </summary>
        private void Down()
        {

            if ((firstVisibleIndex == oldFirstVisibleIndex && lastVisibleIndex == oldLastVisibleIndex) || oldFirstVisibleIndex == 0 && oldLastVisibleIndex == 0)
                return;

            //判断 当前最后一项 是否大于上次移动的最后一项
            if (lastVisibleIndex > oldLastVisibleIndex)
            {
                //获取可视化对象
                var _item = ListView.ContainerFromIndex(lastVisibleIndex) as ListViewItem;
                //
                tt = new TranslateTransform();

                //这里要判断一下 当前可视化是否为空,如果你移动得比较快的化,列表的虚拟化会给不到对象来的。
                if (_item == null)
                {
                    return;
                }


                _item.RenderTransform = tt;

                Storyboard board = new Storyboard();

                //创建一个 double 动画
                DoubleAnimation animation = new DoubleAnimation() { AutoReverse = false, RepeatBehavior = new RepeatBehavior(1), EnableDependentAnimation = true, To = 0, From = _item.ActualWidth / 2, Duration = TimeSpan.FromSeconds(0.2) };
                Storyboard.SetTarget(animation, tt);
                Storyboard.SetTargetProperty(animation, nameof(TranslateTransform.X));

                board.Children.Add(animation);

                board.Begin();

               


            }
        }

        /// <summary>
        /// 滚动条向上,内容向下
        /// </summary>
        private void Up()
        {
            if (firstVisibleIndex < oldFirstVisibleIndex)
            {
                var _item = ListView.ContainerFromIndex(firstVisibleIndex) as ListViewItem;

                tt = new TranslateTransform();
                if (_item == null)
                {
                    return;
                }
                _item.RenderTransform = tt;



                Storyboard board = new Storyboard();


                DoubleAnimation animation = new DoubleAnimation() { AutoReverse = false, RepeatBehavior = new RepeatBehavior(1), EnableDependentAnimation = true, To = 0, From = _item.ActualWidth / 2, Duration = TimeSpan.FromSeconds(0.3) };
                Storyboard.SetTarget(animation, tt);
                Storyboard.SetTargetProperty(animation, nameof(TranslateTransform.X));

                board.Children.Add(animation);

                board.Begin();

               
            }
        }

 

这个了类已经完成了最后我们在前台调试一下吧:前台代码:

<Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
        <ListView x:Name="listView"   >
            <ListView.ItemContainerStyle>
                <Style TargetType="ListViewItem" >
                    <Setter Property="HorizontalContentAlignment" Value="Stretch" ></Setter>
                </Style>
            </ListView.ItemContainerStyle>
            <ListView.ItemTemplate>
                <DataTemplate>
                    <Grid HorizontalAlignment="Stretch" VerticalAlignment="Stretch"  >
                        <Rectangle Height="100" Fill="Red"  HorizontalAlignment="Stretch"  Margin="5" ></Rectangle>
                        <TextBlock Text="{Binding }" FontSize="50" HorizontalAlignment="Right" VerticalAlignment="Center" Margin="20" ></TextBlock>
                    </Grid>
                </DataTemplate>
            </ListView.ItemTemplate>
           
            
            
                     
            <interactivity:Interaction.Behaviors>
                <local:ListViewBehavior></local:ListViewBehavior>
            </interactivity:Interaction.Behaviors>
        </ListView>

        
    </Grid>

就这样我们就完成了一个滚动列表特效了,大家可以在 Down 和 Up 这两个方法里面修改其动画效果可以变得更加酷点,
第一次写博客。。。。。。。呜呜呜

发表评论
用户名: 匿名