目录
引用
提一下瀑布布局的需求,就是打个比方说,我有个三列的冒泡排序的留言板,从下往上冒泡的,但是每次都想要显示在最短的那一列下面,每次最新的冒泡就显示在最短的那一列后面,实现方法如下。
C#核心代码实现
主要是写一个类继承Panel,进行重写里面的方法即可
// 测量
protected override Size MeasureOverride(Size availableSize)
{
double total_y = 0; // 累计高度
// 遍历所有的子项
double per_width = (availableSize.Width - ColumnSpace * 2) / 3;
foreach (UIElement item in this.InternalChildren)
{
item.Measure(new Size(per_width, availableSize.Height));
total_y += item.DesiredSize.Height;
}
return new Size(availableSize.Width, total_y);
}
// 排列
protected override Size ArrangeOverride(Size finalSize)
{
double offset_y = 0, offset_x = 0;
double per_width = (finalSize.Width - ColumnSpace * 2) / 3;
List<Test> testList = new List<Test>();
for (int i = 0; i < this.InternalChildren.Count; i++)
{
UIElement item = this.InternalChildren[i];
// 前三个 肯定是从 0 0 开始 每次都是1/3的宽度 第一行
if (i == 0)
{
item.Arrange(new Rect(offset_x, (offset_y + RowSpace), per_width, item.DesiredSize.Height));
testList.Add(new Test { ValueX = 0, TotalColumn = item.DesiredSize.Height });
}
else if (i == 1)
{
item.Arrange(new Rect(per_width, (offset_y + RowSpace), per_width, item.DesiredSize.Height));
testList.Add(new Test { ValueX = per_width, TotalColumn = item.DesiredSize.Height });
}
else if (i == 2)
{
item.Arrange(new Rect(per_width * 2, (offset_y + RowSpace), per_width, item.DesiredSize.Height));
testList.Add(new Test { ValueX = per_width * 2, TotalColumn = item.DesiredSize.Height });
}
else
{
// 设置一个最大的值,无限大的值,然后下面进行选出最小的一直值,然后进行判断
double minC = 10000;
foreach (var m in testList)
{
minC = Math.Min(minC, m.TotalColumn);
}
Test test = new Test() { TotalColumn = minC};
testList.ForEach(f =>
{
if(test.TotalColumn == f.TotalColumn)
{
test.ValueX = f.ValueX;
}
});
// 获取到最短的那一列,然后获取坐标,在那渲染即可
item.Arrange(new Rect(test.ValueX, test.TotalColumn, per_width, item.DesiredSize.Height));
testList.ForEach( f => {
if(f.ValueX == test.ValueX)
{
f.TotalColumn += item.DesiredSize.Height;
}
});
}
}
return base.ArrangeOverride(finalSize);
}
XAML核心代码实现
<!--引用写好的类-->
<Grid>
<local:XHPanel ColumnSpace="2" RowSpace="2">
<Border Background="Gray">
<TextBlock Text="B1B1BB11BB1B1B1B1B11B11BB1B1BB11BB1B1B1B1B11B11B" FontSize="20" TextWrapping="Wrap"/>
</Border>
<Button Content="B2" Height="20"/>
<Button Content="B2" Height="90"/>
<Button Content="B2" Height="90"/>
<Button Content="B2" Height="90"/>
</local:XHPanel>
</Grid>
效果如下:
所有代码
C#:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
namespace XH.LayoutLesson
{
/// <summary>
/// 瀑布布局
/// </summary>
public class XHPanel : Panel
{
// 空隙
private double _rowSpace = 0;
public double RowSpace
{
get { return _rowSpace; }
set
{
_rowSpace = value;
// 自动刷新UI
this.InvalidateVisual();
}
}
private double _columnSpace = 0;
public double ColumnSpace
{
get { return _columnSpace; }
set
{
_columnSpace = value;
// 重新布局
this.InvalidateVisual();
}
}
// 测量
protected override Size MeasureOverride(Size availableSize)
{
double total_y = 0; // 累计高度
// 遍历所有的子项
double per_width = (availableSize.Width - ColumnSpace * 2) / 3;
foreach (UIElement item in this.InternalChildren)
{
item.Measure(new Size(per_width, availableSize.Height));
total_y += item.DesiredSize.Height;
}
return new Size(availableSize.Width, total_y);
}
// 排列
protected override Size ArrangeOverride(Size finalSize)
{
double offset_y = 0, offset_x = 0;
double per_width = (finalSize.Width - ColumnSpace * 2) / 3;
double maxHeight = 0;
List<Test> testList = new List<Test>();
for (int i = 0; i < this.InternalChildren.Count; i++)
{
UIElement item = this.InternalChildren[i];
if (i == 0)
{
item.Arrange(new Rect(offset_x, (offset_y + RowSpace), per_width, item.DesiredSize.Height));
testList.Add(new Test { ValueX = 0, TotalColumn = item.DesiredSize.Height });
}
else if (i == 1)
{
item.Arrange(new Rect(per_width, (offset_y + RowSpace), per_width, item.DesiredSize.Height));
testList.Add(new Test { ValueX = per_width, TotalColumn = item.DesiredSize.Height });
}
else if (i == 2)
{
item.Arrange(new Rect(per_width * 2, (offset_y + RowSpace), per_width, item.DesiredSize.Height));
testList.Add(new Test { ValueX = per_width * 2, TotalColumn = item.DesiredSize.Height });
}
else
{
double minC = 10000;
foreach (var m in testList)
{
minC = Math.Min(minC, m.TotalColumn);
}
Test test = new Test() { TotalColumn = minC};
testList.ForEach(f =>
{
if(test.TotalColumn == f.TotalColumn)
{
test.ValueX = f.ValueX;
}
});
item.Arrange(new Rect(test.ValueX, test.TotalColumn, per_width, item.DesiredSize.Height));
testList.ForEach( f => {
if(f.ValueX == test.ValueX)
{
f.TotalColumn += item.DesiredSize.Height;
}
});
}
}
return base.ArrangeOverride(finalSize);
}
}
class Test
{
public double ValueX { get; set; } // X坐标
public double TotalColumn { get; set; } // 列总高度
}
}
XAML:
<Window x:Class="XH.LayoutLesson.TestWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:XH.LayoutLesson"
mc:Ignorable="d" FontSize="50"
Title="TestWindow" Height="450" Width="800">
<Grid>
<local:XHPanel ColumnSpace="2" RowSpace="2">
<Border Background="Gray">
<TextBlock
Text="B1B1BB11BB1B1B1111111111111111111111B1B11B11BB1B1BB11BB1B1B1B1B11B11B"
FontSize="20" TextWrapping="Wrap"/>
</Border>
<Button Content="B1" Height="40"/>
<Button Content="B2" Height="90"/>
<Button Content="B3" Height="90"/>
<Button Content="B4" Height="90"/>
</local:XHPanel>
</Grid>
</Window>
需要完整代码可以在本合集置顶博客看我的代码路径,可以进行学习。