我该如何使SwiftUI滚动视图自适应内容大小?

3

我有一个具有两个列表的SwiftUI GUI,这些列表堆叠在彼此上方。每个列表都有可变数量的项目。我希望两个列表都能缩小以适应它们的内容。

如果我在ForEach周围使用VStack,简单情况下可以实现(请参见下面的示例)。底部附近有一个间隔器,因此列表会像我所期望的那样移动到窗口的顶部。

现在,有时列表很大,我想要一个Scroll view和最大高度,但是当它的项较少时,我仍然希望列表缩小。但是,一旦我添加了Scroll view,Scroll view就开始占用所有可能的空间。如果我分配了一个最大值,那么它就不再缩小以适应其内容。

在下面的示例中(如所写),我得到了我想要的调整大小行为(没有最大尺寸)。如果我取消注释Scroll view,则它会占用所有空间;如果我取消注释frame modifier,则它可以工作,但大小是固定的。

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


1
这个回答解决了你的问题吗?https://dev59.com/ybroa4cB1Zd3GeqPiFXw#61185571 - undefined
1个回答

4
你需要使用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)
            }
    }
}

您需要比较您的内容高度(使用 getSize)和 ScrollView 的高度(使用 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) }
            }
        }
    }
}

enter image description here


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接