gpt4 book ai didi

iOS - 自定义 View : Intrinsic content size ignored after updated in layoutSubviews()

转载 作者:行者123 更新时间:2023-11-29 13:52:41 25 4
gpt4 key购买 nike

我有一个表格 View 单元格,其中包含一个自定义 View 以及其他 View ,并且使用了自动布局。

我的自定义 View 的目的是按行布置其 subview ,如果当前 subview 不适合当前行,则分成新行。它有点像多行标签,但有 View 。我通过精确定位而不是自动布局实现了这一点。

因为我只知道 layoutSubviews() 中 View 的宽度,所以我需要计算那里的确切位置和行数。这很有效,但由于缺少 intrinsicContentSize,我的 View 的框架(零)不匹配。

因此,如果我的高度自上次布局通过后发生变化,我会在计算的末尾添加一个检查。如果是这样,我会更新我的 intrinsicContentSize 属性中使用的高度属性并调用 invalidateIntrinsicContentSize()

我观察到最初 layoutSubviews() 被调用了两次。第一遍效果很好,即使单元格的宽度小于应有的宽度,也考虑了 intrinsicContentSize。第二遍使用实际宽度并更新 intrinsicContentSize。然而,父级(tableview 单元格中的 contentView)忽略了这个新的 intrinsicContentSize

所以基本上结果是 subview 的布局和绘制正确,但自定义 View 的框架未在父级中更新/使用。

问题:有没有办法通知父级有关内部尺寸的更改或指定位置更新 layoutSubviews() 中计算的尺寸,以便在父级中使用新尺寸?

编辑:

这是我的自定义 View 中的代码。

仅供引用:8 只是两个 subview 之间的垂直和水平空间

class WrapView : UIView {

var height = CGFloat.zero

override var intrinsicContentSize: CGSize {
CGSize(width: UIView.noIntrinsicMetric, height: height)
}

override func layoutSubviews() {
super.layoutSubviews()

guard frame.size.width != .zero else { return }

// Make subviews calc their size
subviews.forEach { $0.sizeToFit() }

// Check if there is enough space in a row to fit at least one view
guard subviews.map({ $0.frame.size.width }).max() ?? .zero <= frame.size.width else { return }

let width = frame.size.width
var row = [UIView]()

// rem is the remaining space in the current row
var rem = width
var y: CGFloat = .zero
var i = 0

while i < subviews.count {
let view = subviews[i]
let sizeNeeded = view.frame.size.width + (row.isEmpty ? 0 : 8)
let last = i == subviews.count - 1
let fit = rem >= sizeNeeded

if fit {
row.append(view)
rem -= sizeNeeded
i += 1
guard last else { continue }
}

let rowWidth = row.map { $0.frame.size.width + 8 }.reduce(-8, +)
var x = (width - rowWidth) * 0.5

for vw in row {
vw.frame.origin = CGPoint(x: x, y: y)
x += vw.frame.width + 8
}

y += row.map { $0.frame.size.height }.max()! + 8
rem = width
row = []
}

if height != y - 8 {
height = y - 8
invalidateIntrinsicContentSize()
}
}
}

最佳答案

经过大量的尝试和研究,我终于解决了这个错误。

正如@DonMag 在评论中提到的,直到新的布局通过时,单元格的新大小才被识别。这可以通过将显示正确布局的单元格滚动到屏幕外并返回来验证。不幸的是,触发新的传递比预期的要难,因为 .beginUpdates() + .endUpdates() 没有做这份工作。

无论如何,我没有找到触发它的方法,但我按照此 answer 中描述的说明进行操作.特别是用于高度计算的原型(prototype)单元格部分提供了一个可以在 tableview(heightForRowAt:) 中返回的值。

swift 5:

这是用于计算的代码:

let fitSize = CGSize(width: view.frame.size.width, height: .zero)
/* At this point populate the cell with the exact same data as the actual cell in the tableview */
cell.setNeedsUpdateConstraints()
cell.updateConstraintsIfNeeded()
cell.bounds = CGRect(x: .zero, y: .zero, width: view.frame.size.width, height: cell.bounds.height)
cell.setNeedsLayout()
cell.layoutIfNeeded()
height = headerCell.contentView.systemLayoutSizeFitting(fitSize).height + 1

在我的例子中,该值只计算一次并缓存,因为大小不再改变。

然后可以在委托(delegate)中返回值:

func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
indexPath.row == 0 ? height : UITableView.automaticDimension
}

我只用于第一个单元格,因为它是我的标题单元格并且只有一个部分。

关于iOS - 自定义 View : Intrinsic content size ignored after updated in layoutSubviews(),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/58857850/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com