具有基于宽度的固有高度的 UITableViewCell [英] UITableViewCell with intrinsic height based on width

查看:21
本文介绍了具有基于宽度的固有高度的 UITableViewCell的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

所以我制作了自定义视图 ExpressionView 用于可视化数学表达式.表达式的每一部分都是 UILabel 保存一个数字或操作,并且标签在 ExpressionView 内以右对齐的行对齐.我希望 ExpressionView 的宽度由外部的自动布局约束定义,但高度应该是内在的,具体取决于我必须为给定宽度制作多少行标签.

So I have made custom view ExpressionView for visualizing mathematical expression. Every part of expression is UILabel holding one number or operation, and labels are aligned inside the ExpressionView in right-justified rows. I expect ExpressionView to have width defined by autolayout constraints from outside, but height should be intrinsic, depending on how many rows of labels I will have to make for a given width.

对齐方法效果很好,我使用每个标签的 frame.size 和 ExpressionView 的宽度,进行数学运算,设置标签的框架位置,并计算包含所有行所需的高度.我还定义了这些,以便在每次 ExpressionLabel 宽度更改时设置固有大小和重新布局标签:

The aligning methods works well, I use frame.size of each label and width of ExpressionView, do the math, set frame positions of labels, and count required height to contain all rows. I have also defined these, in order to set intrinsic size, and relayout labels every time width of ExpressionLabel changes:

        override var intrinsicContentSize: CGSize {
            let res = CGSize(width: UIView.noIntrinsicMetric,
                         height: CGFloat(self.contentHeight) //counted during self.layoutAllLabels()
            )

            return res
       }
       
        public override func layoutSubviews() {
            super.layoutSubviews() //finish layout to get current label sizes and self width 
            let preHeight = self.contentHeight
            self.layoutAllLabels() //layout all labels in current width, count required height
    
            //if required height changed, relayout everything
            if (preHeight != self.contentHeight) {
                self.invalidateIntrinsicContentSize()
                self.superview?.setNeedsLayout()
                self.superview?.layoutIfNeeded()
            }
        }

当 ExpressionLabel 通过普通 UIView 中的自动布局约束设置到位时,一切正常.但是当 ExpressionLabel 固定在 UITableViewCell 的 contentView 中时它会失败,我希望它定义单元格的高度.我的 UITableView 具有自动调整单元格大小所需的这些行

Everything works well when ExpressionLabel is set in place by autolayout constraints in normal UIViews. BUT it fails when ExpressionLabel is pinned inside UITableViewCell's contentView, and I expect it to define cell's height. My UITableView has these lines required for automatic cell sizing

        self.estimatedRowHeight = 50
        self.rowHeight = UITableView.automaticDimension

单个单元格的大小以某种方式发生并且通常是正确的,但通常也会给出无效的高度.它可能与单元重用有关(通过 dequeueReusableCells()),因为旧的高度可能保留在重用的单元中.但是为什么它们没有更新,什么时候它们应该在任何 ExpressionView.layoutSubviews() 调用中更新?在 UITableView 中创建时单元格是否不会自动布局?如果没有,在哪里进行标签布局,以便即使在 UITableView 中也能正确更新?当我知道最终的单元格宽度,并且可以根据它调整其子视图的固有高度时?

The sizing of individual cells somehow takes place and is usually correct, but often also gives invalid heights. It might have something to do with cell reusing (through dequeueReusableCells()), because old heights may remain in reused cells. But why they are not updated, when they should update in any ExpressionView.layoutSubviews() call? Is the cell NOT automatically layouted when created in UITableView? If not, where to do layouting of my labels so that it will update correctly even in UITableView? When I know final cell width, and can adjust its subview's intrinsic height according to it?

推荐答案

明白了!似乎通过调用单元格的 systemLayoutSizeFitting() 来从 UITableView 确定 autodimensioned UITableViewCell 的高度.在我的单元格类中,我覆盖了该方法,并在调用 super.systemLayoutSizeFitting() 之前调用 layoutIfNeeded() - 以获得正确的尺寸.这有效!也许我什至可以直接调用ExpressionView的排列方法,而不是通过layoutIfNeeded(),但我会保持原样.

Got it! It seems that height of autodimensioned UITableViewCell is determined from UITableView by calling systemLayoutSizeFitting() of the cell . In my cell class, I have overriden the method, and call layoutIfNeeded() before calling super.systemLayoutSizeFitting() - in order to have correct dimensions. And that works! Maybe I even could call the ExpressionView arranging method directly, not through layoutIfNeeded(), but I will leave it as it is.

这是我的单元格类中的覆盖:

This is the override in my cell class:

    override func systemLayoutSizeFitting(_ targetSize: CGSize, withHorizontalFittingPriority horizontalFittingPriority: UILayoutPriority, verticalFittingPriority: UILayoutPriority) -> CGSize {
        
        //force layout of all subviews including ExpressionView, which
        //updates ExpressionView's intrinsic height, and thus height of a cell
        self.setNeedsLayout()
        self.layoutIfNeeded() 
        
        //now intrinsic height is correct, so I can call super method
        return super.systemLayoutSizeFitting(targetSize, withHorizontalFittingPriority: horizontalFittingPriority, verticalFittingPriority: verticalFittingPriority)
    }

这篇关于具有基于宽度的固有高度的 UITableViewCell的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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