SwiftUI:将List放入ScrollView(获取List的内容高度)
SwiftUI: Put List into ScrollView (get List's content height)
我正在尝试将 List
放入 ScrollView
。
如果你想知道为什么,这是我的解释,如果不是 - 直接跳到代码段。我需要在我的 List
之上平滑缩放 header。为此,我应该将 header 和 List
都放在 ScrollView
上,然后使用滚动内容偏移来完成其余的工作。我还需要禁止 List
的 built-in 滚动,因为它已经在 ScrollView
上,并固定 List
的高度 - 所以滚动视图知道它的内容高度。效果很好,但 List
的高度有时(!)是错误的。
我不能使用 LazyVStack
而不是 List
- 它更慢(我猜没有单元格重用),而且 List
很大。它还打破了 NavigationLink
s,所以它出来了 - 它必须是 List
.
单元格的高度不固定,无法手动计算
这是我使用 UITableView
:
创建具有固定高度的不可滚动 List
的代码
struct AutosizingList<Content: View>: View {
@ViewBuilder var content: Content
@State private var tableContentHeight: CGFloat = 0
var body: some View {
List {
content
}
.introspectTableView { tableView in
tableView.isScrollEnabled = false
tableContentHeight = tableView.contentSize.height
}
.frame(height: tableContentHeight)
}
}
我想这个块并不总是在 didLayoutSubviews
之后调用,这就是为什么高度有时正确有时错误的原因。所以这是我的问题:如何可靠地获得 List
的身高?我可以在 SwiftUI 中使用类似于 didLayoutSubviews
的东西吗?
Table contentSize
是根据已经出现在屏幕上的单元格计算的。假设剩余单元格的大小与之前的单元格大小相同。
您可以看到滚动指示器在您滚动时如何变化:它可能会减少或增加,具体取决于新单元格的大小。在我的测试中,我使用依赖于索引的单元格高度来显示此行为。
反过来 introspectTableView
在创建视图时只调用一次:您可以检查 source code.
我建议你在这种情况下使用关键路径观察:
struct ContentView: View {
@State
private var observation: NSKeyValueObservation?
var body: some View {
List {
ForEach(0..<100) { i in
Text(String(i))
.frame(height: CGFloat(i))
}
}.introspectTableView { tableView in
print("initial size", tableView.contentSize)
observation = tableView.observe(\.contentSize) { tableView, value in
print("new size", tableView.contentSize)
}
}
}
}
我正在尝试将 List
放入 ScrollView
。
如果你想知道为什么,这是我的解释,如果不是 - 直接跳到代码段。我需要在我的 List
之上平滑缩放 header。为此,我应该将 header 和 List
都放在 ScrollView
上,然后使用滚动内容偏移来完成其余的工作。我还需要禁止 List
的 built-in 滚动,因为它已经在 ScrollView
上,并固定 List
的高度 - 所以滚动视图知道它的内容高度。效果很好,但 List
的高度有时(!)是错误的。
我不能使用 LazyVStack
而不是 List
- 它更慢(我猜没有单元格重用),而且 List
很大。它还打破了 NavigationLink
s,所以它出来了 - 它必须是 List
.
单元格的高度不固定,无法手动计算
这是我使用 UITableView
:
List
的代码
struct AutosizingList<Content: View>: View {
@ViewBuilder var content: Content
@State private var tableContentHeight: CGFloat = 0
var body: some View {
List {
content
}
.introspectTableView { tableView in
tableView.isScrollEnabled = false
tableContentHeight = tableView.contentSize.height
}
.frame(height: tableContentHeight)
}
}
我想这个块并不总是在 didLayoutSubviews
之后调用,这就是为什么高度有时正确有时错误的原因。所以这是我的问题:如何可靠地获得 List
的身高?我可以在 SwiftUI 中使用类似于 didLayoutSubviews
的东西吗?
Table contentSize
是根据已经出现在屏幕上的单元格计算的。假设剩余单元格的大小与之前的单元格大小相同。
您可以看到滚动指示器在您滚动时如何变化:它可能会减少或增加,具体取决于新单元格的大小。在我的测试中,我使用依赖于索引的单元格高度来显示此行为。
反过来 introspectTableView
在创建视图时只调用一次:您可以检查 source code.
我建议你在这种情况下使用关键路径观察:
struct ContentView: View {
@State
private var observation: NSKeyValueObservation?
var body: some View {
List {
ForEach(0..<100) { i in
Text(String(i))
.frame(height: CGFloat(i))
}
}.introspectTableView { tableView in
print("initial size", tableView.contentSize)
observation = tableView.observe(\.contentSize) { tableView, value in
print("new size", tableView.contentSize)
}
}
}
}