繁体   English   中英

iOS UICollectionView特殊单元格顺序

[英]iOS UICollectionView special cell order

我有一个简单的集合视图,包含5个元素。 单元格的默认顺序如下所示: 在此输入图像描述

我想知道是否可以更改单元格的填充\\顺序以获得如下结果:

在此输入图像描述

选项1 :(清洁选项)

你应该有2个部分

  • 第1节有3个细胞

  • 第2节有2个细胞

然后,您可以使用要调整的部分的 collection​View(_:​layout:​inset​For​Section​At:​) 调整插入 (在这种情况下,第2节)

如果未实现此方法,则流布局将使用其“插入”属性部分中的值来设置边距。 您对此方法的实现可以返回一组固定的边距大小,或为每个部分返回不同的边距大小。

节插入是仅应用于节中的项的边距。 它们表示标题视图与第一行项目之间以及最后一行项目与页脚视图之间的距离。 它们还表明它们在单行项目的两侧间隔。 它们不会影响页眉或页脚本身的大小。

选项2 :(意大利面条选项,但很高兴知道)

为第2部分项创建自定义子类,您可以在其中自定义UICollectionViewCell contentView子视图的实际内容的插入。

然后在第2部分中,返回您的自定义单元格。

为此,您可能需要编写自定义布局。 有关详细信息,请查看“ 集合视图编程指南”

默认(流)布局将始终以此模式放置单元格:

您可以通过将节数从1更改为2来在UICollectionView中实现此类格式。

然后,您可以相应地为不同的部分定义自定义UICollectionViewFlowLayout。

解决方案:我已经创建了一个名为“CenteringCollectionView”的UICollectionView子类,并对我创建的部分进行了一些计算!

.h文件:

#import <UIKit/UIKit.h>

@class CenteringCollectionView;
@protocol CenteringCollectionViewDelegate <NSObject>

-(void)collectionView:(CenteringCollectionView *)collectionView didDequeueReusableCell:(UICollectionViewCell *)cell indexPath:(NSIndexPath *)indexPath;

@end

@interface CenteringCollectionView : UICollectionView

@property (nonatomic, strong) NSMutableArray *dataSourceArr;
@property (nonatomic, weak) id<CenteringCollectionViewDelegate> delegateCenteringCollection;

@end

.m文件:

#import "CenteringCollectionView.h"

@interface CenteringCollectionView () <UICollectionViewDelegate, UICollectionViewDataSource>

@property (nonatomic, assign) IBInspectable long elementsInRow;
@property (nonatomic, assign) long elementsInRowInitialValue;
@property (nonatomic) IBInspectable NSString *cellIdentifier;
@property (nonatomic) IBInspectable CGFloat cellRelativeSize; // 0..1
@property (nonatomic, assign) long numOfSections;
@property (nonatomic, assign) IBInspectable BOOL autoResize; // *** If we want auto resize - we need to set the height constraint of the collection view in size of 1 line only even if we have more than 1 line (section).
@property (nonatomic, assign)IBInspectable CGFloat heightMiddleSpacing;
@property (nonatomic, assign) long cellSize;
//@property (nonatomic, assign) CGFloat verticalTopInset;
@property (nonatomic, assign) CGFloat initialHeightConstraint;
@property (nonatomic, weak) NSLayoutConstraint *selfHeightConstraint;
@property (nonatomic, assign) CGFloat cellSpacing;
@property (nonatomic, assign) BOOL shouldReloadUIElements;

// UI IBInspectable

@property (nonatomic, weak) IBInspectable UIColor *runtimeColor;

@end

static long const maxElementsInRowDefault = 3;

@implementation CenteringCollectionView

-(instancetype)initWithCoder:(NSCoder *)aDecoder
{
    if (self = [super initWithCoder:aDecoder])
    {
        self.elementsInRow = maxElementsInRowDefault; // will get the default value if not stored value in storyboard
        self.elementsInRowInitialValue = self.elementsInRow;
        self.cellRelativeSize = 0.5;
        self.initialHeightConstraint = -1;
    }
    return self;
}

-(void)setDataSourceCount:(long)dataSourceCount
{
    if (dataSourceCount == _dataSourceCount)
    {
        return;
    }

    _dataSourceCount = dataSourceCount;
    self.shouldReloadUIElements = YES;
    self.elementsInRow = MIN(self.elementsInRowInitialValue, self.dataSourceCount);
    self.numOfSections = ceil((CGFloat)self.dataSourceCount / (CGFloat)self.elementsInRow);

    CGFloat selfHeight = [self handleAutoResizeAndReturnTheNewHeightIfNeeded];
    CGFloat selfWidth = CGRectGetWidth(self.frame);

    CGFloat cellWidth = (selfWidth / self.elementsInRow) * self.cellRelativeSize;
    CGFloat cellHeight = (selfHeight / self.numOfSections) * self.cellRelativeSize;

    self.cellSize = MIN(cellWidth, cellHeight);

    dispatch_async(dispatch_get_main_queue(), ^{

        [self setCollectionView];
        [self reloadData];
    });
}

-(void)awakeFromNib
{
    [super awakeFromNib];
    self.elementsInRowInitialValue = self.elementsInRow;
    [self handleUIelementsIBInspectable];
}

-(void)handleUIelementsIBInspectable
{
    if (self.runtimeColor)
    {
        [self setBackgroundColor:self.runtimeColor];
    }
}

-(CGFloat)handleAutoResizeAndReturnTheNewHeightIfNeeded
{
    if (self.autoResize)
    {
        for (NSLayoutConstraint *constraint in [self constraints])
        {
            if (constraint.firstAttribute == NSLayoutAttributeHeight)
            {
                if (self.initialHeightConstraint == -1) // not set yet
                {
                    self.initialHeightConstraint = constraint.constant;
                }

                if (!self.selfHeightConstraint)
                {
                    self.selfHeightConstraint = constraint;
                }


                CGFloat newHeight = self.initialHeightConstraint * self.numOfSections;
                constraint.constant = newHeight;

                if (self.bounds.size.height != newHeight)
                {
                    CGRect frame = self.bounds;
                    frame.size.height = newHeight;
                    [self setBounds:frame];
                }

                dispatch_async(dispatch_get_main_queue(), ^{
                    [self.superview layoutIfNeeded];
                    [self layoutIfNeeded];
                });

                return newHeight;
            }
        }
    }

    return CGRectGetHeight(self.frame);
}

-(long)numOfSpacesInRow
{
    return self.elementsInRow + 1;
}

-(long)numOfSpacesBetweenLines
{
    return self.numOfSections + 1;
}

-(void)setCellRelativeSize:(CGFloat)cellRelativeSize
{
    _cellRelativeSize = MAX(0, MIN(cellRelativeSize, 1));
}

-(void)setCollectionView
{
    [self reloadData];
    UICollectionViewFlowLayout *layout = [[UICollectionViewFlowLayout alloc] init];
    CGFloat horizontalCellSpacing = ((CGRectGetWidth(self.frame) - (self.cellSize * self.elementsInRow)) / self.numOfSpacesInRow);
    CGFloat verticalCellSpacing = (CGRectGetHeight(self.frame) - (self.numOfSections * self.cellSize)) / self.numOfSpacesBetweenLines;

    self.cellSpacing = MAX(MIN(horizontalCellSpacing, verticalCellSpacing), 0);
    [layout setMinimumInteritemSpacing:self.cellSpacing];
    [layout setMinimumLineSpacing:self.cellSpacing];
    [layout setScrollDirection:UICollectionViewScrollDirectionVertical];
    [self setCollectionViewLayout:layout];

    self.showsVerticalScrollIndicator = NO;
    self.showsHorizontalScrollIndicator = NO;
    self.scrollEnabled = NO;

    if (!self.delegate)
    {
        self.delegate = self;
        self.dataSource = self;
    }
}

- (CGSize)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout *)collectionViewLayout sizeForItemAtIndexPath:(NSIndexPath *)indexPath
{
    return CGSizeMake(self.cellSize, self.cellSize);
}

- (NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section
{
    BOOL isLastSection = (section == self.numOfSections - 1);
    if (isLastSection == NO)
    {
        return self.elementsInRow;
    }
    else
    {
        long numOfLeftItemsInLastRow = self.dataSourceCount % self.elementsInRow;
        if (numOfLeftItemsInLastRow == 0)
        {
            return self.elementsInRow;
        }
        else
        {
            return  numOfLeftItemsInLastRow;
        }
    }
}

- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath
{
    UICollectionViewCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:self.cellIdentifier forIndexPath:indexPath];
    if ([self.delegateCenteringCollection respondsToSelector:@selector(collectionView:didDequeueReusableCell:indexPath:)])
    {
        [self.delegateCenteringCollection collectionView:self didDequeueReusableCell:cell indexPath:[self indexPathWithoutSectionsFrom:indexPath]];
    }
    return cell;
}

-(void)collectionView:(UICollectionView *)collectionView didSelectItemAtIndexPath:(NSIndexPath *)indexPath
{
    if ([self.delegateCenteringCollection respondsToSelector:@selector(collectionView:didSelectItemAtIndexPath:cell:)])
    {
        UICollectionViewCell *selectedCell = [collectionView cellForItemAtIndexPath:indexPath];
        [self.delegateCenteringCollection collectionView:self didSelectItemAtIndexPath:[self indexPathWithoutSectionsFrom:indexPath] cell:selectedCell];
    }
}

-(NSIndexPath *)indexPathWithoutSectionsFrom:(NSIndexPath *)indexPath
{
    long sectionNum = indexPath.section;
    long rowNum = sectionNum * self.elementsInRow + indexPath.row;
    NSIndexPath *newIndexPath = [NSIndexPath indexPathForRow:rowNum inSection:0];
    return newIndexPath;
}

-(NSInteger)numberOfSectionsInCollectionView:(UICollectionView *)collectionView
{
    return self.numOfSections;
}

-(void)collectionView:(UICollectionView *)collectionView willDisplayCell:(UICollectionViewCell *)cell forItemAtIndexPath:(NSIndexPath *)indexPath
{
    dispatch_async(dispatch_get_main_queue(), ^{
        if (self.shouldReloadUIElements == NO)
        {
            return;
        }

        if (self.autoResize && self.selfHeightConstraint)
        {
            BOOL isTheFirstCellInTheLastSection = (indexPath.section == self.numOfSections - 1) && indexPath.row == 0;
            if (isTheFirstCellInTheLastSection)
            {
                CGFloat newHeight = CGRectGetMaxY(cell.frame) + self.cellSpacing;

                self.selfHeightConstraint.constant = newHeight;

                if (self.bounds.size.height != newHeight)
                {
                    CGRect frame = self.bounds;
                    frame.size.height = newHeight;
                    [self setBounds:frame];
                }

                [self.superview layoutIfNeeded];
                [self layoutIfNeeded];
            }
        }
    });
}

- (UIEdgeInsets)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout *)collectionViewLayout insetForSectionAtIndex:(NSInteger)section
{
    if (self.shouldReloadUIElements == NO)
    {
        return collectionView.contentInset;
    }

    NSInteger cellsCount = [collectionView numberOfItemsInSection:section];
    CGFloat horizontalInset = (collectionView.bounds.size.width - (cellsCount * self.cellSize) - ((cellsCount - 1) * self.cellSpacing)) * 0.5;
    horizontalInset = MAX(horizontalInset, 0.0);

    BOOL isLastSection = (section == self.numOfSections - 1);

    CGFloat verticalTopInset = self.cellSpacing;

    CGFloat verticalBottomInset = verticalTopInset;

    if (section == 0 && isLastSection == NO)
    {
        if (self.heightMiddleSpacing)
        {
            verticalBottomInset += self.heightMiddleSpacing;
        }
        verticalBottomInset /= 2;
    }

    if (section > 0)
    {
        if (self.heightMiddleSpacing)
        {
            verticalTopInset += self.heightMiddleSpacing;
        }
        verticalTopInset /= 2;

        if (isLastSection == NO)
        {
            if (self.heightMiddleSpacing)
            {
                verticalBottomInset += self.heightMiddleSpacing;
            }
            verticalBottomInset /= 2;
        }
    }

    return UIEdgeInsetsMake(verticalTopInset, horizontalInset, verticalBottomInset, horizontalInset);
}

@end

为了使它工作,我们在父视图中需要做的就是:

self.collectionView.delegateCenteringCollection = self;
self.collectionView.dataSourceCount = 5; // Or whatever number we want!

在故事板中:我们需要创建此类的collectionView并设置“行中的元素”值,同时将“单元格标识符”和“单元格相对大小”设置为0到1(“单元格相对大小”值:将根据collectionView宽度和高度计算单元格大小和填充。 最后 - 如果您希望集合视图根据行数自动调整其自身的高度约束(如果存在),则将“autoResize”设置为“true”。 如果我们将“autoResize”设置为true,我们设置为collectionView的高度约束将确定单个行的高度。 如果我们的collectionView应该增长到例如3行,它将使我们的collectionview高度约束乘以3。

它就像一个魅力!

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM