从故事板检索自定义原型单元格高度?
使用“dynamic原型”在故事板上指定UITableView
内容时,可以将“行高”属性设置为“自定义”。
在实例化单元格时,不会考虑此自定义行高。 这是有道理的,因为我使用的原型单元格是由我的应用程序代码在实例化单元时决定的。 实例化所有的单元格时,计算布局会带来性能损失,所以我明白为什么不能这样做。
那么问题,我可以以某种方式检索给定单元格重用标识符的高度,例如
[myTableView heightForCellWithReuseIdentifier:@"MyCellPrototype"];
或沿着这条线? 还是我必须在我的应用程序代码中重复明确的行高,维护负担如下?
解决了,在@TimothyMoose的帮助下:
高度存储在单元本身,这意味着获得高度的唯一方法是实例化原型。 这样做的一个方法是在正常的单元callback方法之外预先出队。 这是我的小POC,这是工作:
#import "ViewController.h" @interface ViewController () { NSDictionary* heights; } @end @implementation ViewController - (NSString*) _reusableIdentifierForIndexPath:(NSIndexPath *)indexPath { return [NSString stringWithFormat:@"C%d", indexPath.row]; } - (CGFloat) tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath { if(!heights) { NSMutableDictionary* hts = [NSMutableDictionary dictionary]; for(NSString* reusableIdentifier in [NSArray arrayWithObjects:@"C0", @"C1", @"C2", nil]) { CGFloat height = [[tableView dequeueReusableCellWithIdentifier:reusableIdentifier] bounds].size.height; hts[reusableIdentifier] = [NSNumber numberWithFloat:height]; } heights = [hts copy]; } NSString* prototype = [self _reusableIdentifierForIndexPath:indexPath]; return [heights[prototype] floatValue]; } - (NSInteger) tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section { return 3; } - (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView { return 1; } - (UITableViewCell*) tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { NSString* prototype = [self _reusableIdentifierForIndexPath:indexPath]; UITableViewCell* cell = [tableView dequeueReusableCellWithIdentifier:prototype]; return cell; } @end
对于静态(非数据驱动)高度,您可以将该单元出队一次并存储高度:
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath { static NSNumber *height; if (!height) { UITableViewCell *cell = [self.tableView dequeueReusableCellWithIdentifier:@"MyCustomCell"]; height = @(cell.bounds.size.height); } return [height floatValue]; }
对于dynamic(数据驱动)高度,可以在视图控制器中存储原型单元格,并向单元格的类中添加一个计算高度的方法,同时考虑原型实例的默认内容,如子视图布局,字体,等等。:
- (MyCustomCell *)prototypeCell { if (!_prototypeCell) { _prototypeCell = [self.tableView dequeueReusableCellWithIdentifier:@"MyCustomCell"]; } return _prototypeCell; } - (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath { // Data for the cell, eg text for label id myData = [self myDataForIndexPath:indexPath]; // Prototype knows how to calculate its height for the given data return [self.prototypeCell myHeightForData:myData]; }
当然,如果你使用自定义高度,你可能有多个单元格原型,所以你可以将它们存储在字典或其他东西。
据我所知,表视图不会尝试重用原型,大概是因为它已经在cellForRowAtIndexPath:
外出列了。 这种方法对我们来说工作得非常好,因为它允许devise人员修改故事板中的单元格布局,而不需要任何代码更改。
编辑:澄清示例代码的含义,并为静态高度的情况添加了一个示例。
我前段时间为UITableView创build了一个类别,可能对此有所帮助。 它存储“原型”细胞使用原型的重复使用的相关对象 ,并提供了一个方便的方法来获取故事板中分配的行的高度。 原型在释放表视图时被释放。
的UITableView + PrototypeCells.h
#import <UIKit/UIKit.h> @interface UITableView (PrototypeCells) - (CGFloat)heightForRowWithReuseIdentifier:(NSString*)reuseIdentifier; - (UITableViewCell*)prototypeCellWithReuseIdentifier:(NSString*)reuseIdentifier; @end
的UITableView + PrototypeCells.m
#import "UITableView+PrototypeCells.h" #import <objc/runtime.h> static char const * const key = "prototypeCells"; @implementation UITableView (PrototypeCells) - (void)setPrototypeCells:(NSMutableDictionary *)prototypeCells { objc_setAssociatedObject(self, key, prototypeCells, OBJC_ASSOCIATION_RETAIN_NONATOMIC); } - (NSMutableDictionary *)prototypeCells { return objc_getAssociatedObject(self, key); } - (CGFloat)heightForRowWithReuseIdentifier:(NSString*)reuseIdentifier { return [self prototypeCellWithReuseIdentifier:reuseIdentifier].frame.size.height; } - (UITableViewCell*)prototypeCellWithReuseIdentifier:(NSString*)reuseIdentifier { if (self.prototypeCells == nil) { self.prototypeCells = [[NSMutableDictionary alloc] init]; } UITableViewCell* cell = self.prototypeCells[reuseIdentifier]; if (cell == nil) { cell = [self dequeueReusableCellWithIdentifier:reuseIdentifier]; self.prototypeCells[reuseIdentifier] = cell; } return cell; } @end
用法
获得故事板中设置的静态高度就像这样简单:
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath { return [tableView heightForRowWithReuseIdentifier:@"cellIdentifier"]; }
假设一个多节表视图:
enum { kFirstSection = 0, kSecondSection }; static NSString* const kFirstSectionRowId = @"section1Id"; static NSString* const kSecondSectionRowId = @"section2Id"; - (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath { CGFloat height = tableView.rowHeight; // Default UITableView row height switch (indexPath.section) { case kFirstSection: height = [tableView heightForRowWithReuseIdentifier:kFirstSectionRowId]; break; case kSecondSection: height = [tableView heightForRowWithReuseIdentifier:kSecondSectionRowId]; } return height; }
最后如果行高是dynamic的:
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath { id thisRowData = self.allData[indexPath.row]; // Obtain the data for this row // Obtain the prototype cell MyTableViewCell* cell = (MyTableViewCell*)[self prototypeCellWithReuseIdentifier:@"cellIdentifier"]; // Ask the prototype cell for its own height when showing the specified data return [cell heightForData:thisRowData]; }