为什么UITableViewAutomaticDimension不起作用?

83

嗨,关于UITableViewUITableViewCell的动态高度有很多问题需要回答。但是我发现当我这样做时感觉有些奇怪。

下面是其中一些答案:

这里这里

通常情况下,这些可以回答单元格的动态高度问题。

tableView.estimatedRowHeight = 44.0
tableView.rowHeight = UITableView.automaticDimension

但在我的情况下,我想这行代码不会有任何作用。

我的UITableView是在单击分栏视图中的选项卡后查看的。这有帮助吗?

也许我遗漏了什么。有人可以帮我吗?我已经浪费了两个小时。

这些是我的标题约束,标题可能很长,但标签不是。

enter image description here

这是我的单元格

enter image description here


2
你应该仔细检查一下在xib/storyboard中的UITableViewCell自动布局设置。你肯定有一些问题。 - Vitalii Gozhenko
2
是的,我正在重写它。希望找到导致这个问题的原因。 - CaffeineShots
如果您将您的xib/storyboard张贴在那里,我可以帮助您处理。 - Vitalii Gozhenko
你是否将视图约束设置为相对于单元格内容视图的顶部和底部? - Zell B.
你的标签有底部空间约束吗? - Zell B.
显示剩余5条评论
19个回答

175
为了让UITableViewAutomaticDimension起作用,您需要将所有左、右、底部和顶部约束设置为相对于单元格容器视图。在您的情况下,您需要为标题下方的标签添加缺失的与父视图的底部空间约束。

17
请注意,你可能需要将某些视图的底部约束条件设置为>=而不仅仅是=,以便它们可以随着单元格动态高度的增加而增长。这是我的诀窍。 - Ryan R
@khunshan 你确定你没有使用尺寸类吗? - Zell B.
@ZellB。是的,你说得对。这是因为缺少了iPhone类的限制。(Y) - khunshan

32

我在程序中添加了约束条件,不小心直接将它们添加到了单元格上,而不是contentView属性上。将约束添加到contentView上解决了我的问题!


是的,我们需要清楚地知道我们使用了什么约束,因为缺少或添加一个约束可能会导致歧义或未满足的约束。谢谢你的回答! - CaffeineShots
我知道这个问题很老了,但我认为这不是正确的解决方法。如果您不将限制条件添加到内容视图中,则在打开单元格的任何编辑样式(如删除或移动行)时,视图将会失真。 - Esko918
@Esko918 我认为你误解了他的回答。他是在说你需要向contentView添加约束。我也不小心向UITableViewCell添加了约束,但实际上应该是向UITableViewCellcontentView添加约束。 - Alan
这就是我说的。如果您不将约束添加到内容视图中,则在选择编辑样式(如删除或移动行)时,视图将会失真。您不应直接修改单元格视图,因为当您进入编辑模式并且单元格向右移动时,UIKit 会修改单元格布局。您应该将所有子视图和布局约束添加到内容视图中,而不是视图本身。 - Esko918

27
为了设置行高度的自动调整和估算行高度,请按照以下步骤进行操作,以使单元格/行高度布局的自动调整生效:
  • 分配并实现tableview的数据源和代理
  • UITableViewAutomaticDimension分配给rowHeight和estimatedRowHeight
  • 实现代理/数据源方法(例如heightForRowAt),并返回一个值UITableViewAutomaticDimension

-

Objective-C:

// in ViewController.h
#import <UIKit/UIKit.h>

@interface ViewController : UIViewController <UITableViewDelegate, UITableViewDataSource>

  @property IBOutlet UITableView * table;

@end

// in ViewController.m

- (void)viewDidLoad {
    [super viewDidLoad];
    self.table.dataSource = self;
    self.table.delegate = self;

    self.table.rowHeight = UITableViewAutomaticDimension;
    self.table.estimatedRowHeight = UITableViewAutomaticDimension;
}

-(CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath {

    return UITableViewAutomaticDimension;
}

Swift:

@IBOutlet weak var table: UITableView!

override func viewDidLoad() {
    super.viewDidLoad()

    // Don't forget to set dataSource and delegate for table
    table.dataSource = self
    table.delegate = self

    // Set automatic dimensions for row height
    // Swift 4.2 onwards
    table.rowHeight = UITableView.automaticDimension
    table.estimatedRowHeight = UITableView.automaticDimension


    // Swift 4.1 and below
    table.rowHeight = UITableViewAutomaticDimension
    table.estimatedRowHeight = UITableViewAutomaticDimension

}



// UITableViewAutomaticDimension calculates height of label contents/text
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
    // Swift 4.2 onwards
    return UITableView.automaticDimension

    // Swift 4.1 and below
    return UITableViewAutomaticDimension
}

在UITableviewCell中的标签实例:
  • 将行数设置为0(并将换行模式设置为truncate tail)
  • 根据其父视图/单元格容器设置所有约束条件(顶部、底部、右侧和左侧)。
  • 可选项:如果您希望标签覆盖最小的垂直区域,即使没有数据,请为标签设置最小高度。

enter image description here

注意:如果您有多个具有动态长度的标签(UIElements),应根据其内容大小调整这些标签的'Content Hugging and Compression Resistance Priority',以便更高优先级的标签可以扩展/压缩。


使用返回UITableView.automaticDimension的heightForRowAt实现工作。 - Ucdemir
不要在estimatedHeightForRowAt代理方法中返回automaticDimension。它的作用是提示表视图单元格的大小。 - nickdnk

20

同时确保单元格中UILabel的行数设置为0。如果设置为1,则不会垂直增长。


7

从iOS 11和Xcode 9.3开始,上述大部分信息已经过时。苹果公司的指南建议设置自适应大小表格视图单元格。

    tableView.estimatedRowHeight = 85.0
    tableView.rowHeight = UITableViewAutomaticDimension

WWDC 2017会议第245节(讲解动态字体构建应用,视频时长16:33)提到了类似的问题。但这对我并没有什么影响。

对于字幕风格单元格,只需将Title和Subtitle标签(属性检查器中的Label部分)的行数设置为0,即可实现自调整大小的表格视图单元格。如果其中一个标签过长,而你没有将它们的行数设置为0,则表格视图单元格将无法调整其大小。


numberOfLines属性设置为0,对于两个标签都可以让你在非自定义的UITableViewCell中实现自适应大小。非常感谢! - mxcl

7
我有一个具体的案例,阅读了99%的解决方案都没有起作用。我想分享一下我的经验。希望可以帮助到你们,因为在解决这个问题之前我已经挣扎了几个小时。 我的情况
  • 我在一个ViewController中使用了两个TableView
  • 我在这些tableview中加载自定义单元格(xib)
  • 单元格中的动态内容包括两个标签
  • 页面使用了一个ScrollView
我需要实现的目标
  • 动态的TableView高度
  • 动态的TableViewCell高度
为了使其顺利工作,您需要检查以下内容:
  • Like every tutorial and answer will tell you, set all the constraints for your label/content (top, bottom, leading & trailing), and set it to the ContentView (Superview). This video tutorial will be helpful.

  • In the viewWillAppear method of my ViewController, I am giving one of my tableViews (tableView2) an estimated row height and then use the UITableViewAutomaticDimension as such (and as seen in all tutorials/answers):

        override func viewWillAppear(_ animated: Bool) {
        super.viewWillAppear(animated)
    
        tableView2.estimatedRowHeight = 80
        tableView2.rowHeight = UITableViewAutomaticDimension
    
    }
    
对我来说,这些之前的步骤还不够。我的TableView只是取estimatedRowHeight并将其乘以单元格数量。嗯。
  • As I am using two different tableViews, I created an outlet for each of them, tableView1 and tableView2. Allowing me to resize them in the viewDidLayoutSubviews method. Feel free to ask in comment how I did this.

  • One additional step fixed it for me, by adding this to the viewDidAppear method:

    override func viewDidAppear(_ animated: Bool) {
    tableView1.reloadData() // reloading data for the first tableView serves another purpose, not exactly related to this question.
    tableView2.setNeedsLayout()
    tableView2.layoutIfNeeded()
    tableView2.reloadData()
    }
    
希望能帮助到某些人!

最后一个建议(但不包括双IBOutlet)在2019年仍然很有用。 - zhukov.ever

5

对于可能遇到与我相同问题的任何人:我为使它工作而奋斗了一个小时。一个简单的UIlabel,带有顶部、底部、左侧和右侧的约束。我使用willDisplayCell将数据传递给单元格,这会导致单元格高度出现问题。只要我把那段代码放在cellForRow里,一切都正常了。不明白为什么会发生这种情况,也许是因为计算单元格高度时,在调用willDisplayCell之前进行了计算,因此没有内容进行正确的计算。我想提一下,可能可以帮助遇到相同问题的人。


谢谢!我也曾经为这个问题苦恼过。对我来说,这似乎是一个UIKit的bug,但这解决了它! - Gary Hooper

5

忘记删除tableView(heightForRowAt:indexPath:)

可能像我一样,您不小心忘记删除 heightForRowAt 方法的样板代码。

func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
    return 60.0
}

当然也不要给它一个高度限制;-) - Marcos
2
你可以在这个方法中返回UITableViewAutomaticDimension。用于子类化。 - Yanny

4

在iOS 11及更高版本中,这对我来说运作良好,但在iOS 10中出现了问题。

解决方法是添加

</p>
table.rowHeight = UITableView.automaticDimension
table.estimatedRowHeight = 200 // a number and not UITableView.automaticDimension

请确保您添加了 "heightForRowAt",即使它在 iOS 11 及以上版本中可用,如果您支持 iOS 10,则需要该方法。

   func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
        return UITableView.automaticDimension
    }

3

尝试这个,这是一个简单的解决方案,对我有用,

在viewDidLoad中编写以下代码,

-(void)viewDidLoad 
{
[super viewDidLoad];
 self.tableView.estimatedRowHeight = 100.0; // for example. Set your average height
 self.tableView.rowHeight = UITableViewAutomaticDimension;
}

在`cellForRowAtIndexPath`方法中编写以下代码:
 -(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
 {
  static NSString *CellIdentifier = @"Cell";
  UITableViewCell *cell = [tableView 
  dequeueReusableCellWithIdentifier:CellIdentifier];
 if (cell == nil) {
    cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:CellIdentifier] ;
  }
    cell.textLabel.numberOfLines = 0; // Set label number of line to 0
    cell.textLabel.text=[[self.arForTable objectAtIndex:indexPath.row] valueForKey:@"menu"];
    [cell.textLabel sizeToFit]; //set size to fit 
    return cell;
 }

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接