2014-09-22 265 views
77

我有一个UITableView,其中使用自动布局在故事板中定义了自定义UITableViewCell。该单元有几个多行UILabelsUITableView动态单元格高度仅在滚动后才会更正

UITableView似乎可以正确计算单元格高度,但对于前几个单元格,高度在标签之间没有正确划分。 滚动一下后,一切都按预期工作(即使最初不正确的单元格)。

- (void)viewDidLoad { 
    [super viewDidLoad] 
    // ... 
    self.tableView.rowHeight = UITableViewAutomaticDimension; 
} 


- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { 
    TableViewCell *cell = [self.tableView dequeueReusableCellWithIdentifier:@"TestCell"]; 
    // ... 
    // Set label.text for variable length string. 
    return cell; 
} 

有什么我可能会丢失,这是导致汽车布局不能够在前几次完成其工作?

我创建了一个演示此行为的sample project

Sample project: Top of table view from sample project on first load. Sample project: Same cells after scrolling down and back up.

+0

我也面临这个问题,但下面的答案是不是为我工作,在此 – 2016-06-28 12:07:55

+0

任何帮助面临着同样的问题,增加layoutIfNeeded细胞不起作用我呢?更多的建议 – Max 2016-09-05 13:01:53

回答

96

我不知道这是明确记载或没有,但加入[cell layoutIfNeeded]才回到小区解决您的问题。

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { 
    TableViewCell *cell = [self.tableView dequeueReusableCellWithIdentifier:@"TestCell"]; 
    NSUInteger n1 = firstLabelWordCount[indexPath.row]; 
    NSUInteger n2 = secondLabelWordCount[indexPath.row]; 
    [cell setNumberOfWordsForFirstLabel:n1 secondLabel:n2]; 

    [cell layoutIfNeeded]; // <- added 

    return cell; 
} 
+2

我很想知道,为什么只有第一次通过才有必要?如果我将调用放在单元的'-awakeFromNib'中的'-layoutIfNeeded',它也可以工作。我宁愿只调用'layoutIfNeeded',我知道为什么它是必要的。 – blackp 2014-09-23 00:33:40

+2

为我工作!我很想知道为什么它是必需的! – Mustafa 2015-01-16 11:22:55

+0

如果你渲染尺寸类,不同于任何X – 2015-05-07 21:49:45

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


// call the method dynamiclabelHeightForText 
} 

使用哪个动态返回高度该行的上述方法。 并将相同的动态高度分配给您使用的标签。

-(int)dynamiclabelHeightForText:(NSString *)text :(int)width :(UIFont *)font 
{ 

    CGSize maximumLabelSize = CGSizeMake(width,2500); 

    CGSize expectedLabelSize = [text sizeWithFont:font 
           constrainedToSize:maximumLabelSize 
            lineBreakMode:NSLineBreakByWordWrapping]; 


    return expectedLabelSize.height; 


} 

此代码可帮助您找到标签中文本显示的动态高度。

+0

实际上是Ramesh,只要设置了tableView.estimatedRowHeight和tableView.rowHeight = UITableViewAutomaticDimension属性,就不需要这样做。另外,确保自定义单元格对各种小部件和contentView有适当的限制。 – BonanzaDriver 2015-01-15 22:39:42

4

在我的情况下,第一次显示单元格时,UILabel的最后一行被截断。它发生得非常随机,正确调整大小的唯一方法是将单元格从视图中滚动并将其恢复。 我尝试了迄今为止显示的所有可能的解决方案(layoutIfNeeded..reloadData),但没有为我工作。诀窍是将“Autoshrink”设置为Minimuum Font Scale(对我而言为0.5)。试一试

+0

这适用于我,而不应用上面列出的任何其他解决方案。很棒的发现。 – mckeejm 2015-09-09 20:49:52

+0

但是这autoshrinks文本...为什么要在表视图中有不同大小的文字?看起来很糟糕。 – 2017-09-29 14:43:10

18

cellForRowAtIndexPath中添加[cell layoutIfNeeded]对于最初滚动到视野范围内的单元格不起作用。

也没有用[cell setNeedsLayout]预处理它。

您仍然需要将某些单元格向外滚动并返回到视图中才能正确调整大小。

这很令人沮丧,因为大多数开发人员都具有动态类型,自动布局和自定义大小的单元格可以正常工作 - 除了这个烦人的情况。这个bug会影响我所有“更高”的表格视图控制器。

+0

同样适用于我。当我第一次滚动时,单元格的大小是44px。如果我滚动以使细胞看不到并回来,它的大小适当。你有没有找到解决方案? – Max 2015-06-18 13:56:15

+3

取消选中“使用大小班级”为我们工作! – 2015-08-03 10:54:06

+0

谢谢@ ashy_32bit这也为我解决了它。 – ImpurestClub 2015-08-18 17:52:19

2

我尝试了此页面中的所有解决方案,但取消选中使用大小类,然后再次检查解决了我的问题。

编辑:取消选中尺寸类会导致故事板上出现很多问题,所以我尝试了另一种解决方案。我在视图控制器的ViewDidLoadViewWillAppear方法中填充tableView。这解决了我的问题。

9

我在我的一个项目中也有同样的经历。

为什么会发生?

在Storyboard中为某些设备设计了一些宽度的单元。例如400px。例如,您的标签具有相同的宽度。从故事板加载时,它的宽度为400px。

这里有一个问题:

tableView:heightForRowAtIndexPath:单元布局之前调用它的子视图。

因此它计算宽度为400px的标签和单元格的高度。但是你在屏幕上运行设备,例如320px。这个自动计算的高度不正确。仅仅因为电池的layoutSubviews仅在tableView:heightForRowAtIndexPath: 之后发生即使您在layoutSubviews中手动为您的标签设置preferredMaxLayoutWidth也没有帮助。

我的解决办法:

1)子类UITableView并重写dequeueReusableCellWithIdentifier:forIndexPath:。设置单元格宽度等于表格宽度和强制单元格的布局。

- (UITableViewCell *)dequeueReusableCellWithIdentifier:(NSString *)identifier forIndexPath:(NSIndexPath *)indexPath { 
    UITableViewCell *cell = [super dequeueReusableCellWithIdentifier:identifier forIndexPath:indexPath]; 
    CGRect cellFrame = cell.frame; 
    cellFrame.size.width = self.frame.size.width; 
    cell.frame = cellFrame; 
    [cell layoutIfNeeded]; 
    return cell; 
} 

2)子类UITableViewCell。 在layoutSubviews中为您的标签手动设置preferredMaxLayoutWidth。您还需要手动布局contentView,因为它没有细胞框架的变化后,自动布局(我不知道为什么,但它是)

- (void)layoutSubviews { 
    [super layoutSubviews]; 
    [self.contentView layoutIfNeeded]; 
    self.yourLongTextLabel.preferredMaxLayoutWidth = self.yourLongTextLabel.width; 
} 
+1

当我遇到了这个问题,我也需要确保实现代码如下的框架是正确的,所以我叫[self.tableview layoutIfNeeded]被填充的tableview之前(在viewDidLoad中)。 – GK100 2016-05-30 18:34:31

1

我有一个调整的标签,所以我的东东只是做的问题
chatTextLabel.text = chatMessage.message chatTextLabel?.updateConstraints()后设置文本

//完整的代码

func setContent() { 
    chatTextLabel.text = chatMessage.message 
    chatTextLabel?.updateConstraints() 

    let labelTextWidth = (chatTextLabel?.intrinsicContentSize().width) ?? 0 
    let labelTextHeight = chatTextLabel?.intrinsicContentSize().height 

    guard labelTextWidth < originWidth && labelTextHeight <= singleLineRowheight else { 
     trailingConstraint?.constant = trailingConstant 
     return 
    } 
    trailingConstraint?.constant = trailingConstant + (originWidth - labelTextWidth) 

    } 
3

添加约束所有conten表视图自定义单元格内吨,然后估计表视图行的高度,并设置行HIGHT到自动尺寸与在viewdid负载:

override func viewDidLoad() { 
    super.viewDidLoad() 

    tableView.estimatedRowHeight = 70 
    tableView.rowHeight = UITableViewAutomaticDimension 
} 

为了解决这个问题初始加载问题在自定义表视图细胞申请layoutIfNeeded方法与:

class CustomTableViewCell: UITableViewCell { 

override func awakeFromNib() { 
    super.awakeFromNib() 
    self.layoutIfNeeded() 
    // Initialization code 
} 
} 
+0

不为我工作 – 2017-09-29 14:38:45

+0

设置'estimatedRowHeight'为值> 0是很重要的,而不是'UITableViewAutomaticDimension'(这是-1),否则自动行高度将无法正常工作。 – 2017-11-13 10:07:46

0

在我的情况,与细胞高度问题发生在初始表视图被加载后,与一个用户动作发生(攻丝上的按钮,在具有改变的细胞的效果的细胞高度)。我一直无法得到的细胞改变其高度,除非我做的:

[self.tableView reloadData]; 

我曾尝试

[cell layoutIfNeeded]; 

,但没有奏效。

13

这为我工作,当其他类似的解决方案都没有:

override func didMoveToSuperview() { 
    super.didMoveToSuperview() 
    layoutIfNeeded() 
} 

这似乎是一个实际的错误,因为我非常熟悉的自动版式,以及如何使用UITableViewAutomaticDimension,但是我还是偶尔会遇到这个问题。我很高兴终于找到了解决问题的办法。

+1

比接受的答案更好,因为只有在从xib而不是每个单元格显示加载单元格时才会调用它。更少的代码行。 – 2017-03-23 05:22:43

+2

这是一个真正的宝石。谢谢。 – 2017-04-09 22:25:28

+1

不要忘记调用'super.didMoveToSuperview()' – cicerocamargo 2017-09-28 11:36:36

6

我有类似的问题,在第一次加载时,行高不计算,但在一些滚动或转到另一个屏幕后,我回到这个屏幕行计算。在第一次加载时,我的物品从互联网加载,在第二次加载时,我的物品首先从Core Data加载,然后从互联网上重新加载,我注意到行高从互联网重新加载时计算。所以我注意到,当在segue动画中调用tableView.reloadData()(与push和present segue相同的问题)时,行高不计算。所以我隐藏tableview在视图初始化,并把一个活动加载程序,以防止对用户丑陋的影响,我在300毫秒后调用tableView.reloadData现在问题得到解决。我认为这是一个UIKit错误,但是这个解决方法可以解决这个问题。

我把论文线(雨燕3.0)在我的项目负荷完成处理

DispatchQueue.main.asyncAfter(deadline: .now() + .milliseconds(300), execute: { 
     self.tableView.isHidden = false 
     self.loader.stopAnimating() 
     self.tableView.reloadData() 
    }) 

这解释了为什么有些人,把reloadData在layoutSubviews解决问题

+0

这是唯一一个为我工作的华盛顿州。除非我不使用isHidden,但在添加数据源时将表的alpha设置为0,然后在重新加载后将其设置为1。 – 2017-11-13 10:05:46

0

在斯威夫特3.我有每次更新可重用单元的文本时调用self.layoutIfNeeded()。

import UIKit 
import SnapKit 

class CommentTableViewCell: UITableViewCell { 

    static let reuseIdentifier = "CommentTableViewCell" 

    var comment: Comment! { 
     didSet { 
      textLbl.attributedText = comment.attributedTextToDisplay() 
      self.layoutIfNeeded() //This is a fix to make propper automatic dimentions (height). 
     } 
    } 

    internal var textLbl = UILabel() 

    override func layoutSubviews() { 
     super.layoutSubviews() 

     if textLbl.superview == nil { 
      textLbl.numberOfLines = 0 
      textLbl.lineBreakMode = .byWordWrapping 
      self.contentView.addSubview(textLbl) 
      textLbl.snp.makeConstraints({ (make) in 
       make.left.equalTo(contentView.snp.left).inset(10) 
       make.right.equalTo(contentView.snp.right).inset(10) 
       make.top.equalTo(contentView.snp.top).inset(10) 
       make.bottom.equalTo(contentView.snp.bottom).inset(10) 
      }) 
     } 
    } 
} 

func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { 
     let comment = comments[indexPath.row] 
     let cell = tableView.dequeueReusableCell(withIdentifier: CommentTableViewCell.reuseIdentifier, for: indexPath) as! CommentTableViewCell 
     cell.selectionStyle = .none 
     cell.comment = comment 
     return cell 
    } 

commentsTableView.rowHeight = UITableViewAutomaticDimension 
    commentsTableView.estimatedRowHeight = 140 
2

Attatching screenshot for your referance对我来说,这些方法都没有工作,但我发现标签有在Interface Builder明确Preferred Width集。删除(取消选中“显式”),然后使用UITableViewAutomaticDimension按预期工作。

+0

只有这一个工作 – SARATH 2017-10-03 13:13:14

0

在我的情况下,我正在更新其他周期。因此,在设置labelText后,tableViewCell高度已更新。我删除了异步块。

func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { 
    let cell = tableView.dequeueReusableCell(withIdentifier:Identifier, for: indexPath) 
    // Check your cycle if update cycle is same or not 
    // DispatchQueue.main.async { 
     cell.label.text = nil 
    // } 
} 
0

上述解决方案都无法正常工作,但以下方法的组合都做了。

只好在viewDidLoad()中添加以下内容。

DispatchQueue.main.async { 

     self.tableView.reloadData() 

     self.tableView.setNeedsLayout() 
     self.tableView.layoutIfNeeded() 

     self.tableView.reloadData() 

    } 

reloadData,setNeedsLayout和layoutIfNeeded的上述组合工作,但没有任何其他。可能是特定于项目中的单元格。是的,必须调用reloadData两次以使其工作。

而且设置的viewDidLoad以下

tableView.rowHeight = UITableViewAutomaticDimension 
tableView.estimatedRowHeight = MyEstimatedHeight 

在的tableView(_的tableView:UITableView的,cellForRowAt indexPath:IndexPath)

cell.setNeedsLayout() 
cell.layoutIfNeeded() 
0

只要确保你不是在“设置标签文本willdisplaycell'表视图的委托方法。 在'cellForRowAtindexPath'委托方法中设置标签文本以进行动态高度计算。

你是欢迎:)

0

在我的情况下,在电池堆叠视图是造成问题。这显然是一个错误。一旦我将其删除,问题就解决了。

3

我已经尝试了这个问题的大部分答案,并没有得到任何他们的工作。我发现的唯一的功能性的解决办法是将以下内容添加到我的UITableViewController子类:

override func viewWillAppear(_ animated: Bool) { 
    super.viewWillAppear(animated) 
    UIView.performWithoutAnimation { 
     tableView.beginUpdates() 
     tableView.endUpdates() 
    } 
} 

是必需的UIView.performWithoutAnimation通话,否则你会看到正常的表视图动画作为视图控制器负载。

+0

工作,肯定比调用reloadData两次 – 2017-07-19 12:33:10

+0

这是唯一的解决方案,为我工作以及 Swift 3,Xcode 8.3.3 – 2017-08-01 21:41:22

+0

黑魔法。在'viewWillAppear'中做它不适合我,但在'viewDidAppear'中做。 – Martin 2017-10-11 14:45:21

0

我遇到了这个问题,并通过将我的视图/标签初始化代码从tableView(willDisplay cell:)移动到tableView(cellForRowAt:)来修复它。

+0

这是不*推荐的方式来初始化单元格。 'willDisplay'将比'cellForRowAt'具有更好的性能。使用最新版本来实现正确的单元格。 – Martin 2017-10-11 14:41:46

0

问题是,我们有一个有效的行高之前,初始单元格加载。 解决方法是在视图出现时强制重新加载表。

- (void)viewDidAppear:(BOOL)animated 
{ 
    [super viewDidAppear:animated]; 
    [self.tableView reloadData]; 
} 
相关问题