125 lines
3.5 KiB
C#
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); |