我正在尝试创建一个自定义可扩展视图,类似于下面的 gif:
我正在尝试对容器使用偏移量,但是当内容可滚动(如 ScrollView 或 List 等)时,内容会出现问题,因为每个可滚动都会捕获拖动事件并在内部处理它们。
当子可滚动视图丰富其边缘角落时,有什么方法可以滚动父容器吗? 我看到了原生底部工作表在 SwiftUI 中的工作原理。这种滚动行为非常像我需要的,但我不能使用
sheet()
修饰符,因为它不是在 UI 范围内扩展,而是像单独的屏幕一样扩展。
您可以将
.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) {}
}