How do you vertically align the UICollectionViewCe

2019-04-26 12:57发布

I have cells of varying height on a horizontally scrolling UICollectionView that appears to evenly distribute the cells vertically leaving empty space in between the cells and I would like to top align them and have the variable empty space at the bottom of each column.

3条回答
forever°为你锁心
2楼-- · 2019-04-26 13:35

I ported this to Xamarin/MonoTouch for my project and thought it could be useful

public class TopAlignedCollectionViewFlowLayout : UICollectionViewFlowLayout
{
    const int VerticalSpacing = 10;

    public override UICollectionViewLayoutAttributes[] LayoutAttributesForElementsInRect(RectangleF rect)
    {
        var attributesToReturn = base.LayoutAttributesForElementsInRect(rect);
        foreach (UICollectionViewLayoutAttributes attributes in attributesToReturn)
        {
            if (attributes.RepresentedElementKind == null)
            {
                var indexPath = attributes.IndexPath;
                attributes.Frame = this.LayoutAttributesForItem(indexPath).Frame;
            }
        }
        return attributesToReturn;
    }

    public override UICollectionViewLayoutAttributes LayoutAttributesForItem(NSIndexPath indexPath)
    {
        var currentItemAttributes = base.LayoutAttributesForItem(indexPath);
        UIEdgeInsets sectionInset = ((UICollectionViewFlowLayout) this.CollectionView.CollectionViewLayout).SectionInset;

        if (indexPath.Item == 0)
        {
            var frame1 = currentItemAttributes.Frame;
            frame1.Y = sectionInset.Top;
            currentItemAttributes.Frame = frame1;

            return currentItemAttributes;
        }

        var previousIndexPath = NSIndexPath.FromItemSection(indexPath.Item - 1, indexPath.Section);
        var previousFrame = this.LayoutAttributesForItem(previousIndexPath).Frame;
        var previousFrameRightPoint = previousFrame.Y + previousFrame.Size.Height + VerticalSpacing;
        var currentFrame = currentItemAttributes.Frame;
        var strecthedCurrentFrame = new RectangleF(currentFrame.X, 0, currentFrame.Size.Width, this.CollectionView.Frame.Size.Height);
        if (!previousFrame.IntersectsWith(strecthedCurrentFrame))
        {
            var frame = currentItemAttributes.Frame;
            frame.Y = frame.Y = sectionInset.Top;
            currentItemAttributes.Frame = frame;
            return currentItemAttributes;
        }
        RectangleF frame2 = currentItemAttributes.Frame;
        frame2.Y = previousFrameRightPoint;
        currentItemAttributes.Frame = frame2;
        return currentItemAttributes;
    }

}
查看更多
Viruses.
3楼-- · 2019-04-26 13:36

I imagine you are using a UICollectionViewFlowLayout to layout your cells. I don't think you can do this with a flow layout. You probably have to write a custom subclass of UICollectionViewLayout to align the top edges of each cell.

This is not a very pretty solution, but what about forcing all of your cells to be the same size and setting up the constrains in your cell to align the content to the top? This could simulate the look you are going for without having to subclass UICollectionViewLayout.

查看更多
趁早两清
4楼-- · 2019-04-26 13:43

I extended my UICollectionViewFlowLayout provided to my UICollectionView. The following overriding worked for me.

#import "TopAlignedCollectionViewFlowLayout.h"

const NSInteger kVerticalSpacing = 10;

@implementation TopAlignedCollectionViewFlowLayout

- (NSArray *)layoutAttributesForElementsInRect:(CGRect)rect
{
    NSArray* attributesToReturn = [super layoutAttributesForElementsInRect:rect];
    for (UICollectionViewLayoutAttributes* attributes in attributesToReturn) {
        if (nil == attributes.representedElementKind) {
            NSIndexPath* indexPath = attributes.indexPath;
            attributes.frame = [self layoutAttributesForItemAtIndexPath:indexPath].frame;
        }
    }
    return attributesToReturn;
}

- (UICollectionViewLayoutAttributes *)layoutAttributesForItemAtIndexPath:(NSIndexPath *)indexPath
{
    UICollectionViewLayoutAttributes* currentItemAttributes =
    [super layoutAttributesForItemAtIndexPath:indexPath];
    UIEdgeInsets sectionInset = [(UICollectionViewFlowLayout *)self.collectionView.collectionViewLayout sectionInset];
    if (indexPath.item == 0) { 
        CGRect frame = currentItemAttributes.frame;
        frame.origin.y = sectionInset.top;
        currentItemAttributes.frame = frame;

        return currentItemAttributes;
    }
    NSIndexPath* previousIndexPath = [NSIndexPath indexPathForItem:indexPath.item-1 inSection:indexPath.section];
    CGRect previousFrame = [self layoutAttributesForItemAtIndexPath:previousIndexPath].frame;
    CGFloat previousFrameRightPoint = previousFrame.origin.y + previousFrame.size.height + kVerticalSpacing;
    CGRect currentFrame = currentItemAttributes.frame;
    CGRect strecthedCurrentFrame = CGRectMake(currentFrame.origin.x,
                                              0,
                                              currentFrame.size.width,
                                              self.collectionView.frame.size.height
                                              );
    if (!CGRectIntersectsRect(previousFrame, strecthedCurrentFrame)) {
        CGRect frame = currentItemAttributes.frame;
        frame.origin.y = frame.origin.y = sectionInset.top;
        currentItemAttributes.frame = frame;
        return currentItemAttributes;
    }
    CGRect frame = currentItemAttributes.frame;
    frame.origin.y = previousFrameRightPoint;
    currentItemAttributes.frame = frame;
    return currentItemAttributes;
}

@end
查看更多
登录 后发表回答