首页 > 解决方案 > 使 GeometryReader 适合抽屉内容

问题描述

我怎样才能适应GeometryReader中间的ExpandingDrawer内容?

(可复制和粘贴):

import SwiftUI

struct ExpandingDrawerButton: View {
    @Binding var isExpanded: Bool
    
    var body: some View {
        Button(action: { withAnimation { isExpanded.toggle() } }) {
            Text(isExpanded ? "Close" : "Open")
        }
    }
}

struct ExpandingDrawer<Content: View>: View {
    @Binding var isExpanded: Bool
    var content: () -> Content
    
    var body: some View {
        content()
            .frame(minWidth: 0, maxWidth: .infinity, minHeight: nil, maxHeight: contentHeight)
            .allowsHitTesting(isExpanded)
            .clipped()
            .transition(.slide)
    }
    
    private var contentHeight: CGFloat? {
        isExpanded ? nil : CGFloat(0)
    }
}

struct DrawerTestView_Previews: PreviewProvider {
    static var previews: some View {
        ContentView()
    }
    
    struct ContentView: View {
        @State var isExpanded = false
        
        var body: some View {
            GeometryReader { geo in
                VStack(spacing: 0) {
                    top
                        .frame(height: geo.size.height * 1/4)
                    middle
                    bottom
                        .frame(height: geo.size.width)
                }
            }
        }
        
        var top: some View {
            ZStack(alignment: Alignment(horizontal: .center, vertical: .bottom)) {
                Rectangle()
                    .foregroundColor(.blue.opacity(0.2))
                ExpandingDrawerButton(isExpanded: $isExpanded)
                    .padding()
            }
        }
        
        var middle: some View {
            ExpandingDrawer(isExpanded: $isExpanded) {
                middleContent
            }
        }
        
        var middleContent: some View {
            GeometryReader { geo in
                VStack {
                    ForEach(0..<10) { _ in
                        Button(action: {}) { Text("Random shit") }
                    }
                    Text("Don't know how tall...")
                    Text("Height can change...")
                    Text("But does need to fit snug (no extra space)")
                }
            }
        }
        
        var bottom: some View {
            ZStack {
                Rectangle()
                    .foregroundColor(.red)
                    .aspectRatio(1, contentMode: .fit)
                VStack {
                    Text("Needs to be a square...")
                    Text("Okay if pushed below edge of screen...")
                }
            }
        }
    }
}

我尝试了各种组合,.fixedSize().aspectRatio()我很挣扎......

标签: swiftswiftui

解决方案


为了避免GeometryReader改变我们的观点,我们可以把它放在一个.overlay().

例子:

struct ContentView: View {
    class Storage {
        var geo: GeometryProxy! {
            didSet {
                print(geo.size)
            }
        }
    }
    
    let storage = Storage()
    
    /* ... */
}
var middleContent: some View {
    VStack {
        ForEach(0..<10) { _ in
            Button(action: {}) { Text("Random stuff") }
        }
        Text("Don't know how tall...")
        Text("Height can change...")
        Text("But does need to fit snug (no extra space)")
    }
    .overlay(
        GeometryReader { geo in
            Rectangle()
                .fill(Color.clear)
            
            let _ = storage.geo = geo
        }
    )
}

您现在可以使用storage.geo来访问GeometryProxy此视图。


推荐阅读