SwiftUI实现初始显示10%底部Sheet,点击/拖拽展开至75%
解决SwiftUI底部Sheet的拖拽与间隙问题
针对你需要实现**初始显示10%、展开至75%**的底部Sheet需求,以下是修复后的完整代码,同时解决拖拽失效和间隙问题:
核心修改点
- 用比例变量控制Sheet高度,替代原有的显示/隐藏状态
- 添加拖拽手势支持,实现拖拽调整+自动吸附逻辑
- 修复圆角与布局间隙,适配不同屏幕尺寸
完整代码
import SwiftUI struct HomeView: View { @Environment(\.managedObjectContext) var managedObjectContext @State private var sheetRatio: CGFloat = 0.1 // 初始显示屏幕10% private let minRatio: CGFloat = 0.1 private let maxRatio: CGFloat = 0.75 var body: some View { GeometryReader { geometry in ZStack { Color.purple .edgesIgnoringSafeArea(.all) VStack { Spacer() HalfScreenSheetView( sheetRatio: $sheetRatio, minRatio: minRatio, maxRatio: maxRatio ) .frame(height: geometry.size.height * sheetRatio) .transition(.move(edge: .bottom)) .animation(.easeInOut(duration: 0.3), value: sheetRatio) } } } } } struct HalfScreenSheetView: View { @Binding var sheetRatio: CGFloat let minRatio: CGFloat let maxRatio: CGFloat var body: some View { VStack(spacing: 0) { // 拖拽指示器(点击可切换展开/收起) Capsule() .fill(Color.gray.opacity(0.5)) .frame(width: 40, height: 6) .padding(.top, 8) .onTapGesture { sheetRatio = sheetRatio == minRatio ? maxRatio : minRatio } // Sheet内容区域 VStack { Text("Your Half-Screen Content Goes Here") .font(.headline) .padding() Spacer() Button("Close") { sheetRatio = 0 // 完全收起,也可改为minRatio保持10%显示 } .padding() } } .frame(maxWidth: .infinity, maxHeight: .infinity) .background(Color.white) .cornerRadius(20, corners: [.topLeft, .topRight]) .gesture(dragGesture) } // 拖拽手势逻辑 private var dragGesture: some Gesture { DragGesture() .onChanged { value in // 根据拖拽偏移调整比例:向上拖拽增加高度,向下减少 let heightDelta = value.translation.height / UIScreen.main.bounds.height sheetRatio = max(minRatio, min(maxRatio, sheetRatio - heightDelta)) } .onEnded { value in // 松手后自动吸附到最近状态 let velocityThreshold: CGFloat = 500 if value.predictedEndTranslation.height < -velocityThreshold { sheetRatio = maxRatio } else if value.predictedEndTranslation.height > velocityThreshold { sheetRatio = minRatio } else { let midRatio = (minRatio + maxRatio) / 2 sheetRatio = sheetRatio > midRatio ? maxRatio : minRatio } } } } // 扩展:给指定角落添加圆角 extension View { func cornerRadius(_ radius: CGFloat, corners: UIRectCorner) -> some View { clipShape(RoundedCorner(radius: radius, corners: corners)) } } struct RoundedCorner: Shape { var radius: CGFloat = .infinity var corners: UIRectCorner = .allCorners func path(in rect: CGRect) -> Path { let path = UIBezierPath(roundedRect: rect, byRoundingCorners: corners, cornerRadii: CGSize(width: radius, height: radius)) return Path(path.cgPath) } } // 预览 struct HomeView_Previews: PreviewProvider { static var previews: some View { HomeView() } }
问题修复说明
间隙问题解决
- 移除了原代码中错误的
padding(.top, UIScreen.main.bounds.height * 1)设置 - 使用自定义圆角扩展,仅给Sheet顶部两个角添加圆角,避免底部布局间隙
- 移除了原代码中错误的
拖拽功能实现
- 添加
DragGesture实时调整Sheet高度比例,限制在0.1-0.75范围内 - 松手时根据拖拽速度和当前位置,自动吸附到收起(10%)或展开(75%)状态
- 添加
交互优化
- 顶部添加拖拽指示器,点击可快速切换Sheet状态
- 动画绑定到比例变量,状态变化时触发平滑过渡
内容的提问来源于stack exchange,提问作者UmaiZ
相关产品推荐
相关产品推荐

