【问题标题】:Get reference of cell under heightForRowAtIndexPath: in iOS 8在 iOS 8 中获取 heightForRowAtIndexPath: 下单元格的引用
【发布时间】:2015-08-17 21:36:03
【问题描述】:

我目前正在从事一个项目,我在 UITableViewCell 中嵌入了一个 UITableView

我需要做的是禁用UITableView 的滚动并使UITableView 适合所有行的大小。但由于UITableView 继承自UIScrollView,使用Autolayout 不会强制UITableView 使单元格的高度取决于其contentSize(不是框架)返回UITableViewAutomaticDimension时。

iOS 7 解决方案

这在 iOS 7 之前很容易实现,因为我使用下面的代码获得了 heightForRowAtIndexPath: 下单元格的引用:

UITableViewCell *cell = [tableView cellForRowAtIndexPath:indexPath];
int height = cell.tableView.contentSize.height;

return height;

但在 iOS 8 中,它给出了 BAD_ACCESS,因为 iOS 8 在调用 cellForRowAtIndexPath: 之前调用了 heightForRowAtIndexPath:

iOS 8 方法

声明一个属性来保持单元格的引用:

@property (strong, nonatomic) UITableViewCell *prototypeCell

使用方法保存当前单元格对属性的引用以便使用它:

- (id)prototypeCellatIndexPath:(NSIndexPath *)indexPath {
    NSString *cellID = @"MyCell";

    if (!_prototypeCell) {
        _prototypeCell = [self.tableView dequeueReusableCellWithIdentifier:cellID];
    }

    return _prototypeCell;
}

从原型和它的 contentSize 中获取 UITableViewCell 中的 UITableView 我得到高度,然后通过以下方法将其返回到 heighForRowAtIndexPath: 下:

-(int)heightForThreadAtIndexPath:(NSIndexPath *)indexPath {
    _prototypeCell = [self prototypeCellatIndexPath:indexPath];

    [_prototypeCell.contentView setNeedsLayout];
    [_prototypeCell.contentView layoutIfNeeded];

    int footer = [_prototypeCell.tableView numberOfSections]*_prototypeCell.tableView.sectionFooterHeight;
    int header = [_prototypeCell.tableView numberOfSections]*_prototypeCell.tableView.sectionHeaderHeight;

    int height = ceilf(_prototypeCell.tableView.contentSize.height) + _prototypeCell.tableView.contentOffset.y + _prototypeCell.tableView.contentInset.bottom + _prototypeCell.tableView.contentInset.top + header + footer;
    NSLog(@"%i, %i", (int)ceilf(_prototypeCell.tableView.contentSize.height), height);

    return height;
}

-(CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath {
    return [self heightForThreadAtIndexPath:indexPath];
}

问题

我从prototypeCell返回的contentSize.height是错误的,它与UITableView的真实contentSize不匹配,但是当我记录真实的contentSize 在 CustomCell 类 下它显示正确的 contentSize,这与prototypeCell 下的不同。

这让我想知道也许我应该尝试使单元格在特定状态下出列以获得正确的 contentSize,但日志显示相同的值。

我一直在研究并尝试不同的想法,但到目前为止都没有奏效。我不知道是否有人试图实现与我类似的事情,并解决了这个问题。如果您能给我一个想法或其他东西,那就太好了。

【问题讨论】:

  • 您是否尝试过调用[self tableView:tableView cellForRowAtIndexPath:indexPath] 数据源方法而不是[self prototypeCellatIndexPath:indexPath];
  • 它提供 EXC_BAD_ACCESS

标签: ios uitableview ios8


【解决方案1】:

正如您所说,heightForRowAtIndexPath 委托方法在自动调用时不会为您提供行的动态高度。相反,您必须明确地将其称为: [self delegateMethod][self tableView:tableView cellForRowAtIndexPath:indexPath];

如果您将主 tableView 声明为 IBOutlet,如 myTableView,那么即使调用 [self.myTableView cellForRowAtIndexPath:indexPath] 也不起作用!!

我已经测试了代码,这对我有用:

内部MainTableViewController.m

-(NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
  return 7;
}

-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
  UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"tableViewCellMain"];
  if (cell == nil) {
    cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:@"tableViewCellMain"];
  }

  UITableView *tableViewChild = [[UITableView alloc] initWithFrame:CGRectMake(cell.frame.origin.x, cell.frame.origin.y, tableView.frame.size.width, tableView.frame.size.height) style:UITableViewStylePlain];
  [self.cls setNumberOfRows:indexPath.row+1];
  [tableViewChild setDelegate:self.cls];
  [tableViewChild setDataSource:self.cls];
  [tableViewChild setSeparatorStyle:UITableViewCellSeparatorStyleNone];
  [tableViewChild setScrollEnabled:NO];
  [tableViewChild reloadData];
  [cell addSubview:tableViewChild];
  return cell;
}

-(CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
  UITableViewCell *cell = [self tableView:tableView cellForRowAtIndexPath:indexPath];
  CGFloat height = cell.frame.size.height;
  for (int i=0; i<cell.subviews.count; i++) {
    UITableView *childTableView = (UITableView*) [cell.subviews lastObject];
    height = childTableView.contentSize.height;
  }

  NSLog(@"%f",height);
  return height;
}

我已将另一个类设置为childTableView 的委托以获取其数据。

内部ChildTableViewController.m

-(NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
  return self.numberOfRows;
}

-(UITableViewCell*)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
  UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"tableViewCellChild"];
  if (cell == nil) {
    cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:@"tableViewCellChild"];
  }
  [cell.textLabel setText:[NSString stringWithFormat:@"%ld",indexPath.row]];
  UIColor *cellTextColor = [UIColor blackColor];

  switch (indexPath.row)
  {
    case 0: cellTextColor = [UIColor redColor]; break;
    case 1: cellTextColor = [UIColor greenColor]; break;
    case 2: cellTextColor = [UIColor blueColor]; break;
    case 3: cellTextColor = [UIColor magentaColor]; break;
    case 4: cellTextColor = [UIColor purpleColor]; break;
    default: break;
  }
  [cell.textLabel setTextColor:cellTextColor];
  [tableView sizeToFit];
  return cell;
}

-(CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
  return 30;
}

你会得到如下图所示的工作:

我的故事板如下所示:

您可以使用任何方式为mainTableView 生成动态内容,而无需为childTableView 使用另一个类。

【讨论】:

  • 这个答案有几点需要重新考虑,因为它们具有误导性。您需要避免将属性设置为 IBOutlets 的事实是不正确的。您提供的示例代码在 lastObject 上崩溃,因为它不是 tableView 而是其他东西,还有cellForRowAtIndexPath:。无论如何,这对我有一些帮助,所以我投票给你。
  • 感谢您的支持。关于创建 IBOutlet,我并不是要避免创建,我的意思是在 heightForRowAtIndexPath 的第一行调用 IBOutlet UITableView 的 cellForRowAtIndexPath: 不起作用。您可以随时随地使用 IBOutlets。关于崩溃,你能告诉我导致崩溃的原因和原因吗,因为我再次运行它并发现它正在工作。
【解决方案2】:

您也可以在 iOS 8 中使用您的 iOS 7 方法,唯一改变的是您不能使用 heightForRowAtIndexPath: 方法中的 delegate 而是在您的控制器中调用实际的 cellForRowAtIndexPath:,所以换行:

UITableViewCell *cell = [tableView cellForRowAtIndexPath:indexPath];

到行:

UITableViewCell* cell = [self tableView:tableView cellForRowAtIndexPath:indexPath];

并且应该可以工作。

【讨论】:

  • 就像在cmets中提到的,这个方法在cellForRowAtIndexPath:下给出EXC_BAD_ACCESS。
  • 对我有用,但是当您尝试在表格视图中添加新单元格时,您会感觉到它对性能造成的损害。同样不建议访问heightForRowAtIndexPath中的单元格
【解决方案3】:

我不确定这是否对你有帮助,但我之前必须做这样的事情,我最终将它嵌入 UICollectionView 并在单元格中垂直滚动,因此它的行为类似于 tableview 但其他视图不是 UITableView 并且这使得我能够分别控制每个人

希望这个提示能帮助你好运

【讨论】:

  • 我可以单独控制在 ViewController 中完成主 tableView 处理的 tableViews,同时在 customCell 上处理嵌入的 tableViews。不是这样的,情况是iOS 8在添加自动高度的时候做了一些大的改动。
【解决方案4】:

我设置了另一个响应,我将所有内容设置为完全动态并且无法重现您的问题: 这是一个存储库:https://bitbucket.org/Kettu/dynamiccellfrorow。我所做的是调用重新加载数据,当我 awakeForNib 计算所有行时,可以在 iOS 7 中的 scrollView contentSize 下找到最终值。

请注意,由于此演示项目中的行数和高度是完全随机的,因此每次单元格可重用时都会重新加载并闪烁。不应该发生在真实数据上。

【讨论】:

  • 是的,但是根据您提供的方法,它有[tableView dequeueReusableCellWithIdentifier:CellIdentifier],但我的是[tableView dequeueReusableCellWithIdentifier:CellIdentifier forIndexPath:indexPath]。更改在这里:stackoverflow.com/questions/25826383/… 还要提到这里的大小计算不正确,因为我使用的是UITableViewAutomaticDimension,所以我被卡住的地方是一样的。如果你愿意,我可以通过我修改后的数据来提供你的项目。
  • 这是一个很好的例子,我通过使用这个项目作为参考解决了它,所以这个。所以我给你赏金。 :)
猜你喜欢
  • 1970-01-01
  • 2015-10-22
  • 1970-01-01
  • 2015-03-13
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多