【UWP】列表項寬度自適應的實現


目的

在UWP開發中,我們常常用到兩個顯示列表的控件:ListView和GridView。而這兩個列表控件在PC等大屏幕上如果能多列“智能”調整自己的大小(通常是根據當前窗口大小調整寬度),那么用戶就會在同一屏幕內接收到更多信息,同時空間的利用率得以提高,也會提高應用的視覺體驗。這是我的第一篇博客,向大家分享一下列表項寬度自適應的實現。

實現思路及方法

我們最初的想法可能是,定義列表項模板,給模板里的Panel起個名字,在窗口的SizeChanged事件里加入調整其寬度的代碼。這種想法最朴素,然而在操作中遇到了一些問題:我們不能在后台代碼里直接訪問DataTemplete里的元素。而且,當同一頁面中存在多個列表時,給大家都分配一個名字也比較傻,而且后台代碼會堆積,不利於維護。

這個時候,數據綁定就可以大顯身手了。

我們可以在Xaml里定義一個隨便什么元素(當然,它只起到一個“橋”的作用,不能影響當前布局。(廢話))這里,我們定義一個Border即可:

1 <Border x:Name="width"/>

然后,創建一個我們想要實現自適應的列表,注意其中的綁定

1 <GridView  x:Name="testlist">
2   <GridView.ItemTemplate>
3     <DataTemplate>
4       <Grid Width="{Binding ElementName=width,Path=Width}">
5                ......                                    
6       </Grid>
7     </DataTemplate>
8   </GridView.ItemTemplate>
9 </GridView>

接下來我們所要做的只有一步:在后台的SizeChanged事件中加入對width寬度的調整即可。這里為了方便,我們把它寫成一個方法,可以放在自己App的Helper類里供應用內所有列表調用。這個方法長成這個樣子:

 1   class WidthFit
 2     {
 3         /// <summary>
 4         /// 獲取自適應列表項寬度
 5         /// </summary>
 6         /// <param name="width">當前窗口寬度</param>
 7         /// <param name="max">列表項最大寬度</param>
 8         /// <param name="min">列表項最小寬度</param>
 9         /// <param name="offset">偏移量</param>
10         /// <returns></returns>
11         public static double GetWidth(double width, int max, int min, int offset = 8)
12         {
13             if (offset < 0 || offset > 12)
14             {
15                 offset = 8;
16             }
17             double w = 1;
18             int column = 1;
19             int maxcolumn = (int)width / min;
20             double i2 = width / min;
21             for (int i = 1; i <= maxcolumn; i++)
22             {
23                 if (Math.Abs(i - i2) < 1) 
24                 {
25                     column = (int)Math.Truncate(i2) == 0 ? 1 : (int)Math.Truncate(i2);
26                 }
27             }
28             w = width / column;
29             w -= offset * column;
30             return w;
31         }
32     }

 

代碼很易讀,在這里不做過多說明。只說明一下,offset這個參數用來設定寬度的偏移量,因為我們的列表項之間、列表與父面板間通常會有間距,這個間距也要被考慮到,否則實際顯示的列數可能會減少,很不美觀。

這樣,我們可以方便地調用此方法:

1 private void Page_SizeChanged(object sender, SizeChangedEventArgs e)
2 {
3   width.Width = WidthFit.GetWidth(ActualWidth, 600, 300);
4 }

實現的效果就不貼出來了,大家可以動手試一試。

還有什么沒提到……

ListView能實現這種效果嗎?能。具體做法也很簡單,更改一下ListView默認的ItemPanel即可,余下的工作與GridView完全一樣。

 1 <ListView.Style>
 2     <Style TargetType="ListView">
 3         <Setter Property="ItemsPanel">
 4             <Setter.Value>
 5                 <ItemsPanelTemplate>
 6                     <ItemsWrapGrid  Orientation="Horizontal"/>
 7                 </ItemsPanelTemplate>
 8             </Setter.Value>
 9         </Setter>
10     </Style>
11 </ListView.Style>        

到了要說“但是”的時候了。上面提到的GetWidth方法有一個小缺陷:可能會造成看上去像是“顯示的列數受到損失”的情況(當然啦,這個概率很小)。我們發現,這個Bug出現在列數發生變動的臨界值附近。而原因其實也很簡單,此時我們定義的最大寬度小於當前窗口寬度與計算出的列數的比,因而無法鋪滿窗口的寬度,看上去就像是少了一列一樣。這個小缺陷當然也易於修正,大家可以在GetWidth方法里做點文章,怠惰一點的話,也可以直接使最大寬度設置得大一點。

 

明明快到考期了,可我還是“死豬不怕開水燙,越到考期我越浪”,強行水了我的第一篇博客。如果有什么錯誤與不周到的地方還望大佬們指正。我去補作業了……


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM