之前寫過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一下我的專案。謝謝。