2014-01-06 234 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:將新單元格插入到集合視圖中。

這不是微不足道的,因爲您必須移動所有索引路徑,更新該部分中的項目數以反映新添加的單元格等。如果您正在尋找簡單的東西,那麼瀑布示例很好。如果你想要一個更復雜/可配置的解決方案,那麼你必須擺脫你自己的自定義佈局。這就是我所做的。