Iphone - 当每个单元格的高度是动态时,何时计算tableView的heightForRowAtIndexPath? [英] Iphone - when to calculate heightForRowAtIndexPath for a tableview when each cell height is dynamic?

查看:129
本文介绍了Iphone - 当每个单元格的高度是动态时,何时计算tableView的heightForRowAtIndexPath?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我看过这个问题很多次,但令人惊讶的是,我没有看到一个一致的答案,所以我会自己尝试一下:



如果你有tableview包含你自己的自定义UITableViewCells包含UITextViews和UILabels,其高度必须在运行时确定,你应该如何确定heightForRowAtIndexPath中的每一行的高度?



显而易见的第一个想法是通过计算并且然后对cellForRowAtIndexPath内的单元格内的每个视图的高度求和来计算每个单元格的高度,并且存储该最终总高度用于稍后检索。



这不会工作,但是因为cellForRowAtIndexPath被称为AFTER heightForRowAtIndexPath。



我唯一能想到的是做viewDidLoad内的所有计算,创建所有的UITableViewCells然后,计算单元格的高度并将其存储在UITableViewCell子类中的自定义字段中,并将每个单元格放在一个以indexPath为关键字的NSMutableDictionary中,然后使用cellForRowAtIndexPath和heightForRowAtIndexPath中的indexPath从字典中检索单元格,返回自定义高度值或单元格对象本身。



这种方法似乎是错误的,因为它不使用dequeueReusableCellWithIdentifier,而是我将加载所有的单元格一次进入我的控制器中的字典,并且委托方法将只做从字典检索正确的单元格。



我没有看到任何其他方式做它虽然。这是一个坏主意 - 如果是,这是正确的方法是什么?

解决方案

Apple实现UITableView的方式对每个人都不直观,很容易误解 heightForRowAtIndexPath :。一般的意图是,这是一个更快和内存的方法,可以在表中的每一行都被频繁调用。这与 cellForRowAtIndexPath:形成对比,后者通常较慢并且占用更多的内存,但仅对实际需要在任何给定时间显示的行进行调用。



为什么Apple实现这样? 部分原因是计算行的高度,而不是构建和填充整个单元格,它几乎总是更便宜(或者可以更便宜,如果你编码正确)。考虑到在许多表中,每个单元的高度将是相同的,它通常是非常便宜的。 原因的另一部分是因为iOS需要知道整个表格的大小:这允许它创建滚动条并将其设置在滚动视图等上。



因此,除非每个单元格的高度相同,否则当创建一个UITableView时,每当你发送一个reloadData消息时,数据源会为每个单元格发送一个heightForRowAtIndexPath消息。因此,如果您的表有30个单元格,该消息将发送30次。这些30个单元格中只有6个在屏幕上可见。在这种情况下,当创建和发送一个reloadData消息,UITableView将发送一个cellForRowAtIndexPath消息每个可见行,即该消息发送六次。



人们有时会对如何计算单元格高度而不创建视图本身产生疑问。。但通常这很容易做。



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

查看此问题,也许还可以这一个


I have seen this question asked many times but astoundingly, I have not seen a consistent answer, so I will give it a try myself:

If you have a tableview containing your own custom UITableViewCells that contain UITextViews and UILabels whose height must be determined at runtime, how are you supposed to determine the height for each row in heightForRowAtIndexPath?

The most obvious first idea is to calculate the height for each cell by calculating and then summing the heights of each view inside the cell inside of cellForRowAtIndexPath, and store that final total height for later retrieval.

This will not work however because cellForRowAtIndexPath is called AFTER heightForRowAtIndexPath.

The only thing I can think of is to do all the calculations inside viewDidLoad, create all the UITableViewCells then, calculate the cells height and store that in a custom field inside your UITableViewCell subclass, and put each cell in an NSMutableDictionary with the indexPath as the the key, and then simply retrieve the cell from the dictionary using the indexPath inside cellForRowAtIndexPath and heightForRowAtIndexPath, returning either the custom height value or the cell object itself.

This approach seems wrong though because it does not make use of dequeueReusableCellWithIdentifier, instead I would be loading all the cells at once into a dictionary in my controller, and the delegate methods would be doing nothing more than retrieving the correct cell from the dictionary.

I don't see any other way to do it though. Is this a bad idea - if so, what is the correct way to do this?

解决方案

The way Apple implements UITableView is not intuitive to everyone and it's easy to misunderstand the role of heightForRowAtIndexPath:. The general intention is that this is a faster and light-on-memory method that can be called for every row in the table quite frequently. This contrasts with cellForRowAtIndexPath: which is often slower and more memory intensive, but is only called for the rows that are actually need to be displayed at any given time.

Why do Apple implement it like this? Part of the reason is that it's almost always cheaper (or can be cheaper if you code it right) to calculate the height of a row than it is to build and populate a whole cell. Given that in many tables the height of every cell will be identical, it is often vastly cheaper. And another 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.

So, unless every cell height is the same, then 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. 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.

Some people are sometimes puzzled about how to calculate a cell height without creating the views themselves. But usually this is easy to do.

For example, 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 (which, last time I checked, also calls heightForRowAtIndexPath: on ever row but also does some scrolling work for good measure).

See this question and perhaps also this one.

这篇关于Iphone - 当每个单元格的高度是动态时,何时计算tableView的heightForRowAtIndexPath?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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