经验首页 前端设计 程序设计 Java相关 移动开发 数据库/运维 软件/图像 大数据/云计算 其他经验
当前位置:技术经验 » 程序设计 » ASP.net » 查看文章
UWP FillRowViewPanel
来源:cnblogs  作者:法的空间  时间:2018/9/25 20:41:36  对本文有异议

最近有童鞋有这种需求,说实话我不知道这个Panel怎么起名字。

效果连接https://tuchong.com/tags/风光/

下面是我做成的效果,可以规定每个Row的Items个数

2个

3个

4个

代码在:GitHub

下面我来说一下我的思路

其实很早之前就写过这种可变大小的控件,但这次的跟这个需求有点变化,这个每一行个数一定,大小根据图片的大小进行填充。

微软默认的VariableSizedWrapGrid和Toolikt里面的StaggeredPanel都会导致ListView失去一些特性(虚拟化,增量加载)

之前做另一种。其实现在这个差不多。就是ListViewItem 就是每一行,那么每一行里面相当于一个水平的ListView。

我只需要做一个Panel来布局填充行就可以了。。垂直上面还是ListView自带的效果

除此之后,还需要一个数据源来把 一维的数据改为了 二维的(根据每一行的个数)

直接上代码:

FillRowViewSource这个类是把一个 一维的数据源改为了 二维的。主要方法是UpdateRowItems根据RowItemsCount把集合分割

  1. private void UpdateRowItems()
  2. {
  3. if (sourceList == null)
  4. {
  5. return;
  6. }
  7. int i = 0;
  8. var rowItems = sourceList.Skip(i * RowItemsCount).Take(RowItemsCount);
  9. while (rowItems != null && rowItems.Count() != 0)
  10. {
  11. var rowItemsCount = rowItems.Count();
  12. var item = this.ElementAtOrDefault(i);
  13. if (item == null)
  14. {
  15. item = new ObservableCollection<T>();
  16. this.Insert(i, item);
  17. }
  18. for (int j = 0; j < rowItemsCount; j++)
  19. {
  20. var rowItem = rowItems.ElementAt(j);
  21. var temp = item.ElementAtOrDefault(j);
  22. if (temp==null || !temp.Equals(rowItem))
  23. {
  24. item.Insert(j, rowItem);
  25. }
  26. }
  27. while (item.Count > rowItemsCount)
  28. {
  29. item.RemoveAt(item.Count - 1);
  30. }
  31. i++;
  32. rowItems = sourceList.Skip(i * RowItemsCount).Take(RowItemsCount);
  33. }
  34. var rowCount = sourceList.Count / RowItemsCount + 1;
  35. while (this.Count > rowCount)
  36. {
  37. this.RemoveAt(this.Count - 1);
  38. }
  39. }
View Code

FillRowViewPanel 最早的时候希望使用item.Measure(new Size(double.PositiveInfinity, double.PositiveInfinity));方式来获得每个元素的大小,但是像Image这些控件不是开始就有大小的,需要等待图片加载完毕,而且每个Item都进行Measure的话。性能也不佳。

最后还是按照老控件的方式IResizable 写了个接口。绑定的数据源对象必须继承这个。你需要告诉我你的每个Item的大小尺寸。这样计算起来就方便多了而且有效多了

  1. public class FillRowViewPanel : Panel
  2. {
  3. public int MinRowItemsCount
  4. {
  5. get { return (int)GetValue(MinRowItemsCountProperty); }
  6. set { SetValue(MinRowItemsCountProperty, value); }
  7. }
  8. // Using a DependencyProperty as the backing store for MinRowItemsCount. This enables animation, styling, binding, etc...
  9. public static readonly DependencyProperty MinRowItemsCountProperty =
  10. DependencyProperty.Register("MinRowItemsCount", typeof(int), typeof(FillRowViewPanel), new PropertyMetadata(0));
  11. protected override Size MeasureOverride(Size availableSize)
  12. {
  13. var size = base.MeasureOverride(availableSize);
  14. return size;
  15. }
  16. protected override Size ArrangeOverride(Size finalSize)
  17. {
  18. double childrenWidth = 0;
  19. //double maxheight = double.MinValue;
  20. foreach (var item in Children)
  21. {
  22. if (item is ContentControl cc && cc.Content is IResizable iResizable)
  23. {
  24. //item.Measure(new Size(double.PositiveInfinity, double.PositiveInfinity));
  25. var elementSize = iResizable;
  26. var width = elementSize.Width * finalSize.Height / elementSize.Height;
  27. //maxheight = Math.Max(elementSize.Height, maxheight);
  28. childrenWidth += width;
  29. }
  30. }
  31. double ratio = childrenWidth / finalSize.Width;
  32. double x = 0;
  33. var count = Children.Count;
  34. foreach (var item in Children)
  35. {
  36. if (item is ContentControl cc && cc.Content is IResizable iResizable)
  37. {
  38. var elementSize = iResizable;
  39. var width = elementSize.Width * finalSize.Height / elementSize.Height;
  40. //if children count is less than MinRowItemsCount and chidren total width less than finalwidth
  41. //it don't need to stretch children
  42. if (count < MinRowItemsCount && ratio < 1)
  43. {
  44. //to nothing
  45. }
  46. else
  47. {
  48. width /= ratio;
  49. }
  50. var rect = new Rect(x, 0, width, finalSize.Height);
  51. item.Measure(new Size(rect.Width, finalSize.Height));
  52. item.Arrange(rect);
  53. x += width;
  54. }
  55. }
  56. return base.ArrangeOverride(finalSize);
  57. }
  58. }
View Code

在Sample页面

原理就是Listview的Item其实是个ListView。而做为Item的ListView的Panel是FillRowViewPanel

记住给FillRowViewPanel的高度进行设置。相当于每个元素的高度

  1. <ct:PullToRefreshGrid RefreshThreshold="100" PullToRefresh="PullToRefreshGrid_PullToRefresh">
  2. <ListView x:Name="FillRowView" SizeChanged="FillRowView_SizeChanged">
  3. <ListView.ItemContainerStyle>
  4. <Style TargetType="ListViewItem">
  5. <Setter Property="HorizontalContentAlignment" Value="Stretch"/>
  6. <Setter Property="Margin" Value="0"/>
  7. <Setter Property="Padding" Value="0"/>
  8. </Style>
  9. </ListView.ItemContainerStyle>
  10. <ListView.ItemTemplate>
  11. <DataTemplate>
  12. <ListView ScrollViewer.HorizontalScrollMode="Disabled" ItemsSource="{Binding}">
  13. <ListView.ItemContainerStyle>
  14. <Style TargetType="ListViewItem">
  15. <Setter Property="HorizontalContentAlignment" Value="Stretch"/>
  16. <Setter Property="VerticalContentAlignment" Value="Stretch"/>
  17. <Setter Property="Margin" Value="0"/>
  18. <Setter Property="Padding" Value="0"/>
  19. </Style>
  20. </ListView.ItemContainerStyle>
  21. <ListView.ItemsPanel>
  22. <ItemsPanelTemplate>
  23. <ct:FillRowViewPanel x:Name="fillRowViewPanel" MinRowItemsCount="2" Height="300"/>
  24. </ItemsPanelTemplate>
  25. </ListView.ItemsPanel>
  26. <ListView.ItemTemplate>
  27. <DataTemplate>
  28. <!--<msct:ImageEx Margin="5" IsCacheEnabled="True" Source="{Binding ImageUrl}" Stretch="Fill"/>-->
  29. <Image Margin="5" Source="{Binding ImageUrl}" Stretch="Fill"/>
  30. </DataTemplate>
  31. </ListView.ItemTemplate>
  32. </ListView>
  33. </DataTemplate>
  34. </ListView.ItemTemplate>
  35. </ListView>
  36. </ct:PullToRefreshGrid>
View Code

在整个ListViewSizechanged的时候我们再根据自己的需求调整RowItemsCount。

  1. private void FillRowView_SizeChanged(object sender, SizeChangedEventArgs e)
  2. {
  3. if (e.NewSize.Width < 600)
  4. {
  5. source.UpdateRowItemsCount(2);
  6. }
  7. else if (e.NewSize.Width >= 600 && e.NewSize.Width < 900)
  8. {
  9. source.UpdateRowItemsCount(3);
  10. }
  11. else
  12. {
  13. source.UpdateRowItemsCount(4);
  14. }
  15. }
View Code

整个就差不多这样了。做的比较简单。一些东西也没有全部去考虑。比如SourceList_CollectionChanged的时候。只考虑了Reset这种方式。

算是比较针对这个需求做的东东吧,如果有其他需求。可以提出来。大家一起撸撸。

老规矩 开源有益:Github

 

 友情链接:直通硅谷  点职佳  北美留学生论坛

本站QQ群:前端 618073944 | Java 606181507 | Python 626812652 | C/C++ 612253063 | 微信 634508462 | 苹果 692586424 | C#/.net 182808419 | PHP 305140648 | 运维 608723728

W3xue 的所有内容仅供测试,对任何法律问题及风险不承担任何责任。通过使用本站内容随之而来的风险与本站无关。
关于我们  |  意见建议  |  捐助我们  |  报错有奖  |  广告合作、友情链接(目前9元/月)请联系QQ:27243702 沸活量
皖ICP备17017327号-2 皖公网安备34020702000426号