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

SwiftUI DragGesture拖动致应用冻结CPU占100%问题求解

问题根因

左右拖拽时应用冻结、CPU占用100%是无限布局重绘死循环导致,触发逻辑如下:

  • 拖拽位移计算逻辑错误:DragGesture的value.translation是手势从按下开始的累计总位移,不是相邻两次回调的增量位移,直接在原有width基础上累加总位移本身就会导致宽度计算异常
  • 布局依赖形成闭环:拖拽把手(显示冒号的Text)放在ZStack的bottomTrailing对齐位,ZStack宽度绑定width状态,width变化时把手会自动跟随ZStack的右侧边移动;而DragGesture的位移基于父视图坐标计算,哪怕手指按住不动,把手自身移动也会被识别为新的拖拽位移,触发onChanged再次修改width,直接形成「改宽度→把手位移→触发新拖拽→再改宽度」的死循环
  • 显示宽度数值的Text直接绑定width设置frame,width变化时文本内容、布局尺寸同时刷新,进一步放大了布局连锁反应
问题复现代码
struct TestView2 : View {
    @State private var width : CGFloat = 400.0
        
    var body : some View {
        VStack {
            ZStack(alignment: .bottomTrailing) {
                    
                Text("\(width)")
                    .frame(width: width)
                Text(":")
                    .frame(width: 10, height: 30)
                    .background(.bar)
                    .gesture(
                        DragGesture()
                            .onChanged { value in  
                                width = max(100, width + value.translation.width)
                                print(width)
                            }
                    )
            }
            .frame(width: width, height: 30, alignment: .topLeading)
            .border(.gray, width: 1)
            .background(.green)
        }
        .frame(maxWidth: .infinity, maxHeight: .infinity, alignment: .topLeading)
    }
}
修复方案

核心修改逻辑:

  • 拖拽开始时记录初始宽度,用「初始宽度+手势总位移」直接计算当前宽度,不要做累加操作
  • 拖拽结束后重置初始宽度标记,避免下次拖拽计算异常
  • 解除显示文本和可变宽度的强frame绑定,避免不必要的布局连锁刷新

修复后可正常运行的代码:

struct TestView2 : View {
    @State private var width : CGFloat = 400.0
    // 记录拖拽触发时的初始宽度
    @State private var dragStartWidth: CGFloat = 0
        
    var body : some View {
        VStack {
            ZStack(alignment: .bottomTrailing) {
                Text("\(width)")
                    .padding(.horizontal)
                    .frame(maxWidth: .infinity, alignment: .leading)
                Text(":")
                    .frame(width: 10, height: 30)
                    .background(.bar)
                    .gesture(
                        DragGesture()
                            .onChanged { value in
                                // 首次触发回调时记录起始宽度
                                if dragStartWidth == 0 {
                                    dragStartWidth = width
                                }
                                // 基于初始宽度计算当前宽度,设置最小宽度限制
                                width = max(100, dragStartWidth + value.translation.width)
                            }
                            .onEnded { _ in
                                // 拖拽结束重置标记
                                dragStartWidth = 0
                            }
                    )
            }
            .frame(width: width, height: 30, alignment: .topLeading)
            .border(.gray, width: 1)
            .background(.green)
        }
        .frame(maxWidth: .infinity, maxHeight: .infinity, alignment: .topLeading)
    }
}
参考截图

拖拽调整尺寸运行效果
调试器100%CPU异常状态

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.30 17:27:22