UITableView的动态单元格高度一些滚动后唯一正确UITableView的动态单元格高度一些滚

2019-05-13 04:22发布

我有一个UITableView一个自定义UITableViewCell在使用自动布局的故事板定义。 小区有几个多UILabels

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;
}

有什么,我可能会丢失,这是造成自动布局不能够完成其工作的第几次?

我创建了一个示例项目 ,其演示了此行为。

Answer 1:

我不知道这是明确记载或没有,但加入[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;
}


Answer 2:

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

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

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



Answer 3:

添加[cell layoutIfNeeded]cellForRowAtIndexPath不会为最初滚出的视图细胞起作用。

也不与它作序[cell setNeedsLayout]

你还有滚动某些细胞并重新进入视野,以便正常调整。

这是非常令人沮丧,因为大多数开发者有动态类型,自动版式和自调整大小细胞正常工作 - 除了这恼人的情况。 这个bug影响我所有的“高”表视图控制器。



Answer 4:

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

为什么会发生?

细胞设计故事板与一些宽度对于一些设备。 例如400像素。 例如你的标签具有相同的宽度。 当它从故事板加载它具有宽度400像素。

这里有一个问题:

tableView:heightForRowAtIndexPath:细胞布局之前调用它的子视图。

因此,计算标签和细胞宽度为400像素高度。 但是你用屏幕上的设备上运行,例如,320像素。 而这个自动计算高度不正确。 只是因为电池的layoutSubviews后,才发生tableView:heightForRowAtIndexPath:即使设置preferredMaxLayoutWidth为您的标签在手动layoutSubviews它不是帮助。

我的解决方案:

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 。 设置preferredMaxLayoutWidth手动为您的标签layoutSubviews 。 你也需要手动布局contentView ,因为它没有细胞框架的变化后,自动布局(我不知道为什么,但它是)

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


Answer 5:

我有一个类似的问题,在第一负载,未计算行高,但一些滚动后或去到另一个画面,我回到这个屏幕行计算。 在第一次加载我的项目是从互联网上下载,并在第二负载我的项目是从核心数据首先被加载,并从互联网重新加载和我注意到,行高,在从互联网上重装计算。 所以,我注意到,当tableView.reloadData()赛格瑞动画过程中被调用(用推和赛格瑞存在同样的问题),未计算行高。 所以我隐藏在视图初始化的实现代码如下,并把活动装载机,以防止一个丑陋的效果给用户,我叫tableView.reloadData 300毫秒后,现在的问题就解决了。 我认为这是一个错误的UIKit但这种解决方法使的伎俩。

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

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

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



Answer 6:

在我的情况下的UILabel的最后一行时被显示首次细胞被截断。 它发生相当随意地和大小的唯一方式是正确的滚动单元出来的观点,并把它带回来。 我尝试了所有显示到目前为止(layoutIfNeeded..reloadData)可能的解决方案,但没有为我工作。 诀窍是“自动收缩”设置为Minimuum字体比例 (0.5给我)。 试试看



Answer 7:

添加约束的表视图自定义单元格内的所有内容,然后估算表视图行的高度,并设置行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
}
}


Answer 8:

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

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

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



Answer 9:

设置preferredMaxLayoutWidth帮助我的情况。 我加

cell.detailLabel.preferredMaxLayoutWidth = cell.frame.width

在我的代码。

另请参阅单行文本发生在的UILabel两条线和http://openradar.appspot.com/17799811 。



Answer 10:

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

编辑:取消勾选大小班引起了很多关于故事板的问题,所以我尝试另一种解决方案。 我在视图控制器填充的tableView ViewDidLoadViewWillAppear的方法。 这解决了我的问题。



Answer 11:

对我来说,这些方法都没有工作,但我发现标签有一个明确的Preferred Width在Interface Builder中。 去除(取消选中“显性”),然后使用UITableViewAutomaticDimension发挥预期。



Answer 12:

调用cell.layoutIfNeeded()cellForRowAt工作对我来说iOS上的10和11的ios,但不能在iOS 9。

获得在iOS 9这项工作还可以,我叫cell.layoutSubviews()和它的伎俩。



Answer 13:

我有一个调整标签问题,所以我的东东只是做
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)

  }


Answer 14:

以我为例,我是在更新周期等。 所以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
     // }
}


Answer 15:

只要确保你没有设置在表视图“willdisplaycell”委托方法的标签文本。 设置“的cellForRowAtIndexPath”动态高度计算委托方法的标签文本。

别客气 :)



Answer 16:

- (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;


}

此代码可以帮助你发现在标签显示文本的动态高度。



Answer 17:

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

[self.tableView reloadData];

我曾尝试

[cell layoutIfNeeded];

但没有奏效。



Answer 18:

在斯威夫特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


Answer 19:

上述解决方案都没有工作,但下面的建议组合一样。

必须添加以下的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() 


Answer 20:

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



Answer 21:

我遇到了这个问题,并通过移动我的看法/标签初始化代码与固定它tableView(willDisplay cell:) TO tableView(cellForRowAt:)



Answer 22:

问题是,最初的细胞加载,我们有一个有效的行高之前。 解决方法是强制执行表重装视图出现时。

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


Answer 23:

以上解决方案的工作对我来说,什么工作是这个配方的魔力:给他们打电话顺序如下:

tableView.reloadData()
tableView.layoutIfNeeded() tableView.beginUpdates() tableView.endUpdates()

我的tableView数据从web服务填充,在我写上面的线路连接的回调。



文章来源: UITableView dynamic cell heights only correct after some scrolling