2023-07-19 21:01:19 +08:00

125 lines
3.5 KiB
C#

using CoreGraphics;
using Foundation;
using UIKit;
namespace Blahblah.FlowerApp.Platforms.iOS.Controls;
public class FlowLayout : UICollectionViewFlowLayout
{
public CalculateCellHeightHandler? CalculateCellHeight { get; set; }
private readonly List<UICollectionViewLayoutAttributes> layoutAttributes = new();
private CGSize oldBounds;
private bool dirty;
private int cols;
private nfloat[]? yArray;
private nfloat maxHeight;
public FlowLayout(int cols = 2)
{
SetCols(cols);
}
public void SetCols(int cols)
{
if (this.cols != cols)
{
dirty = true;
this.cols = cols;
}
}
public void Invalidate()
{
dirty = true;
}
private void Clean()
{
dirty = false;
yArray = new nfloat[cols];
maxHeight = 0f;
layoutAttributes.Clear();
}
public override CGSize CollectionViewContentSize => new(CollectionView.Bounds.Width, maxHeight);
public override bool ShouldInvalidateLayoutForBoundsChange(CGRect newBounds)
{
return newBounds.Width != CollectionView.Bounds.Width;
}
public override void PrepareLayout()
{
base.PrepareLayout();
var bounds = CollectionView.Bounds.Size;
if (dirty || oldBounds.Width != bounds.Width)
{
oldBounds = bounds;
Clean();
}
var sectionLeft = SectionInset.Left;
var sectionTop = SectionInset.Top;
var minSpacing = MinimumInteritemSpacing;
var itemWidth = (bounds.Width - sectionLeft - SectionInset.Right - minSpacing * (cols - 1)) / cols;
var itemCount = CollectionView.NumberOfItemsInSection(0);
for (nint i = layoutAttributes.Count; i < itemCount; i++)
{
var indexPath = NSIndexPath.FromItemSection(i, 0);
var attr = UICollectionViewLayoutAttributes.CreateForCell(indexPath);
var itemHeight = CalculateCellHeight?.Invoke(indexPath, itemWidth) ?? 20;
nfloat value = nfloat.MaxValue;
int minHeightIndex = 0;
if (yArray?.Length >= cols)
{
for (var n = 0; n < cols; n++)
{
if (yArray[n] < value)
{
value = yArray[n];
minHeightIndex = n;
}
}
}
var itemY = value;
if (itemY < sectionTop)
{
itemY = sectionTop;
}
if (i >= cols)
{
itemY += minSpacing;
}
var itemX = sectionLeft + (itemWidth + minSpacing) * minHeightIndex;
attr.Frame = new CGRect(itemX, itemY, itemWidth, itemHeight);
layoutAttributes.Add(attr);
if (yArray != null)
{
yArray[minHeightIndex] = itemY + itemHeight;
}
}
nfloat y = 0f;
if (yArray != null)
{
for (var i = 0; i < yArray.Length; i++)
{
if (yArray[i] > y)
{
y = yArray[i];
}
}
}
maxHeight = y + SectionInset.Bottom;
}
public override UICollectionViewLayoutAttributes[] LayoutAttributesForElementsInRect(CGRect rect)
{
return layoutAttributes.Where(a => a.Frame.IntersectsWith(rect)).ToArray();
}
}
public delegate nfloat CalculateCellHeightHandler(NSIndexPath indexPath, nfloat itemWidth);