当单元格构造不均匀时,如何计算heightForRowAtIndexPath? [英] how do I calculate heightForRowAtIndexPath when the cell is not even constructed yet?

查看:114
本文介绍了当单元格构造不均匀时,如何计算heightForRowAtIndexPath?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

问题 - 如何在UITableViewController的heightForRowAtIndexPath方法中最好地计算行的高度,假设:

Question - How does one best calculate the height for a row in the "heightForRowAtIndexPath" method of a UITableViewController, given that:


  1. 我正在使用自定义子类UITableViewCell&子视图的实际大小(例如UILabels)是在运行时计算的。取决于诸如用户是否更改了字体大小的内容

  2. 单元格实际上没有准备好它似乎在heightForRowAtIndexPath之前,所以你不能依赖于调用你的特定自定义单元格即时查询它

目前我唯一想到的是:
1.在你的自定义UITableViewCell中子类创建一个方法来计算UITableViewCell子类中每个子视图(例如UILabel)的高度 - 然后在创建实例
时在单元子类中使用它。另外在自定义子类中创建一个类方法贯穿所有UILabel,调用上述方法,总结高度,从而计算总行高。它必须将数据传递给它(例如每个UILabel中的文本)
3.在UITableViewControllerheightForRowAtIndexPath中,你必须从上面的(2)调用calRowHeight类型方法,传递它标签文本数据。因此,有效地调用自定义单元子类上的类方法,该方法知道如何计算总行高,但是它使用了与单元格所需的逻辑相同的...

Only thing I can think of for the moment is to: 1. In your custom UITableViewCell subclass create a method that calculates the heights of each subview (e.g. UILabel) that is in the UITableViewCell subclass - then use this within the cell subclass when it is creating instances 2. Also in the custom subclass create a class method that runs through all the UILabels, calling the above-mentioned method, to sum up the heights and therefore work out the total row height. It would have to get the data passed to it (e.g. text in each of the UILabels) 3. In the UITableViewController "heightForRowAtIndexPath" then you have to call the "calRowHeight" type method from (2) above, passing it the label text data. So effectively call a class method on your custom cell subclass which knows how to work out the total row height, but it's using the same logic that the cell needs too...

有没有比这更容易的方法?

Is there an easier way than this I'm missing?

推荐答案

创建UITableView时,无论何时发送reloadData消息,为每个单元格发送一个heightForRowAtIndexPath消息的数据源。因此,如果您的表格有30个单元格,则该消息会被发送30次。

When a UITableView is created and whenever you send it a reloadData message, the datasource is sent one heightForRowAtIndexPath message for each cell. So if your table has 30 cells, that message gets sent 30 times.

假设屏幕上只显示这30个单元格中的6个。在这种情况下,当创建并发送reloadData消息时,UITableView将为每个可见行发送一个cellForRowAtIndexPath消息,即该消息被发送六次。

Say only six of those 30 cells are visible on screen. In that case, when created and when you send it a reloadData message, the UITableView will send one cellForRowAtIndexPath message per visible row, i.e. that message gets sent six times.

为什么Apple会像这样实现吗?部分原因是,计算行的高度几乎总是比构建和填充整个单元格更便宜。鉴于在许多表格中,每个单元格的高度都是相同的,它通常要便宜得多。部分原因是因为iOS需要知道整个表的大小:这允许它创建滚动条并将其设置在滚动视图等上。

Why do Apple implement it like this? Part of the reason is that it's almost always cheaper to calculate the height of a row than it is to build and populate a whole cell. And given that in many tables the height of every cell will be identical, it is often vastly cheaper. And part of the reason is because iOS needs to know the size of the whole table: this allows it to create the scroll bars and set it up on a scroll view etc.

如果您的行高不同,因为它们包含不同数量的文本,您可以使用相关字符串上的sizeWithFont:方法之一来进行计算。这比构建视图然后测量结果更快。请注意,如果更改单元格的高度,则需要重新加载整个表格(使用reloadData - 这将询问代表的每个高度,但只询问可见的单元格)或选择性地重新加载大小所在的行更改。

If your row heights vary in size because they hold varying amounts of text, you can use one of the sizeWithFont: methods on the relevant string to do the calculations. This is quicker than building a view and then measuring the result. Note, that if you change the height of a cell, you will need to either reload the whole table (with reloadData - this will ask the delegate for every height, but only ask for visible cells) OR selectively reload the rows where the size has changed.

其他材料
如果我理解评论中的跟进问题,以下内容可能有所帮助:

Additional material If I understand the follow up question in the comment, the following may help:

如果您正在实施编辑模式,那么需要更改表格行的高度并不罕见。例如,您可能在表行中有文本,当它们的单元格变窄时 - 为右侧的删除圆圈腾出空间 - 您可能希望某些单元格变得更高以容纳文本。这里的基本方法是:

If you are implementing an editing mode, then it's not uncommon to need to change the height of your table rows. For example, you may have text in your table rows and when they cells become narrower - to make space for the delete circles on the right - you may want some of the cells to become taller to accommodate the text. The basic approach here is to:


  • 确保tableView:heightForRowAtIndexPath:方法知道您是否处于编辑模式。 (它可以使用isEditing询问tableView。)然后让方法返回正确的高度,具体取决于你是否处于编辑模式。

  • Make sure the tableView:heightForRowAtIndexPath: method knows whether your are in editing mode or not. (It can ask the tableView using isEditing.) And then get the method to return the right height, depending on whether you are in editing mode or not.

在UITableViewController中的setEditing:animated:方法(或者你正在使用的UIViewController中,根据你使用的内容存在一些差异,所以值得仔细检查文档)在你改变状态之后向tableView发送reloadData消息。这将强制tableView获取每一行的高度,它将重新获取可见行的单元格。当您进入编辑模式时,tableView处理使单元格变窄,但如果您想在布局上做更多工作,请在tableView:cellForRowAtIndex:中执行此操作。如上所述,一般策略是找到一种快速计算高度的方法。使用文本sizeWithFont :(及其变体)可以做到这一点。如果您有图像等,那么您可以抓住它们的尺寸并做一些总和。

In your setEditing:animated: method in the UITableViewController (or a UIViewController, whichever you are using - there are some differences depending what you use, so it's worth checking the documentation carefully) send a reloadData message to the tableView after you have changed its state. This will force the tableView to grab the heights of every row and it will refetch the cells for the visible rows. The tableView handles making cells narrower when you enter editing mode, but if you want to do more work on the layout, do it in tableView:cellForRowAtIndex:. As noted above, the general strategy is to find a means of calculating the height that is quick. With text sizeWithFont: (and its variants) can do it. If you have images etc., then you can grab their dimensions and do some sums.

除了这些步骤,您可能还想在切换模式后稍微滚动tableView。如果行的高度不同,那么在切换模式后,您将在表中的错误位置结束。我在这里采用的方法是在我重新加载表以调用执行滚动调整的方法之后使用performSelector:withObject:afterDelay。您需要使用延迟,以便让tableView有时间收集新的高度和新的表格单元格。 (可能有一种更聪明的方法可以做到这一点。)我做了一些总结,根据tableView的origin.y之间的差异进行滚动调整:cellForRowAtIndexPath:重新加载前后屏幕上第一个可见行的单元格。因此,例如,要在预加载之前获得位置,有点像这样。

In addition to those steps you may also want to scroll the tableView a bit after switching modes. If the heights of your rows are different, then you will end up in the wrong position in the table after switching mode. An approach I have taken here is to use performSelector:withObject:afterDelay after I've reloaded the table to call a method that does the scroll adjusting. You need to use the delay, to allow time for the tableView to collect the new heights and the new table cells. (There may be a smarter way of doing this.) I do some sums to make the scroll adjustment based on the difference between the origin.y of the tableView:cellForRowAtIndexPath: of the cell first visible row on screen before and after the reload. So, for e.g., to get the position before the pre-load, something a bit like this.

CGPoint offset = [[self tableView] contentOffset];
NSIndexPath* indexPath = [[self tableView] indexPathForRowAtPoint:CGPointMake(0,offset.y)];
CGFloat preCellOffset = [[[self tableView] cellForRowAtIndexPath:indexPath] origin].y;


这篇关于当单元格构造不均匀时,如何计算heightForRowAtIndexPath?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆