观察 SwiftUI 中的帧变化
Posted
技术标签:
【中文标题】观察 SwiftUI 中的帧变化【英文标题】:Observe frame changes in SwiftUI 【发布时间】:2020-08-02 20:25:07 【问题描述】:我有可以拖放到其他视图之上的视图(比如说类别)。为了检测我在哪个类别视图之上,我将它们的帧存储在一个帧数组中,这发生在它们的不可见叠加层的 onAppear 中。 (这是基于 this 教程中的 Paul Hudsons 实现)。
这一切都很好,除非这些视图的位置发生变化,例如在 iPad 上调整设备方向或窗口大小。这当然不会触发 onAppear,因此帧不再匹配。
HStack()
ForEach(categories) category in
ZStack
Circle()
Rectangle()
.foregroundColor(.clear)
.overlay(
GeometryReader geo in
Color.clear
.onAppear
categoryFrames[index(for: category)] = geo.frame(in: .global)
)
因此,欢迎任何想法如何更新这些实例中的帧或如何以不同的方式观察它们。
【问题讨论】:
不完全是,因为他们用 UIKit 实现了这一点,这对我来说不如纯 SwiftUI 理想。他们说 GeometryReader 应该可以,但没有解释如何。 【参考方案1】:可以在刷新期间使用视图首选项动态读取视图帧,因此您不必关心方向,因为每次重绘视图时都有实际帧。
这是一个方法草案。
为视图偏好键引入模型:
struct ItemRec: Equatable
let i: Int // item index
let p: CGRect // item position frame
struct ItemPositionsKey: PreferenceKey
typealias Value = [ItemRec]
static var defaultValue = Value()
static func reduce(value: inout Value, nextValue: () -> Value)
value.append(contentsOf: nextValue())
现在你的代码(假设@State private var categoryFrames = [Int, CGRect]()
)
HStack()
ForEach(categories) category in
ZStack
Circle()
Rectangle()
.foregroundColor(.clear)
.background( // << prefer background to avoid any side effect
GeometryReader geo in
Color.clear.preference(key: ItemPositionsKey.self,
value: [ItemRec(i: index(for: category), p: geo.frame(in: .global))])
)
.onPreferenceChange(ItemPositionsKey.self)
// actually you can use this listener at any this view hierarchy level
// and possibly use directly w/o categoryFrames state
for item in $0
categoryFrames[item.i] = item.p
【讨论】:
【参考方案2】:我遇到了类似的问题,这篇文章启发了我寻找解决方案。所以也许这对其他人有用。
只需像对onAppear
所做的那样分配给onChange
修饰符,并在geo.size
更改时将其设置为触发。
HStack()
ForEach(categories) category in
ZStack
Circle()
Rectangle()
.foregroundColor(.clear)
.overlay(
GeometryReader geo in
Color.clear
.onAppear
categoryFrames[index(for: category)] = geo.frame(in: .global)
.onChange(of: geo.size) _ in
categoryFrames[index(for: category)] = geo.frame(in: .global)
)
【讨论】:
以上是关于观察 SwiftUI 中的帧变化的主要内容,如果未能解决你的问题,请参考以下文章
SwiftUI 双向绑定到枚举案例中 ObservableObject 中的值