UITableViewCell with intrinsic height based on width

被刻印的时光 ゝ 提交于 2021-01-29 15:39:44

问题


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.

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()
            }
        }

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

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?


回答1:


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



来源:https://stackoverflow.com/questions/65775159/uitableviewcell-with-intrinsic-height-based-on-width

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!