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

SwiftUI拖拽手势导致模拟器崩溃问题求助

SwiftUI下拉视图拖拽手势冻结崩溃问题解析

问题现象

为下拉通知视图添加向上拖拽关闭功能时,执行拖拽手势后视图仅移动小段就冻结,进而导致模拟器卡死、Xcode崩溃,但相同逻辑在卡片滑动视图上可正常运行。

核心问题分析

  1. 手势绑定对象错误
    原代码将拖拽手势绑定在底部的小圆角矩形上,而offset状态却作用在整个通知视图容器上。当拖拽小矩形时,视图因offset变化发生位移,导致手势的坐标参考系不断变动,触发高频的视图重绘与状态更新,最终引发渲染死循环。

  2. Offset状态计算逻辑缺陷
    onChanged中直接将offset设为gesture.translation,未考虑视图当前的偏移位置。当视图已偏移后,后续的拖拽偏移会出现计算叠加错误,导致状态异常,加剧渲染压力。

  3. 状态切换条件不合理
    modifyState中判断拖拽范围的区间-600...(-100)过大,且未限制offset的最大值,可能导致视图偏移超出预期范围,进一步加重渲染负担。

修复后的代码

import SwiftUI

struct MessagesHomeView: View {
    @State private var offset = CGSize.zero
    @State var showNotifications: Bool = false
        
    var body: some View {
        VStack {
            Button {
                withAnimation(.easeInOut){
                    showNotifications.toggle()
                }
            } label: {
                Image(systemName: "bell").font(.title)
            }
        }
        .overlay {
            VStack {
                if showNotifications {
                    ZStack {
                        Color(UIColor.darkGray)
                        VStack(alignment: .leading){
                            Text("Notifications").font(.title3).foregroundColor(.white)
                            Spacer()
                        }.padding(10).padding(.top, 70)
                        VStack {
                            Spacer()
                            RoundedRectangle(cornerRadius: 10)
                                .frame(width: 90, height: 9)
                                .foregroundColor(.white)
                        }.padding(.bottom, 4)
                    }
                    .frame(height: 500)
                    .transition(AnyTransition.move(edge: .top).combined(with: .opacity))
                    .cornerRadius(10, corners: [.bottomLeft, .bottomRight])
                    .offset(y: offset.height)
                    // 将手势绑定到整个通知视图容器
                    .gesture(
                        DragGesture()
                            .onChanged { gesture in
                                // 限制仅向上拖拽,且偏移不超过视图高度
                                let newOffset = gesture.translation.height + offset.height
                                if newOffset < 0 {
                                    offset.height = max(newOffset, -500)
                                }
                            }
                            .onEnded { _ in
                                withAnimation(.easeInOut){
                                    modifyState()
                                }
                            }
                    )
                    Spacer()
                }
            }.ignoresSafeArea()
        }
    }
    
    func modifyState(){
        switch offset.height {
        case -100...(-500):
            showNotifications = false
            offset = .zero
        default:
            offset = .zero
        }
    }
}

关键修改点

  • 将拖拽手势从底部小矩形移至整个通知视图容器,确保手势坐标参考系稳定
  • 调整offset计算逻辑,基于当前偏移累加拖拽位移,并限制最大向上偏移为视图高度(500),避免过度偏移
  • 优化状态切换的区间判断,匹配实际视图高度,确保状态切换逻辑精准

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.11 12:17:34