如何使 SwiftUI 滚动视图缩小到内容?

Posted

技术标签:

【中文标题】如何使 SwiftUI 滚动视图缩小到内容?【英文标题】:How do I make a SwiftUI Scroll view shrink-to-content? 【发布时间】:2021-08-19 04:21:21 【问题描述】:

我有一个 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")
        
    


【问题讨论】:

这是否回答了您的问题***.com/a/61185571/12299030? 【参考方案1】:

您需要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) 
            
        
    

【讨论】:

以上是关于如何使 SwiftUI 滚动视图缩小到内容?的主要内容,如果未能解决你的问题,请参考以下文章

如何在 SwiftUI 中查找滚动视图内容是不是已到达内容的末尾

使 ScrollView 中的滚动条在 SwiftUI 中始终可见

SwiftUI当总内容宽度小于屏幕宽度时,如何在动态水平滚动视图中居中内容

SwiftUI:如何让滚动视图包含完整列表长度

SwiftUI:将列表添加到带有上方图标的滚动视图中

如何滚动滚动视图以使 TextField 在 SwiftUI 中移动到键盘上方?