.reportWidth() ...

ไธป่ฆๅŠŸ่ƒฝ

  • view.reportWidth(to: key) ๅ›žๅ ฑ่‡ชๅทฑ็š„ๅฏฌๅบฆ (geometry.size.width) ็ตฆ key (PreferenceKey)ใ€‚

  • view.reportFrame(to: key, in: space) ๅ›žๅ ฑ่‡ชๅทฑ็š„ geometry.frame(in: space) ็ตฆ keyใ€‚

import SwiftUI

// ๐ŸŒ€View + pref (generic methods)
extension View {
    
    // โญ๏ธ ๅ›žๅ ฑ GeometryProxy ็š„ๅฑฌๆ€ง็ตฆ `key`
    //    - view.report(to: key) { $0.size }
    public func report<K: PreferenceKey>(
        
        // ่ฆๅ›žๅ ฑ็š„ๅฐ่ฑก (PreferenceKey)
        to key: K.Type = K.self,
        
        // ่ฆๅ›žๅ ฑ GeometryProxy ็š„ๅ“ชๅ€‹ๅฑฌๆ€ง๏ผŸ
        // โš ๏ธ ๆณจๆ„๏ผš
        //    ้€™่ฃก็š„ `value` closure ๅฟ…้ ˆๆจ™่จป็‚บ `@escaping`๏ผŒ
        //    ๅ› ็‚บๅฎƒ็”จๅœจ GeometryReader ็š„ @ViewBuilder closure ่ฃก้ข๏ผŒ
        //    ่€Œ้€™ๅ€‹ closure ๆœฌ่บซๅฐฑๆ˜ฏ `@escaping`๏ผŒๆ‰€ไปฅๅฆ‚ๆžœๆฒ’ๆœ‰ๆจ™่จป็š„่ฉฑ๏ผŒ
        //    ๆœƒ็”ข็”Ÿ "escaping closure captures non-escaping parameter" ็š„้Œฏ่ชค โ€ผ๏ธ
        value : @escaping (GeometryProxy) -> K.Value
        
    ) -> some View {
        self
            // โญ๏ธ 1. read self's geometry
            .background(GeometryReader { geo in  
                Color.clear
                    // โญ๏ธ 2. set preference:
                    //       report geo's attribute to `key`
                    .preference(key: key, value: value(geo))
            })
    }
    
    // view.register(to: key) { $0.frame(in: space) } 
    // T๏ผšๆ”ถ้›†็š„ๅ€‹ๅˆฅ่ณ‡ๆ–™ๅž‹ๅˆฅ
    // K๏ผšPreferenceKey, K.Value == [T]
    public func register<T, K: PreferenceKey>(
        to key: K.Type = K.self, 
        value : @escaping (GeometryProxy) -> K.Value.Element
    ) -> some View 
        where K.Value == Array<T>  // โญ๏ธ ๆ”ถ้›†ๅˆฐ K.Value == [T]
    {
        self
            // โญ๏ธ 1. read self's geometry
            .background(GeometryReader { geo in  
                Color.clear
                    // โญ๏ธ 2. set preference:
                    //       (register geo's value to `key`)
                    .preference(key: key, value: [value(geo)])
            })
    }
    
}

// specialized methods
extension View {
    
    // report width
    // view.reportWidth(to: key)
    public func reportWidth<K: PreferenceKey>(
        to key: K.Type = K.self
    ) -> some View 
        where K.Value == CGFloat? 
    { 
        self.report(to: key) { $0.size.width } 
    }
    
    // report frame
    // view.reportFrame(to: key, in: space)
    public func reportFrame<K: PreferenceKey>(
        to key: K.Type = K.self, 
        in  space: CoordinateSpace = .global
    ) -> some View 
        where K.Value == CGRect? 
    { 
        self.report(to: key) { $0.frame(in: space) } 
    }
    
    // register frame
    // view.registerFrame(to: key, in space)
    public func registerFrame<K: PreferenceKey>(
        to key: K.Type = K.self, 
        in  space: CoordinateSpace = .global
    ) -> some View 
        where K.Value == [CGRect]
    { 
        self.register(to: key) { $0.frame(in: space) } 
    }
    
}

Last updated