.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) }
}
}
import SwiftUI
// 🌀View + anchor preference (generic methods)
extension View {
// view.register(to: FrameAnchors.self)
public func register<K: PreferenceKey>(to key: K.Type = K.self) -> some View
where K.Value == [Anchor<CGRect>]
{
self.anchorPreference(key: K.self, value: .bounds) { [$0] }
}
// view.overlay(with: FrameAnchors.self) { anchors in ... }
public func overlay<K: PreferenceKey, T: View>(
with key: K.Type = K.self,
transform: @escaping (K.Value) -> T
) -> some View
where K.Value == [Anchor<CGRect>]
{
overlayPreferenceValue(key) { transform($0) }
}
}
Last updated
Was this helpful?