Наблюдайте за изменениями кадров в SwiftUI - PullRequest
1 голос
/ 02 августа 2020

У меня есть представление, которое можно перетаскивать поверх других представлений (скажем, категорий). Чтобы определить, в каком представлении категории я нахожусь, я сохраняю их фреймы в массиве фреймов, что происходит в onAppear их невидимых оверлеев. (Это основано на реализации Пола Хадсона в этом учебнике.) на 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)
                        }
                }
            )
        }
    }
}

Поэтому любая идея, как обновить кадры в этих экземплярах или как по-другому их наблюдать, будет приветствоваться.

1 Ответ

1 голос
/ 03 августа 2020
• 1000 подход.

Введите модель для ключа предпочтения просмотра:

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
        }
    }

}
...