uwp ListView列表滑動特效

   在看過一篇文章  html

WPF自定義控件之列表滑動特效 PowerListBox  http://www.cnblogs.com/ShenNan/p/4993374.html#3619585 實現了滑動的特效(就是動畫)以後 ,以爲頗有趣 也想在 UWP裏面實現。最好效果以下

接下來就說說是怎麼實現的吧:佈局

一. 添加 Behaviorspost

  右鍵項目 選中 「管理 NuGet 程序包」動畫

而後搜索 Behaviors 添加url

 

 二 . 添加一個新的類spa

      這個類就叫3d

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();
        }
    }

而後在這個類裏面添加一些屬性,等會會用到code

  public DependencyObject AssociatedObject { get; set; }

        /// <summary>
        /// 須要作動畫的列表
        /// </summary>
        public ListView ListView;

        /// <summary>
        /// listView 裏面的滾動條
        /// </summary>
        public ScrollViewer scroll;

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


/// <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 這兩個方法裏面修改其動畫效果能夠變得更加酷點,第一次寫博客。。。。。。。嗚嗚嗚

相關文章
相關標籤/搜索