You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

求助:如何阻止滑动Bottom Sheet低于200pt的最小高度

解决方案

要解决这个问题,你得在手势的偏移计算里加范围限制,同时修复当前手势的偏移逻辑错误,下面是改好的完整代码:

public struct FloatingPanel: View {
    @State var offset: CGFloat = 200
    @State var isInitialOffsetSet: Bool = false
    // 新增:记录手势开始时的初始偏移量
    @State private var gestureStartOffset: CGFloat = 0
    // 定义最低面板高度
    private let minPanelHeight: CGFloat = 200
    
    public init() {}
    
    public var body: some View {
        GeometryReader { proxy in
            ZStack {
                Color.white
                    .clipShape(CustomCorner(corners: [.topLeft, .topRight], radius: 20))
                
                VStack {
                    Capsule()
                        .fill(Color.gray)
                        .frame(width: 60, height: 4)
                        .padding(.top, 5)
                    
                    NavigationView {
                        VStack {
                            Text("this is navigation content")
                        }
                        .background(Color.white)
                    }
                    .navigationViewStyle(.stack)
                    
                    Spacer()
                }
            }
        }
        .offset(y: offset)
        .gesture(
            DragGesture()
                // 手势开始时保存当前偏移量
                .onStart { _ in
                    gestureStartOffset = offset
                }
                .onChanged { value in
                    // 基于初始偏移量计算新的偏移
                    let newOffset = gestureStartOffset + value.translation.height
                    // 计算最大允许偏移:屏幕高度 - 最低面板高度,确保面板不会滑出屏幕
                    let maxOffset = UIScreen.main.bounds.height - minPanelHeight
                    // 限制偏移范围:最小可以到0(面板顶部对齐屏幕顶部),最大不超过maxOffset
                    offset = max(0, min(newOffset, maxOffset))
                    // 平滑动画
                    withAnimation(.easeInOut) {}
                }
        )
        .onAppear {
            if !isInitialOffsetSet {
                // 初始偏移:屏幕高度 - 250(初始面板高度250)
                offset = UIScreen.main.bounds.height - 250
                isInitialOffsetSet = true
            }
        }
        .ignoresSafeArea(.all, edges: .all)
    }
}

struct CustomCorner: Shape {
    var corners: UIRectCorner
    var radius: CGFloat

    func path(in rect: CGRect) -> Path {
        let path = UIBezierPath(roundedRect: rect, byRoundingCorners: corners, cornerRadii: CGSize(width: radius, height: radius))
        return Path(path.cgPath)
    }
}

关键修改点说明:

  • 修复手势偏移逻辑:新增gestureStartOffset变量,手势一开始就保存当前的offset,拖动时基于这个值加平移量,避免拖动时位置跳变。
  • 添加偏移范围限制:计算maxOffset为屏幕高度减去最低面板高度200,用max(0, min(newOffset, maxOffset))把offset限制在合理范围,确保面板滑到最底部时高度刚好200,不会超出屏幕;如果不想让面板滑到屏幕顶部,修改max里的0值即可。
  • 保持平滑动画:在拖动回调里加入withAnimation(.easeInOut),保证滑动过程的动画流畅自然。
  • 统一常量管理:把最低高度设为私有常量minPanelHeight,后续要调整数值直接改这个常量就行,方便维护。

这样修改后,你的Bottom Sheet就能保持最低200pt的高度,滑动时不会滑出屏幕,同时保留无吸附点的平滑动画效果。

内容的提问来源于stack exchange,提问作者drunkiosdeveloper

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.19 05:35:44