模仿NetFlix首頁效果

貓叔Vincent發表於2020-04-20

之前寫過UWP 帶左右滾動按鈕的橫向ListView———仿NetFlix首頁河的設計,講述瞭如何設計一個帶有左右滾動按鈕橫向的ListView。

不過我在半年之前挖了一個坑,由於工作關係,沒時間來填坑。這篇文章也是花了好幾天時間零零散散寫的。

 

要是完全實現仿照NetFlix首頁那樣,我們還需要一個豎向的重複排列的控制元件。【什麼???NetFlix是什麼???一個世界頂級視訊網站,相比之下優酷騰訊愛奇藝都是渣渣的那種】

說到這,大家肯定首先想到了ListView。

沒錯,我一開始也確實用來ListView,然後再它的DataTemplate裡面用了之前那篇文章的控制元件。

<Page.Resources>
   <DataTemplate x:Key="riverTemplate" x:DataType="local:Product">
      <StackPanel>
         <Image Width="200" Height="200" Source="{x:Bind image}"/>
         <TextBlock Text="{x:Bind text}" Margin="0 10 0 0" FontSize="18"/>
      </StackPanel>
   </DataTemplate>
</Page.Resources>

<ListView x:Name="listView">
   <ListView.ItemTemplate>
      <DataTemplate x:DataType="local:StoreModel">
         <StackPanel Margin="0 0 0 32">
         <TextBlock Text="{x:Bind title}" FontSize="28"/>
         <local:StepThroughListView
            Margin="0 10 0 0"
            AlwaysShowButton="Collapsed"
            ItemsSource="{x:Bind products}"
            ItemTemplate="{StaticResource riverTemplate}"/>
         </StackPanel>
      </DataTemplate>
   </ListView.ItemTemplate>
</ListView>

 

 

上面的程式碼會產生下面的類似效果圖:

 

 

 

在這之前,先說明一下,NetFlix的首頁上下滾動,資料非常多,而且不卡的。

使用了ListView承載的話,它會啟動內部的虛擬化機制,不渲染沒有在視野的Items,減少App的CPU和記憶體消耗。

 

但是!!!

有一個非常大的bug就是,在實際的專案中,資料模板設計會有比較多的元素展示。當用滑鼠快速上下拖動滾動條的時候,整個App就是一片空白,控制元件渲染速度明顯跟不上了。

還有就是在XBox上也是一樣,更慢。。。

 

 

所以為了優化ListView,微軟在Windows UI Library專案中又新推出了一個船新的ItemsRepeater控制元件。

ItemsRepeater,從字面的意思上就可以猜出大概,它只是完成一些重複的項,並且它沒有UI。

通過 ItemsRepeater 建立使用靈活佈局系統、自定義檢視和虛擬化的自定義集合體驗。
與 ListView 不同,ItemsRepeater 不提供綜合性的終端使用者體驗 - 它沒有沒有預設 UI,不提供任何圍繞焦點、選擇或使用者互動的策略, 
而是一個構建基塊,你可以使用它來建立自己的基於集合的獨特體驗和自定義控制元件。 雖然它沒有內建的策略,但允許你附加策略來構建所需的體驗。 例如,你可以定義要使用的佈局、鍵盤操作策略、選擇策略等。
在概念上,可以將 ItemsRepeater 視為資料驅動的皮膚,而不是 ListView 之類的完整控制元件。 

 

 

由此可以看出,ItemsRepeater好像是吸取了Flutter的精髓,萬物皆是Widget的思想。其實如果之前所有的UWP控制元件都要是圍繞這種思想的話,UWP也不至於淪落至此。

既然ItemsRepeater是一個基塊,那麼我們就可以像搭積木一樣,把它放進如何現有的控制元件中。

沒有UI和互動的程式碼邏輯,從而可以實現更為高效的佈局,這使得ItemsRepeater在終端使用者體驗上比ListView,特別是在中低端機器上,更為優秀。

 

那麼,到這裡大家就清楚了,要實現一個類似NetFLix的效果,我們需要一個縱向的ItemsRepeater,每一個ItemsRepeater需要包含一個橫向的ItemsRepeater。

 

1. 通過ItemsRepeater進行滾動

ItemsRepeater 不是派生自控制元件,因此沒有控制元件模板。 因此,它不包含任何內建的滾動功能,這一點不同於 ListView 或其他集合控制元件。
使用 ItemsRepeater 時,若要提供滾動功能,則應將其包裝在 ScrollViewer 控制元件中。

通過檢視ItemsRepeater的後設資料也可以看到。

 

 

如果應用會在較早的 Windows 版本(在 Windows 10 版本 1809 之前發行的版本)上執行,則還需將 ScrollViewer 託管在 ItemsRepeaterScrollHost 中。

 

<muxc:ItemsRepeaterScrollHost>
    <ScrollViewer>
        <muxc:ItemsRepeater ... />
    </ScrollViewer>
</muxc:ItemsRepeaterScrollHost>

 

 

2. 定義資料模板

首先從小到大,先分解一下水平的列表,定義成一個Horizontal Template

一張電視劇封面圖,下面放一個對圖片的描述,比如電視劇名稱,分類等

        <!--Horizontal ItemsRepeater data template-->
        <DataTemplate x:Key="HorizontalTemplate" x:DataType="local:Product">
            <StackPanel>
                <Image 
                    Source="{x:Bind image}"/>
                <TextBlock 
                    Margin="0 12 0 0"
                    Text="{x:Bind text}"/>
            </StackPanel>
        </DataTemplate>

 

 

然後整個縱向的列表,定義一個Vertical Template

一個標題分類,加上這個分類下的一些電視劇。

        <!--Vertical ItemsRepeater data template-->
        <DataTemplate x:Key="VerticalTemplate" x:DataType="local:StoreModel">
            <StackPanel>
                <TextBlock 
                    Text="{x:Bind title}"/>
                <muxc:ItemsRepeater 
                    Margin="0 20 0 0" 
                    ItemsSource="{x:Bind products}"
                    ItemTemplate="{StaticResource HorizontalTemplate}"/>
            </StackPanel>
        </DataTemplate>

 

大體的模型如下

 

3. 開始寫介面

就像一開始所說的那樣,最好在ScrollViewer外面加上一個ScrollHost,這樣比較保險一點。 

    <muxc:ItemsRepeaterScrollHost>
        <ScrollViewer>
            <muxc:ItemsRepeater
                x:Name="NetFlixItemsRepeater"
                ItemTemplate="{StaticResource VerticalTemplate}">
                <muxc:ItemsRepeater.Layout>
                    <muxc:StackLayout Orientation="Vertical" Spacing="40"/>
                </muxc:ItemsRepeater.Layout>
            </muxc:ItemsRepeater>
        </ScrollViewer>
    </muxc:ItemsRepeaterScrollHost>

 

 

需要注意的是,在ItemsRepeater的佈局裡面,需要指定它的方向。預設是縱向的。

像剛才在橫向的模板裡面,我就特別指定它的方向是橫向。

 

4. 編寫測試資料,進行壓力測試

我直接在Page_Laded里加了資料,簡單粗暴。

        private void Page_Loaded(object sender, RoutedEventArgs e)
        {
            List<Product> products = new List<Product>();
            for (int i = 0; i < 100; i++)
            {
                products.Add(
                    new Product {
                    text = i.ToString(),
                    image = "ms-appx:///Assets/v2.jpg"
                    }
                    ) ;
            }

            for (int i = 0; i < 100; i++)
            {
                stores.Add(
                    new StoreModel
                    {
                        title = "River" + i.ToString(),
                        products = products
                    }
                    );
            }

            //listView.ItemsSource = stores;
            NetFlixItemsRepeater.ItemsSource = stores;
        }

  

 

5. 執行App測試,看記憶體和CPU

 

 

 

 

 

視訊連結:https://youtu.be/2qqYywttue4

 

也歡迎大家訂閱我的Youtube頻道,謝謝!

 

點選右下角紅色小鈴鐺?,第一時間獲取最新資訊。

 

 

 

本專案已開源,專案地址:https://github.com/hupo376787/NetFlix_UWP

也歡迎Star一下我的專案。謝謝。

 

相關文章