uwp ListView列表滑動特效

来源:http://www.cnblogs.com/chifan/archive/2017/11/23/7884867.html
-Advertisement-
Play Games

在看過一篇文章 WPF自定義控制項之列表滑動特效 PowerListBox http://www.cnblogs.com/ShenNan/p/4993374.html#3619585 實現了滑動的特效(就是動畫)之後 ,覺得很有趣 也想在 UWP裡面實現。最好效果如下 接下來就說說是怎麼實現的吧: 一 ...


   在看過一篇文章  

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


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 經常遇到這樣的需求, 生成Word格式的報告, 而不是單純的一張表格的報表. 就像體檢報告一樣. 數據來源部分決定採用一個存儲過程返回Dataset的方式, 整張報告的數據來源於此Dataset的多個Datatable. 首先通過配置文件遍歷Dataset生成Word文檔, 但這就意味著要配置的內容 ...
  • HiLo是在NHiernate中生成主鍵的一種方式,不過現在我們可以在Entity Framework Core中使用。所以在這篇內容中,我將向您在如何使用HiL在Entity Framework Core生成主鍵。 ...
  • 1. 前言 這是我最近項目剛要的需求,然後在網上找了半天的教材 但是很不幸,有關於Epplus的介紹真的太少了,然後經過了我的不斷研究然後不斷的採坑,知道現在看到Excel都想吐的時候,終於成功的完成了公司的要求,最後我 稍微的優化了一下代碼(畢竟是個剛工作一年多的新人),現在就給大家看一看不足之處 ...
  • 一,最近在學習abp的東西。發現其中作者在獲取數據時,大量的使用了async和awaiit。好吧,因為不太懂,所以網上搜搜,在這裡記錄一下。 先來看一段代碼。調用UpdateUserAsync會返回一個Task,那task是個啥呢。根據騰飛(Jesse)的說法,task是async和awaiit的叔 ...
  • 導入導出對於剛做的人一臉懵逼,但是明白思路之後就感覺非常容易,我也是研究了好久,才總算做了出來,放在這裡給大家分享一下 一.先看下導出 視圖腳本 視圖html代碼 控制器代碼 二,從Excel導入資料庫 視圖代碼 控制器代碼 public ActionResult Show(HttpPostedFi ...
  • c# 多線程 由於代碼已經過優化或者本機框架位於調用堆棧之上,無法計算表達式的值 ...
  • 工作中我們會使用到各種各樣的文檔,其中,PPT起著不可或缺的作用。一份PPT文檔里可能包含重要商業計劃、企業運營資料或者公司管理資料等。因此,在競爭環境里,企業重要資料的保密工作就顯得尤為重要,而對於重要資料我們可以選擇添加密碼的形式來進行文檔保護。本文將介紹如何通過C#來給PPT添加密碼,當然你也 ...
  • 關於web變數配置問題 webservice裡面介面完成時考慮到介面可能用在不同的伺服器,不同的資料庫所以將鏈接地址修改成變數,在webconfig裡面去修改它更加的容易方便 假始根據在同一個伺服器裡面,訪問不同的資料庫裡面的數據首先可以將資料庫名申明成為一個變數,在web裡面調用介面時,可以自由填 ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...