简体   繁体   中英

In SwiftUI why can't I get an Anchor preference to work with a dictionary?

Can anyone tell me why the following code for publishing an anchor preference does not work:

Based on: https://swiftwithmajid.com/2020/03/18/anchor-preferences-in-swiftui/

enum MyPreferenceKeyType: Hashable {
    case firstBounds
    case secondBounds
}

struct MyPreferenceKey: PreferenceKey {
    typealias Value = [MyPreferenceKeyType: Anchor<CGRect>]
    static var defaultValue: Value { [:] }

    static func reduce(value: inout Value, nextValue: () -> Value) {
        value.merge(nextValue()) { $1 }
    }
}


// Publish an anchor preference like this
.anchorPreference(key: MyPreferenceKey.self, value: .bounds) {
    [MyPreferenceKeyType.firstBounds: $0]
}

In the above case the transform function is never called and the preference does not appear to be sent up the view hierarchy. However the following code works and the anchor preference is propagated up the view hierarchy:

struct MyPreferenceKey: PreferenceKey {
    typealias Value = Anchor<CGRect>?
    static var defaultValue: Value = nil

    static func reduce(value: inout Value, nextValue: () -> Value) {
        value = nextValue()
    }
}

// Publish an anchor preference like this
.anchorPreference(key: MyPreferenceKey.self, value: .bounds) {
    $0
}

Why is it that the transform closure is only called when there is nothing to transform?

Works fine. I assume the issue is in code that use this, so here is usage of your initial dictionary-based variant. Just for demo:

var body: some View {
    HStack {
        Text("Hello")
            .anchorPreference(key: MyPreferenceKey.self, value: .bounds) {
                [.firstBounds: $0]
            }
        Text("World")
    }
    .overlayPreferenceValue(MyPreferenceKey.self) { prefs in
        if let first = prefs[.firstBounds] {
            GeometryReader { gp in
                Rectangle()
                    .stroke(Color.red, lineWidth: 5)
                    .frame(width: gp[first].width, height: gp[first].height)
                    .position(x: gp[first].midX, y: gp[first].midY)
            }
        }
    }
}

演示

Tested with Xcode 13.4 / iOS 15.5

*if you add similarly for Text("World") and .secondBounds , you get for both

演示

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM