swiftui - 如何使 SwiftUI 滚动视图缩小到内容?
问题描述
我有一个 SwiftUI GUI,其中有两个堆叠在一起的列表。每个列表都有可变数量的项目。我希望两个列表都缩小以适应它们的内容。
如果我在 ForEach 周围使用 VStack,那么简单的情况就可以工作(参见下面的示例)。底部附近有一个垫片,因此列表会像我预期的那样移动到窗口的顶部。
现在,有时列表很大,我想要滚动视图和最大高度,但我仍然希望列表在项目较少时缩小。但是一旦我添加了滚动视图,滚动视图就会开始占用它所能占用的所有空间。如果我给它分配一个最大值,那么它就不会缩小以适应它的内容了。
在下面的示例中(如所写),我得到了我想要的调整大小行为(没有最大大小)。如果我取消注释滚动视图,那么它会占用所有空间,如果我取消注释框架修饰符,它可以工作,但大小是固定的。
struct ContentView: View {
@State var List1: [String] = [ ]
@State var List2: [String] = [ ]
var body: some View {
VStack {
Button("1-5") {
List1=[ "1" ]
List2=[ "a", "b", "c", "d", "e" ]
}
Button("3-3") {
List1=[ "1", "2", "3" ]
List2=[ "a", "b", "c" ]
}
Button("5-1") {
List1=[ "1", "2", "3", "4", "5" ]
List2=[ "a" ]
}
//ScrollView {
VStack {
ForEach(List1.indices, id: \.self) { idx in
Text(List1[idx])
}
}
//}
//.frame(maxHeight: 40)
Text("middle")
VStack {
ForEach(List2.indices, id: \.self) { idx in
Text(List2[idx])
}
}
Spacer()
Text("last")
}
}
}
解决方案
您需要PreferenceKey
计算ScrollView
内容的大小。这里有一个getSize
可以帮助你的功能:
struct SizePreferenceKey: PreferenceKey {
static var defaultValue: CGSize = .zero
static func reduce(value: inout CGSize, nextValue: () -> CGSize) {
value = nextValue()
}
}
struct SizeModifier: ViewModifier {
private var sizeView: some View {
GeometryReader { geometry in
Color.clear.preference(key: SizePreferenceKey.self, value: geometry.size)
}
}
func body(content: Content) -> some View {
content.overlay(sizeView)
}
}
extension View {
func getSize(perform: @escaping (CGSize) -> ()) -> some View {
self
.modifier(SizeModifier())
.onPreferenceChange(SizePreferenceKey.self) {
perform($0)
}
}
}
您必须比较内容的高度(with getSize
)和高度ScrollView
(with GeometryReader
),并相应地设置框架:
struct SwiftUIView12: View {
@State private var items: [String] = ["One", "Two", "Three"]
@State private var scrollViewSize: CGSize = .zero
var body: some View {
GeometryReader { proxy in
ScrollView {
ForEach(items, id: \.self) { item in
Text(item)
.padding()
}
.frame(maxWidth: .infinity)
.getSize {scrollViewSize = $0}
}
.frame(height: scrollViewSize.height < proxy.size.height ? scrollViewSize.height : .none )
.background(Color.blue.opacity(0.2))
}
.navigationTitle("Test")
.toolbar {
Button("Many items") {
items = (1 ... 30).map { _ in String.random(length: 10) }
}
}
}
}
推荐阅读
- java - 将字符串转换为日期火花sql
- c++ - 试图以递归方式获取数组元素的总和
- java - javax.persistence 不包含在 Spring Data jpa 中吗?
- reactjs - 我收到错误超过最大更新深度。当组件在 componentWillUpdate 或 componentDidUpdate 中重复调用 setState 时,可能会发生这种情况
- php - 如何在 PHP 中访问 JSON 文件中的特定对象?
- docker - 如何从 pod 中查找 pod 终止原因?
- php - 从字符串中获取日期
- javascript - 成功登录后反应重定向,但页面在刷新之前不会更新
- php - 如何在多个条件下通过 5 次迭代增加变量值
- c - 这在 C ((TYPE){}) 中意味着什么。该片段取自: __typeof__ ( ((TYPE){}).MEMBER )