UICollectionView布局自定义 [英] UICollectionView Layout customization
问题描述
我有很多部分和项目。当我触摸单元格中的按钮时,它会在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:
- 使用
UICollectionView
UICollectionViewFlowLayout
。 -
UICollectionView
的委托符合UICollectionViewDelegateFlowLayout
并实现-collectionView:layout:sizeForItemAtIndexPath:
以识别唯一的单元格大小。 -
UICollectionView
的委托实现-collectionView:didSelectCellAtIndexPath:
它调整单元格的大小以显示或隐藏看起来像新单元格的子视图。 - 表示单元格内容的自定义对象和自定义
UICollectionViewCell
子类用于使执行和跟踪扩展更容易。
- Use
UICollectionView
with aUICollectionViewFlowLayout
. - The
UICollectionView
's delegate conforms toUICollectionViewDelegateFlowLayout
and implements-collectionView:layout:sizeForItemAtIndexPath:
to recognize unique cell sizes. - 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. - 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屋!