我試了一下,UICollectionViewCell
是通過改變自己的大小來擴大。當你點擊一個單元格時彈出的新「單元格」不是真正的新單元格,而是原始單元格的子視圖。本質上,它的工作原理是這樣的:
- 使用
UICollectionView
用UICollectionViewFlowLayout
。
UICollectionView
的代表符合UICollectionViewDelegateFlowLayout
並實現-collectionView:layout:sizeForItemAtIndexPath:
以識別唯一的單元格大小。
UICollectionView
的代表實現了-collectionView:didSelectCellAtIndexPath:
,它調整單元格的大小以顯示或隱藏看起來像新單元格的子視圖。
- 表示單元格內容的自定義對象和自定義子類用於使其更容易執行並跟蹤擴展。
我創建了一個example project 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
,你已經證明,也不需要不同的細胞,然後你可以繼續用[拓展表]如果電池是一樣簡單(https://www.cocoacontrols.com/controls/jkexpandtableview) – cjd
@cjd我需要不同的單元格。 – user2545330
我希望[collapseclick](https://www.cocoacontrols.com/controls/collapseclick)能幫助你。 – cjd