2014-01-06 229 views
0

我有很多部分和项目。当我触摸单元格中的按钮时,它会在1个单元格中创建具有4个项目的单元格(如扩展表格)再次触摸单元格消失。我发现了WaterfallCollectionView,我可以改变物品的高度。UICollectionView布局定制

什么是实现这一目标的最佳方法?

结构,如:

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

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

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

一个新的细胞与4点的UIImageView的创建1个单元格内(如果在1 4种元素细胞,如果更多创造更多的细胞)。如果1个元素创建此单元格,但图像将位于左上角。 在单元格中的位置应该是我的信息(如展开表格)

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

+0

,你已经证明,也不需要不同的细胞,然后你可以继续用[拓展表]如果电池是一样简单(https://www.cocoacontrols.com/controls/jkexpandtableview) – cjd

+0

@cjd我需要不同的单元格。 – user2545330

+0

我希望[collapseclick](https://www.cocoacontrols.com/controls/collapseclick)能帮助你。 – cjd

回答

2

我试了一下,UICollectionViewCell是通过改变自己的大小来扩大。当你点击一个单元格时弹出的新“单元格”不是真正的新单元格,而是原始单元格的子视图。本质上,它的工作原理是这样的:

  1. 使用UICollectionViewUICollectionViewFlowLayout
  2. UICollectionView的代表符合UICollectionViewDelegateFlowLayout并实现-collectionView:layout:sizeForItemAtIndexPath:以识别唯一的单元格大小。
  3. UICollectionView的代表实现了-collectionView:didSelectCellAtIndexPath:,它调整单元格的大小以显示或隐藏看起来像新单元格的子视图。
  4. 表示单元格内容的自定义对象和自定义子类用于使其更容易执行并跟踪扩展。

我创建了一个example project here,它有一个单元展开以显示数字的除数。它看起来是这样的:

enter image description here

该项目是相当粗糙和取消注释,以及过渡必有动画,但如果你发现这个方法有趣而不能按照我的代码可以清理一下。

这里是代码转储...

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 
0

如果您想要展开的单元格,则必须通过在集合视图上调用insertItemsAtIndexPaths:将新单元格插入到集合视图中。

这不是微不足道的,因为您必须移动所有索引路径,更新该部分中的项目数以反映新添加的单元格等。如果您正在寻找简单的东西,那么瀑布示例很好。如果你想要一个更复杂/可配置的解决方案,那么你必须摆脱你自己的自定义布局。这就是我所做的。