使用 SwiftUI 自定义底部工作表容器

问题描述 投票:0回答:1

我正在尝试创建一个自定义可扩展视图,类似于下面的 gif:

我正在尝试对容器使用偏移量,但是当内容可滚动(如 ScrollView 或 List 等)时,内容会出现问题,因为每个可滚动都会捕获拖动事件并在内部处理它们。

当子可滚动视图丰富其边缘角落时,有什么方法可以滚动父容器吗? 我看到了原生底部工作表在 SwiftUI 中的工作原理。这种滚动行为非常像我需要的,但我不能使用

sheet()
修饰符,因为它不是在 UI 范围内扩展,而是像单独的屏幕一样扩展。

swiftui scrollview swiftui-list swiftui-sheet
1个回答
0
投票

您可以将

.sheet()
presentationDetents
一起使用,如下例所示。 Sheet 高度根据内容进行调整,当底部 Sheet 的内容达到屏幕的 80% 时,就会开始滚动。您还可以与工作表后面和上方的内容进行交互,如本示例中使用打开和关闭按钮演示的那样,希望这可以解决您的疑问。

import SwiftUI

struct ContentView: View {
    
    @State private var isSheetOpen = true
    @State private var bottomSheetHeight: CGFloat = 0
    private var maxHeightBottomSheet = (UIScreen.main.bounds.height * 0.8)
    
    
    var body: some View {
        
        VStack {
            
            Button(action: {
                isSheetOpen = true
            } ) {
                Text("Open Sheet")
                    .frame(maxWidth: .infinity)
                    .foregroundColor(.black)
            }
            .frame(height: 50)
            .background(Color.white)
            .padding(.horizontal, 50)
            .padding(.top, 100)
            
            Button(action: {
                isSheetOpen = false
            } ) {
                Text("Close Sheet")
                    .frame(maxWidth: .infinity)
                    .foregroundColor(.black)
            }
            .frame(height: 50)
            .background(Color.white)
            .padding(.horizontal, 50)
            
            Spacer()
        }
        .background(Color.blue.edgesIgnoringSafeArea(.all))
        
        .sheet(isPresented: $isSheetOpen, content: {
            BottomSheet(height: $bottomSheetHeight)
                .presentationDetents([.height(min(bottomSheetHeight, maxHeightBottomSheet))])
                .shadow(color: .black, radius: 5)
        })
        .ignoresSafeArea(.all)
    }
}


struct BottomSheet: View {
    
    @Binding var height: CGFloat
    
    var body: some View {
        
        ScrollView {
            VStack(spacing: 0) {
                
                // Handle bar
                Rectangle()
                    .frame(width: 100, height: 6)
                    .cornerRadius(3.0)
                    .foregroundColor(Color.gray)
                    .padding(.top, 10)
                
                Rectangle()
                    .frame(height:  100)
                    .foregroundColor(.clear)
                Text("Drag down to close sheet")
                Text("BottomSheet")
                
                Rectangle()
                    .frame(height:  250)
                    .foregroundColor(.clear)
            }
            .background(.green)
            .readSize { calculatedHeight in
                height = calculatedHeight.height
            }
        }
    }
}


struct ContentView_Previews: PreviewProvider {
    static var previews: some View {
        ContentView()
    }
}


extension View {
    func readSize(onChange: @escaping (CGSize) -> Void) -> some View {
        background(
            GeometryReader { geometryProxy in
                Color.clear
                    .preference(key: SizePreferenceKey.self, value: geometryProxy.size)
            }
        )
        .onPreferenceChange(SizePreferenceKey.self, perform: onChange)
    }
}

struct SizePreferenceKey: PreferenceKey {
    static var defaultValue: CGSize = .zero
    static func reduce(value: inout CGSize, nextValue: () -> CGSize) {}
}
© www.soinside.com 2019 - 2024. All rights reserved.