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

SwiftUI中onPreferenceChange未触发问题求助

问题原因与修复方案

你的代码核心问题是PreferenceKey的传递路径错误:Preference是从子视图向上传递到祖先视图的,只有祖先视图上的onPreferenceChange才能接收到子视图发送的Preference值。但你把监听Preference的titleByKey修饰符加在了Text组件上,而ChildView和Text是同级视图,ChildView的Preference无法传递到同级的Text修饰符中,导致onPreferenceChange完全不会触发。

修复步骤

1. 调整修饰符的位置

将titleByKey修饰符从Text移到包含Text和ChildView的VStack上,让监听Preference的视图成为ChildView的直接祖先:

struct MainView: View {
    @State var title: String = "DEF"
    
    var body: some View {
        VStack {
            Text(title)
                .padding()
                .font(.system(size: 20))
                .foregroundStyle(Color.black)
            ChildView()
        }
        .titleByKey(title: $title) // 移到VStack上
    }
}

2. 可选优化:完善PreferenceKey的reduce逻辑

原reduce方法会直接覆盖现有值,如果有多个子视图发送Preference,只会保留最后一个的值。可以添加非空判断,避免空字符串覆盖原有标题:

struct TitleChangePreferenceKey: PreferenceKey {
    static var defaultValue: String = ""
    
    static func reduce(value: inout String, nextValue: () -> String) {
        let newValue = nextValue()
        // 仅当新值非空时更新
        if !newValue.isEmpty {
            value = newValue
        }
    }
}

修复后效果

修改后,当你在ChildView的输入框中输入内容时,updateTitleByKey会发送新的Preference值,向上传递到VStack的titleByKey修饰符中,触发onPreferenceChange更新title状态,最终Text会同步显示输入的内容。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.22 06:31:16