UICollectionView布局自定义 [英] UICollectionView Layout customization

查看:108
本文介绍了UICollectionView布局自定义的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有很多部分和项目。当我触摸单元格中的按钮时,它会在1个单元格中创建包含4个项目的单元格(如扩展表格)再次触摸单元格消失。

I have a lot of section and items. When I touch button in cell it create cell with 4 items in 1 cell (like expanded table) touch again cell disappear.

我发现 WaterfallCollectionView 在那里我可以更改项目的高度。

I found WaterfallCollectionView and there I can change height of items.

达到此目的的最佳方法是什么?

What is the best way to achieve this???

结构如:

 -----      -----
|    +|    |    +|   and other rows
|     |    |     |
 -----      -----

当我触摸我的按钮时(+ )它应该是这样的:

When I touch my button (+) it should be like:

 -----      -----     -----
|    -|    |__|__|   |    +|
|     |    |  |  |   |     |
 -----      -----     -----

全新cell使用4个UIImageView在1个单元格内创建(如果1个单元格中有4个元素,如果更多则创建更多单元格)。如果1个元素创建此单元格,但图像将位于左上角。
单元格中的哪个位置应该是我的信息(如扩展表格)

A new cell create with 4 UIImageView's inside 1 cell ( if 4 elements in 1 cell, if more create more cell). If 1 element create this cell but image will be in the top left corner. Where in cells should be my info (like expanded table)

创建不同类型的单元格会更好吗?

Is it better to create different type of cells?

推荐答案

我尝试通过改变自己的大小来扩展 UICollectionViewCell 。点击单元格时弹出的新单元格不是新单元格,而是原始单元格的子视图。基本上它的工作原理如下:

I tried something out where a UICollectionViewCell is made to expand by changing its own size. The new 'cells' that pop out when you tap on a cell are not really new cells, but subviews of the original cell. Essentially it works something like this:


  1. 使用 UICollectionView UICollectionViewFlowLayout

  2. UICollectionView 的委托符合 UICollectionViewDelegateFlowLayout 并实现 -collectionView:layout:sizeForItemAtIndexPath:以识别唯一的单元格大小。

  3. UICollectionView 的委托实现 -collectionView:didSelectCellAtIndexPath:它调整单元格的大小以显示或隐藏看起来像新单元格的子视图。

  4. 表示单元格内容的自定义对象和自定义 UICollectionViewCell 子类用于使执行和跟踪扩展更容易。

  1. Use UICollectionView with a UICollectionViewFlowLayout.
  2. The UICollectionView's delegate conforms to UICollectionViewDelegateFlowLayout and implements -collectionView:layout:sizeForItemAtIndexPath: to recognize unique cell sizes.
  3. The UICollectionView's delegate implements -collectionView:didSelectCellAtIndexPath: where it adjusts the cell's size to reveal or hide the subviews that look like new cells.
  4. A custom object representing the cell's contents and a custom UICollectionViewCell subclass are used to make it easier to perform and keep track of expansion.

我创建了一个这里的示例项目,其中有一个单元格,可以展开以显示数字的divis ORS。它看起来像这样:

I created an example project here which has a cells that expand to show a number's divisors. It looks something like this:

该项目非常粗糙且没有注释,转换发生时没有动画,但是如果你发现这种方法很有趣并且无法遵循代码我可以稍微清理一下。

The project is pretty rough and uncommented, and the transition happens without animation, but if you find this approach interesting and cannot follow the code I can clean it up a bit.

这里是代码转储......

And here's the code dump...

CollectionViewController.h

#import <UIKit/UIKit.h>

@interface CollectionViewController : UIViewController

@end

CollectionViewController.m

#import "CollectionViewController.h"
#import "CellDataItem.h"
#import "CollectionViewCell.h"

@interface CollectionViewController () <UICollectionViewDataSource, UICollectionViewDelegateFlowLayout>

@property (strong, nonatomic) UICollectionView *collectionView;
@property (strong, nonatomic) NSMutableArray *cellData;

@end

NSString *const kCollectionViewCellIdentifier = @"Cell";

@implementation CollectionViewController

- (NSMutableArray *)cellData
{
    if (!_cellData) {
        NSInteger countValues = 20;
        _cellData = [[NSMutableArray alloc] initWithCapacity:countValues];
        for (NSInteger i = 0; i < countValues; i++) {
            CellDataItem *item = [[CellDataItem alloc] init];
            item.number = @(arc4random() % 100);
            [_cellData addObject:item];
        }
    }
    return _cellData;
}

- (void)viewDidLoad
{
    [super viewDidLoad];
    // Do any additional setup after loading the view.
    self.view.backgroundColor = [UIColor grayColor];

    UICollectionViewFlowLayout *layout = [[UICollectionViewFlowLayout alloc] init];
    layout.itemSize = [CollectionViewCell sizeWithDataItem:nil];
    layout.minimumInteritemSpacing = [CollectionViewCell margin];
    layout.minimumLineSpacing = layout.minimumInteritemSpacing;
    layout.scrollDirection = UICollectionViewScrollDirectionHorizontal;
    _collectionView = [[UICollectionView alloc] initWithFrame:CGRectZero
                                         collectionViewLayout:layout];
    _collectionView.backgroundColor = [UIColor darkGrayColor];
    _collectionView.dataSource = self;
    _collectionView.delegate = self;
    [self.view addSubview:_collectionView];

    [_collectionView registerClass:[CollectionViewCell class] forCellWithReuseIdentifier:kCollectionViewCellIdentifier];
}

- (void)viewDidLayoutSubviews
{
    [super viewDidLayoutSubviews];

    UICollectionViewFlowLayout *layout = (UICollectionViewFlowLayout *)self.collectionView.collectionViewLayout;
    self.collectionView.frame = CGRectMake(0.0f, 0.0f, self.view.bounds.size.width, layout.itemSize.height);
}

- (NSInteger)numberOfSectionsInCollectionView:(UICollectionView *)collectionView
{
    return 1;
}

- (NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section
{
    return self.cellData.count;
}

- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath
{
    CollectionViewCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:kCollectionViewCellIdentifier
                                                         forIndexPath:indexPath];
    cell.dataItem = [self.cellData objectAtIndex:indexPath.row];
    return cell;
}

- (CGSize)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout *)collectionViewLayout sizeForItemAtIndexPath:(NSIndexPath *)indexPath
{
    return [CollectionViewCell sizeWithDataItem:[self.cellData objectAtIndex:indexPath.row]];
}

- (void)collectionView:(UICollectionView *)collectionView didSelectItemAtIndexPath:(NSIndexPath *)indexPath
{
    CollectionViewCell *cell = (CollectionViewCell *)[collectionView cellForItemAtIndexPath:indexPath];
    [cell toggleExpansion];
    [collectionView reloadData];
}

@end

#import <Foundation/Foundation.h>

@interface CellDataItem : NSObject

@property (strong, nonatomic) NSNumber *number;
@property (nonatomic, readonly) NSArray *divisors;
@property (nonatomic, getter = isExpanded) BOOL expanded;

@end

CellDataItem.m

#import "CellDataItem.h"

@interface CellDataItem ()

@property (strong, nonatomic) NSArray *divisors;

@end

@implementation CellDataItem

+ (NSArray *)divisorsForNumber:(NSNumber *)number
{
    NSMutableArray *divisors = [NSMutableArray arrayWithObjects:@(1), number, nil];
    float root = pow(number.doubleValue, 0.5);
    if (root == roundf(root)) {
        [divisors addObject:[NSNumber numberWithInteger:(NSInteger)root]];
    }

    NSInteger maxDivisor = (NSInteger)root;
    for (NSInteger divisor = 2; divisor < maxDivisor; divisor++) {
        float quotient = number.floatValue / (float)divisor;
        if (quotient == roundf(quotient)) {
            [divisors addObject:[NSNumber numberWithInteger:divisor]];
            [divisors addObject:[NSNumber numberWithInteger:(NSInteger)quotient]];
        }
    }
    return [divisors sortedArrayUsingSelector:@selector(compare:)];
}

- (void)setNumber:(NSNumber *)number
{
    if (_number == number) {
        return;
    }
    _number = number;
    self.divisors = [self.class divisorsForNumber:_number];
}

@end

CollectionViewCell.h

#import <UIKit/UIKit.h>

@class CellDataItem;
@interface CollectionViewCell : UICollectionViewCell

+ (CGFloat)margin;
+ (CGSize)sizeWithDataItem:(CellDataItem *)dataItem;

@property (strong, nonatomic) CellDataItem *dataItem;

- (void)toggleExpansion;

@end

@interface ChildView : UIView

- (UILabel *)labelAtIndex:(NSInteger)index;
- (void)clearLabels;

@end

CollectionViewCell.m

#import "CollectionViewCell.h"
#import <QuartzCore/QuartzCore.h>
#import "CellDataItem.h"

@interface CollectionViewCell ()

@property (strong, nonatomic) NSMutableArray *childViews;
@property (strong, nonatomic) UILabel *numberLabel;

@end

NSInteger const kCollectionViewCellSplitCount = 4;
CGFloat const kCollectionViewCellMargin = 20.0f;
CGSize const kCollectionViewCellDefaultSize = {200.0f, 200.0f};

@implementation CollectionViewCell

+ (CGFloat)margin
{
    return kCollectionViewCellMargin;
}

+ (CGSize)sizeWithDataItem:(CellDataItem *)dataItem
{
    if (dataItem && dataItem.isExpanded) {
        CGSize size = kCollectionViewCellDefaultSize;
        NSInteger childViewsRequired = [self childViewsRequiredForDataItem:dataItem];
        size.width += childViewsRequired * ([self margin] + size.width);
        return size;
    } else {
        return kCollectionViewCellDefaultSize;
    }
}

+ (NSInteger)childViewsRequiredForDataItem:(CellDataItem *)dataItem
{
    return (NSInteger)ceilf((float)dataItem.divisors.count / (float)kCollectionViewCellSplitCount);
}

- (id)initWithFrame:(CGRect)frame
{
    self = [super initWithFrame:frame];
    if (self) {
        // Initialization code
        _numberLabel = [[UILabel alloc] init];
        _numberLabel.textAlignment = NSTextAlignmentCenter;
        _numberLabel.layer.borderColor = [UIColor blackColor].CGColor;
        _numberLabel.layer.borderWidth = 1.0f;
        _numberLabel.backgroundColor = [UIColor whiteColor];
        [self.contentView addSubview:_numberLabel];
    }
    return self;
}

- (void)setDataItem:(CellDataItem *)dataItem
{
    if (_dataItem == dataItem) {
        return;
    }

    _dataItem = dataItem;
    self.numberLabel.text = [NSString stringWithFormat:@"%i", dataItem.number.integerValue];

    if (!dataItem.expanded) {
        [self collapse];
    } else if (dataItem.expanded) {
        [self expand];
    }
}

- (void)collapse
{
    for (ChildView *view in self.childViews) {
        view.hidden = YES;
    }
}

- (void)expand
{
    NSInteger childViewsRequired = [self.class childViewsRequiredForDataItem:self.dataItem];
    while (self.childViews.count < childViewsRequired) {
        ChildView *childView = [[ChildView alloc] init];
        [self.childViews addObject:childView];
        [self.contentView addSubview:childView];
    }

    NSInteger index = 0;
    for (ChildView *view in self.childViews) {
        view.hidden = !(index < childViewsRequired);
        if (!view.hidden) {
            [view clearLabels];
        }
        index++;
    }

    for (NSInteger i = 0; i < self.dataItem.divisors.count; i++) {
        NSInteger labelsPerChild = 4;
        NSInteger childIndex = i / labelsPerChild;
        NSInteger labelIndex = i % labelsPerChild;
        [[[self.childViews objectAtIndex:childIndex] labelAtIndex:labelIndex] setText:[NSString stringWithFormat:@"%i", [[self.dataItem.divisors objectAtIndex:i] integerValue]]];
    }
}

- (void)layoutSubviews
{
    [super layoutSubviews];

    CGFloat const unitWidth = kCollectionViewCellDefaultSize.width;
    CGFloat const unitHeight = kCollectionViewCellDefaultSize.height;
    CGFloat const margin = [self.class margin];
    self.numberLabel.frame = CGRectMake(0.0f, 0.0f, unitWidth, unitHeight);

    for (NSInteger i = 0; i < self.childViews.count; i++) {
        ChildView *view = [self.childViews objectAtIndex:i];
        view.frame = CGRectMake((i + 1) * (margin + unitWidth), 0.0f, unitWidth, unitHeight);
    }
}

- (NSMutableArray *)childViews
{
    if (!_childViews) {
        _childViews = [[NSMutableArray alloc] init];
    }
    return _childViews;
}

- (void)toggleExpansion
{
    self.dataItem.expanded = !self.dataItem.isExpanded;
    if (self.dataItem.isExpanded) {
        [self expand];
    } else {
        [self collapse];
    }
}

@end

@interface ChildView ()

@property (strong, nonatomic) NSMutableArray *labels;

@end

@implementation ChildView

- (id)init
{
    if ((self = [super init])) {
        self.backgroundColor = [UIColor lightGrayColor];
    }
    return self;
}

- (UILabel *)labelAtIndex:(NSInteger)index
{
    if (!self.labels) {
        self.labels = [NSMutableArray array];
    }

    while (self.labels.count <= index) {
        UILabel *label = [[UILabel alloc] init];
        label.textAlignment = NSTextAlignmentCenter;
        label.layer.borderColor = [UIColor blackColor].CGColor;
        label.layer.borderWidth = 1.0f;
        [self.labels addObject:label];
        [self addSubview:label];
    }

    return [self.labels objectAtIndex:index];
}

- (void)clearLabels
{
    for (UILabel *label in self.labels) {
        label.text = nil;
    }
}

- (void)layoutSubviews
{
    [super layoutSubviews];

    CGFloat labelWidth = self.bounds.size.width * 0.5f;
    CGFloat labelHeight = self.bounds.size.height * 0.5f;
    for (NSInteger i = 0; i < self.labels.count; i++) {
        UILabel *label = [self.labels objectAtIndex:i];
        NSInteger x = i % 2;
        NSInteger y = i / 2;
        label.frame = CGRectMake(x * labelWidth, y * labelHeight, labelWidth, labelHeight);
    }
}

@end

这篇关于UICollectionView布局自定义的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆