Use of PreferenceKey/preference key, GeometryPreferenceKey/geometry view preference key, ScrollViewOffsetPreferenceKey/scroll view offset preference key

1. Basic use of PreferenceKey preference key

  1.1 Create the basic usage view of the preference key PreferenceKeyBootcamp.swift

import SwiftUI

/// 偏好/首选项键
struct PreferenceKeyBootcamp: View {
    @State private var text: String  = "Hello, world!"
    
    var body: some View {
        NavigationView {
            VStack {
                SecondaryScreen(text: text)
                    .navigationTitle("Navigation Title")
            }
        }
        .onPreferenceChange(CustomTitlePreferenceKey.self) { value in
            if !value.isEmpty {
                self.text = value
            }
        }
    }
}

extension View{
    /// 自定义标题
    func customTitle(_ text: String) -> some View {
        preference(key: CustomTitlePreferenceKey.self, value: text)
    }
}

/// 辅助屏幕
struct SecondaryScreen: View{
    let text: String
    @State private var newValue: String = ""
    
    init(text: String) {
        self.text = text
    }
    
    var body: some View{
        Text(text)
            .onAppear {
                getDataFromDatabase()
            }
            .customTitle(newValue)
    }
    
    private func getDataFromDatabase(){
        // 模拟数据
        DispatchQueue.main.asyncAfter(deadline: .now() + 2.0) {
            self.newValue = "NEW value from database"
        }
    }
}

/// 自定义标题首选项键
struct CustomTitlePreferenceKey: PreferenceKey{
    static var defaultValue: String = ""
    // 换算
    static func reduce(value: inout String, nextValue: () -> String) {
        value = nextValue()
    }
}

struct PreferenceKeyBootcamp_Previews: PreviewProvider {
    static var previews: some View {
        PreferenceKeyBootcamp()
    }
}

  1.2 Rendering:

2. GeometryPreferenceKey Geometry view preference key is used to obtain the view size and set other view sizes.

  2.1 Create geometry view preference key view GeometryPreferenceKeyBootcamp.swift

import SwiftUI

/// 几何视图 首选项/偏好键 来获取视图大小设置其他视图大小
struct GeometryPreferenceKeyBootcamp: View {
    @State private var rectSize: CGSize = .zero
    
    var body: some View {
        VStack {
            // 根据几何阅读器和偏好设置键 获取其他 View 大小参数,设置到此 View 的大小
            Text("Hello, world!")
                .frame(width: rectSize.width, height: rectSize.height)
                .background(Color.blue)
            //Spacer()
            HStack {
                Rectangle()
                // 几何阅读器
                GeometryReader { geo in
                    Rectangle()
                        .updateRectangleGeoSize(geo.size)
                }
                Rectangle()
            }
            .frame(height: 55)
        }
        .onPreferenceChange(RectangleGeometrySizePreferenceKey.self) { value in
            self.rectSize = value
        }
    }
}

extension View{
    /// 更新值
    func updateRectangleGeoSize(_ size: CGSize) -> some View{
        preference(key: RectangleGeometrySizePreferenceKey.self, value: size)
    }
}

/// 矩形几何大小偏好键
struct RectangleGeometrySizePreferenceKey: PreferenceKey{
    static var defaultValue: CGSize = .zero
    //减少 下一个
    static func reduce(value: inout CGSize, nextValue: () -> CGSize) {
        value = nextValue()
    }
   
}

struct GeometryPreferenceKeyBootcamp_Previews: PreviewProvider {
    static var previews: some View {
        GeometryPreferenceKeyBootcamp()
    }
}

  2.2 Rendering:

3. ScrollViewOffsetPreferenceKey uses the scroll view offset setting preference key to update the title.

  3.1 Create the scroll offset preference key view ScrollViewOffsetPreferenceKeyBootcamp.swift

import SwiftUI

/// 首选项 / 偏好键
struct ScrollViewOffsetPreferenceKey: PreferenceKey{
    static var defaultValue: CGFloat = 0
    
    static func reduce(value: inout CGFloat, nextValue: () -> CGFloat) {
        value = nextValue()
    }
}

extension View{
    
    func onScrollViewOffsetChange(action: @escaping (_ offset: CGFloat) -> Void) -> some View{
        background(
            GeometryReader { geo in
                Text("")
                    .preference(key: ScrollViewOffsetPreferenceKey.self, value: geo.frame(in: .global).minY)
            }
        )
        .onPreferenceChange(ScrollViewOffsetPreferenceKey.self) { value in
            action(value)
        }
    }
}

/// 滚动视图偏移首选项/偏好键
struct ScrollViewOffsetPreferenceKeyBootcamp: View {
    let title: String  = "New title here!!!"
    @State private var scrollViewOffset: CGFloat = 0
    
    var body: some View {
        ScrollView {
            VStack {
                titleLayer.opacity(Double(scrollViewOffset / 75.0))
                    .onScrollViewOffsetChange { value in
                        self.scrollViewOffset = value
                    }
                contentLayer
            }
            .padding()
        }
        .overlay(Text("\(scrollViewOffset)"))
        .overlay(navBarLayer.opacity(scrollViewOffset < 52 ? 1.0 : 0.0), alignment: .top)
    }
}

/// 扩展类
extension ScrollViewOffsetPreferenceKeyBootcamp{
    /// 文本布局
    private var titleLayer: some View{
        Text(title)
            .font(.largeTitle)
            .fontWeight(.semibold)
            .frame(maxWidth: .infinity, alignment: .leading)
    }
    
    /// 内容布局
    private var contentLayer: some View{
        ForEach(0 ..< 30) { _ in
            RoundedRectangle(cornerRadius: 10)
                .fill(Color.orange.opacity(0.3))
                .frame(width: 300, height: 200)
        }
    }
    
    /// 导航栏布局
    private var navBarLayer: some View{
        Text(title)
            .font(.headline)
            .frame(maxWidth: .infinity)
            .frame(height: 55)
            .background(Color.accentColor)
    }
}

struct ScrollViewOffsetPreferenceKeyBootcamp_Previews: PreviewProvider {
    static var previews: some View {
        ScrollViewOffsetPreferenceKeyBootcamp()
    }
}

  3.2 Rendering:

Guess you like

Origin blog.csdn.net/u011193452/article/details/133795780