Ios 从情节提要检索自定义原型单元高度?

Ios 从情节提要检索自定义原型单元高度?,ios,uitableview,uistoryboard,Ios,Uitableview,Uistoryboard,当使用“动态原型”在情节提要上指定UITableView内容时,有一个“行高”属性可以设置为自定义 实例化单元格时,不考虑此自定义行高度。这是有道理的,因为在实例化单元时,我使用的原型单元由我的应用程序代码决定。在计算布局时实例化所有单元格会带来性能损失,所以我理解为什么不能这样做 那么问题是,我是否可以在给定单元重用标识符的情况下检索高度,例如 [myTableView heightForCellWithReuseIdentifier:@"MyCellPrototype"]; 还是类似的?或

当使用“动态原型”在情节提要上指定
UITableView
内容时,有一个“行高”属性可以设置为自定义

实例化单元格时,不考虑此自定义行高度。这是有道理的,因为在实例化单元时,我使用的原型单元由我的应用程序代码决定。在计算布局时实例化所有单元格会带来性能损失,所以我理解为什么不能这样做

那么问题是,我是否可以在给定单元重用标识符的情况下检索高度,例如

[myTableView heightForCellWithReuseIdentifier:@"MyCellPrototype"];
还是类似的?或者我必须在我的应用程序代码中复制显式的行高度,并承担随之而来的维护负担

在@timothymose:的帮助下解决

高度存储在单元格中,这意味着获取高度的唯一方法是实例化原型。一种方法是在正常的单元回调方法之外预先将单元出列。这是我的小型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];
}
对于动态(数据驱动)高度,可以将原型单元存储在视图控制器中,并将计算高度的方法添加到单元类中,同时考虑原型实例的默认内容,如子视图放置、字体等:

- (MyCustomCell *)prototypeCell
{
    if (!_prototypeCell) {
        _prototypeCell = [self.tableView dequeueReusableCellWithIdentifier:@"MyCustomCell"];
    }
    return _prototypeCell;
}

- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
    // Data for the cell, e.g. text for label
    id myData = [self myDataForIndexPath:indexPath];

    // Prototype knows how to calculate its height for the given data
    return [self.prototypeCell myHeightForData:myData];
}
当然,如果您使用的是自定义高度,您可能有多个单元原型,因此您需要将它们存储在字典或其他东西中

据我所知,表视图没有尝试重用原型,可能是因为它在
cellforrowatinexpath:
之外出列。这种方法对我们来说非常有效,因为它允许设计者在不需要任何代码更改的情况下修改故事板中的单元布局


编辑:澄清了示例代码的含义,并添加了一个静态高度示例。

我不久前为UITableView创建了一个类别,这可能会有所帮助。它存储用于重用原型的“原型”单元,并提供了一种方便的方法来获取故事板中指定的行高度。取消分配表视图时,将释放原型

UITableView+PrototypeCells.h

#import <UIKit/UIKit.h>

@interface UITableView (PrototypeCells)

- (CGFloat)heightForRowWithReuseIdentifier:(NSString*)reuseIdentifier;
- (UITableViewCell*)prototypeCellWithReuseIdentifier:(NSString*)reuseIdentifier;

@end
假设为多节表视图:

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;
}
最后,如果行高度是动态的:

- (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];
}

我不认识
heightForData:
方法。它是做什么的?
heightForData:
是一种计算给定单元格数据高度的方法。我明白了。问题是,我想使用存储在故事板文件本身中的高度(静态高度)。不过,您的细胞预排可能也适用于此。我会试试看。看看。它通过自动创建原型来计算单元高度,a)返回原型静态高度,或b)如果单元实现了
tldynamiczeview
prototype,则返回动态高度。请参见示例项目。这确实是该库的第二个功能,但值得一看。这种方法的问题是,当界面方向从纵向更改为横向时,它不起作用。可能的解决方案:将单元格的边框/宽度重置为表格的宽度,然后再计算heightForRowAtIndexPath:method中的高度。希望这有帮助。这看起来真的很有用。谢谢伟大的实现,你应该把它放在github上&potI已经使用这个方法有一段时间了,然后在一个新的故事板上,我得到的单元格高度(和宽度)几乎为零。即使是非零值也是意外值。禁用大小类可恢复此功能。但令人失望的是,这个“修复”禁用了故事板中的重要功能。然而,这满足了我的迫切需要。我找到了一个更完整的解决方案。
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;
}
- (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];
}