• 【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方法里做点文章,怠惰一点的话,也可以直接使最大宽度设置得大一点。

    明明快到考期了,可我还是“死猪不怕开水烫,越到考期我越浪”,强行水了我的第一篇博客。如果有什么错误与不周到的地方还望大佬们指正。我去补作业了……

  • 相关阅读:
    ASP.NET Core 问题排查:Request.EnableRewind 后第一次读取不到 Request.Body
    解决 AutoMapper ProjectTo 不起作用的问题
    解决 ASP.NET Core 自定义错误页面对 Middleware 异常无效的问题
    ASP.NET Core 从 gitlab-ci 环境变量读取配置
    终于解决 xUnit.net 测试中无法输出到控制台的问题
    ASP.NET Core 新建线程中使用依赖注入的问题
    前端回顾:2016年 JavaScript 之星
    前端工程师和设计师必读文章推荐【系列三十五】
    AsciiMorph
    Notyf
  • 原文地址:https://www.cnblogs.com/DaweiX/p/6158198.html
Copyright © 2020-2023  润新知