SwiftUI学习之PreferenceKey

在 SwiftUI 中,当某个视图包含多个子视图,并且这些子视图都设置了同一类型的 > PreferenceKey 时,父视图会自动将这些子视图的偏好值(Preference Values)
合并为一个单一的值,并向上传递给更上层的祖先视图

在 SwiftUI 中,数据通常通过向下传递(父 → 子)实现,例如使用 @State、@Binding 或 @Environment。但某些场景需要子视图向上传递数据,例如:
1、 获取子视图的尺寸或位置(如实现滚动视图跟踪元素位置)。
2、 收集多个子视图的信息(如动态调整父视图布局)。
3、 传递自定义状态(如子视图完成加载后通知父视图)。
PreferenceKey 提供了一种声明式的解决方案,无需直接引用子视图或管理复杂回调。

import SwiftUI

struct ContentView: View {
    @State private var text:String = "hellow world"
    var body: some View  {
        VStack{
            ChildView()
        }
        .onPreferenceChange(CustomMessageKey.self) { newValue in
            print(newValue)
        }
      
    }
    
  
}
// 示例:传递一个字符串数据
struct CustomMessageKey: PreferenceKey {
    // 默认值(必须实现)
    static var defaultValue: String = ""

    // 合并多个子视图传递的值(必须实现)
    static func reduce(value: inout String, nextValue: () -> String) {
        value = nextValue() // 这里取最后一个子视图的值
        // 若需要合并所有子视图的值,可改为:value += nextValue()
    }
}
struct ChildView: View {
    var body: some View {
        Text("我是子视图")
            // 发送数据(例如:固定字符串)
            .preference(key: CustomMessageKey.self, value: "Hello from Child!")
    }
}
  • 首先需要创建一个遵循 PreferenceKey 协议的类型,并实现两个必要方法:
  • 用 .preference(key:value:) 修饰符将数据附加到子视图发送数据给父视图
  • 通过 .onPreferenceChange(_:perform:) 在父视图中监听数据变化:

经常会使用NavigationView navigationTitle(_:)设置导航条标题, 修饰符本质上是通过 SwiftUI 内部的 PreferenceKey 机制将标题传递给 NavigationView。

struct ContentView: View {

    var body: some View  {
       
        NavigationView {
            Text("测试")
                .navigationTitle("text")
                .navigationBarTitleDisplayMode(.inline)
        }
        
    }

}
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容