UITableview部分-如何正确重新计算高度?

时间:2019-01-16 10:51:14

标签: ios uitableview autolayout kingfisher

视频:

https://youtu.be/sSHrxSIHUM4

您可以在视频中看到我遇到的问题。图像高度限制被破坏,也导致标签高度丢失。它们位于表视图部分(类UITableHeaderFooter)中。我用automaticDimension来计算它的高度,结果得到了纠正。

这是图像视图约束。 (默认的高度限制为184,要在运行时根据比例进行更新。)

https://uphinhnhanh.com/image/SAezyz

标签约束:

https://uphinhnhanh.com/image/SAeT5Y

我致电table reload重新配置横断面图数据和高度然后下载图像后,发生了问题。我收到打破约束警告。 Xcode打破了导致此问题的imageview高度限制。

(
    "<NSLayoutConstraint:0x2807252c0 UIImageView:0x109c002d0.height == 735.885   (active)>",
    "<NSLayoutConstraint:0x280727160 UIImageView:0x109c007f0.height == 40   (active)>",
    "<NSLayoutConstraint:0x280715900 UIView:0x109c00d10.height == 51   (active)>",
    "<NSLayoutConstraint:0x2807140f0 UILayoutGuide:0x281d7e680'UIViewSafeAreaLayoutGuide'.bottom == UIView:0x109c00d10.bottom   (active)>",
    "<NSLayoutConstraint:0x2807174d0 V:|-(11)-[UIImageView:0x109c007f0]   (active, names: '|':engie_up.PostDetailHeaderView:0x109c00000 )>",
    "<NSLayoutConstraint:0x280717c50 V:[UIImageView:0x109c007f0]-(18.5)-[engie_up.KwExpandableContextLabel:0x10491c600'bfbfnff']   (active)>",
    "<NSLayoutConstraint:0x280715130 V:[engie_up.KwExpandableContextLabel:0x10491c600'bfbfnff']-(18)-[UIImageView:0x109c002d0]   (active)>",
    "<NSLayoutConstraint:0x280714fa0 V:[UIImageView:0x109c002d0]-(0)-[UIView:0x109c00d10]   (active)>",
    "<NSLayoutConstraint:0x28072ad00 'UIView-Encapsulated-Layout-Height' engie_up.PostDetailHeaderView:0x109c00000.height == 343   (active)>",
    "<NSLayoutConstraint:0x2807179d0 'UIViewSafeAreaLayoutGuide-bottom' V:[UILayoutGuide:0x281d7e680'UIViewSafeAreaLayoutGuide']-(0)-|   (active, names: '|':engie_up.PostDetailHeaderView:0x109c00000 )>"
)

Will attempt to recover by breaking constraint 
<NSLayoutConstraint:0x2807252c0 UIImageView:0x109c002d0.height == 735.885   (active)>

我注意到'UIView-Encapsulated-Layout-Height'是估算高度。

由于我使用翠鸟,因此获取代码很简单

let ratio = CGFloat(image.width) / CGFloat(image.height)
userContentImageViewHeightConstraint.constant = CGFloat((UIScreen.main.bounds.width) / ratio)
self.userContentImageView.kf.indicatorType = .activity
self.userContentImageView.kf.setImage(with: URL(string: image.url), completionHandler: { (_, _, _, _) in
     self.setNeedsLayout()
     self.layoutIfNeeded()
     })

所以我想问一下如何解决约束破裂问题?

谢谢。

2 个答案:

答案 0 :(得分:-1)

更新:我删除了图像高度限制,并添加了宽高比限制,现在中断消失了,但是在视频中得到了相同的结果

        let ratio = CGFloat(image.width) / CGFloat(image.height)
        let constraint = NSLayoutConstraint(item: self.userContentImageView,
                                            attribute: NSLayoutConstraint.Attribute.width,
                                            relatedBy: NSLayoutConstraint.Relation.equal,
                                            toItem: self.userContentImageView,
                                            attribute: NSLayoutConstraint.Attribute.height,
                                            multiplier: ratio,
                                            constant: 0.0)
        constraint.priority = 999
        self.userContentImageViewAspectConstraint = constraint

更新2:2019年1月18日

最后,我找到了问题的根本原因。 我没有注意到底部视图的底部约束与“安全区域布局”保持一致。首先,这导致视图在选项卡栏上方被拉起,并产生了额外的空间并破坏了图像约束的高度(其优先级为999)。我将其更改为与超级视图对齐,然后问题消失了。

答案 1 :(得分:-1)

我再次检查了您随附的屏幕截图。一切对我来说都很好。现在我仍然在这里猜测。通常,当发生此类约束警告时,即使花了我很多时间,我也会解决。很高兴您已经有了数据图像的大小。

从这段代码中:

self.userContentImageView.kf.setImage(with: URL(string: image.url), completionHandler: { (_, _, _, _) in
     self.setNeedsLayout()
     self.layoutIfNeeded()
     })

这很丑陋,并且肯定会产生闪烁或不想要的动画/运动错误,就像在视频演示中一样。

通常,对我来说,self.layoutIfNeeded()足以在调整任何视图的约束之后调整布局。

因此您的代码块可以转换为:

let ratio = CGFloat(image.width) / CGFloat(image.height)
userContentImageViewHeightConstraint.constant = CGFloat((UIScreen.main.bounds.width) / ratio)
self.layoutIfNeeded()
self.userContentImageView.kf.indicatorType = .activity
self.userContentImageView.kf.setImage(with: URL(string: image.url), completionHandler: { (_, _, _, _) in })

还更好,(我意识到这是在您的牢房内):

在返回cellForRow中的单元格之前,请先调整约束!之前我有一个个人项目,其流程/逻辑与您相同-带有网络呼叫的随机图像大小。

func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        self.feedCell = tableView.dequeueReusableCell(withIdentifier: self.feedCell.identifier)
            as! FeedTableViewCell
        self.feedCell.indexPath = indexPath
        self.feedCell.delegate = self

        let post = self.catPosts[indexPath.row]
        self.feedCell.post = post

        let aspectRatio = self.feedCell.getAspectRatioAccordingToiPhones(cellImageFrame: self.feedCell.frame.size, media: post.media!.first!)
        self.feedCell.constraint_PostHeight?.update(offset: aspectRatio)

        return self.feedCell
    }

在我的单元格中,我有getAspectRadio....方法:

func getAspectRatioAccordingToiPhones(cellImageFrame: CGSize, media: Media) -> CGFloat {

        guard let widthNumber = NumberFormatter().number(from: catMedia.width!),
            let heightNumber = NumberFormatter().number(from: catMedia.height!) else {
            return UIScreen.main.bounds.width
        }

        let imageWidth = CGFloat(truncating: widthNumber)
        let imageHeight = CGFloat(truncating: heightNumber)

        let widthOffset = imageWidth - cellImageFrame.width
        let widthOffsetPercentage = (widthOffset * 100) / imageWidth
        let heightOffset = (widthOffsetPercentage * imageHeight) / 100
        let effectiveHeight = imageHeight - heightOffset
        return effectiveHeight
    }

希望现在对您有所帮助:)祝您好运!