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

SwiftUI绘制路径时遇状态更新错误的解决方法咨询

问题解决:修复SwiftUI中"Modifying state during view update"错误

你遇到的错误是因为在GeometryReader内部直接修改@State变量——这会在视图渲染过程中触发状态更新,进而引发新一轮视图刷新,形成循环,导致系统抛出未定义行为的警告。

正确的做法是使用SwiftUI的PreferenceKey机制来安全传递布局尺寸信息,这是官方推荐的在视图间传递布局数据的方式,不会干扰视图更新流程。

修改步骤:

  1. 定义一个自定义PreferenceKey,用来存储视图的CGRect信息:
struct RectPreferenceKey: PreferenceKey {
    static var defaultValue: [String: CGRect] = [:]
    
    static func reduce(value: inout [String: CGRect], nextValue: () -> [String: CGRect]) {
        value.merge(nextValue()) { $1 }
    }
}
  1. 替换原来的GeometryReader逻辑,通过preference传递rect,而不是直接修改@State:
    Text部分的background修改为:
.background {
    GeometryReader { proxy in
        Color.clear
            .preference(key: RectPreferenceKey.self, value: ["title": proxy.frame(in: .named("root"))])
    }
}

Divider部分同理修改:

.background {
    GeometryReader { proxy in
        Color.clear
            .preference(key: RectPreferenceKey.self, value: ["divider": proxy.frame(in: .named("root"))])
    }
}
  1. 在父视图添加.onPreferenceChange来接收并更新状态:
    在ZStack的.coordinateSpace(name: "root")之前添加:
.onPreferenceChange(RectPreferenceKey.self) { preferences in
    titleRect = preferences["title"] ?? .zero
    dividerRect = preferences["divider"] ?? .zero
}

修改后的完整代码:

struct MyView: View {
    @State private var titleRect: CGRect = .zero
    @State private var dividerRect: CGRect = .zero
    
    struct RectPreferenceKey: PreferenceKey {
        static var defaultValue: [String: CGRect] = [:]
        
        static func reduce(value: inout [String: CGRect], nextValue: () -> [String: CGRect]) {
            value.merge(nextValue()) { $1 }
        }
    }
    
    var body: some View {
        ZStack {
            RoundedRectangle(cornerRadius: 25.0)
                .foregroundColor(.yellow)
            VStack {
                Text("Some fancy title …")
                    .border(.green)
                    .background {
                        GeometryReader { proxy in
                            Color.clear
                                .preference(key: RectPreferenceKey.self, value: ["title": proxy.frame(in: .named("root"))])
                        }
                    }
                Rectangle()
                    .frame(height: 20.0)
                    .foregroundColor(.clear)
                Rectangle()
                    .frame(height: 1.0)
                    .background {
                        GeometryReader { proxy in
                            Color.clear
                                .preference(key: RectPreferenceKey.self, value: ["divider": proxy.frame(in: .named("root"))])
                        }
                    }
                Spacer()
            }
            .padding(.top)
            
            Path { path in
                path.move(to: CGPoint(x: dividerRect.minX, y: titleRect.maxY))
                path.addLine(to: CGPoint(x: dividerRect.minX + dividerRect.width * 2/3, y: dividerRect.maxY))
                path.addLine(to: CGPoint(x: dividerRect.maxX, y: titleRect.maxY))
            }
            .stroke(.orange, lineWidth: 2) // 给Path添加橙色描边,匹配需求
        }
        .padding()
        .onPreferenceChange(RectPreferenceKey.self) { preferences in
            titleRect = preferences["title"] ?? .zero
            dividerRect = preferences["divider"] ?? .zero
        }
        .coordinateSpace(name: "root")
    }
}

额外说明:

  • PreferenceKey的reduce方法用来合并多个视图的偏好值,这里用字典通过key区分不同视图的rect。
  • 给Path添加.stroke(.orange)可以让橙色线条正常显示,符合你的需求。
  • 这种方式彻底避免了在视图渲染过程中直接修改状态,解决了"Modifying state during view update"的错误。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.07 14:18:09