Mane Manero
Mane Manero

Reputation: 3788

SwiftUI: Path .anchorPreference

I am trying to set a SwiftUI Path .anchorPreference to center.

I have looked at many examples on SO, but could not make it work. Apple documentation on this is zero.

import SwiftUI

struct PatternScene: View {

    let pattern = Path { path in
        path.move(to: CGPoint(x: 50, y: 50))
        path.addLine(to: CGPoint(x: 250, y: 50))
        path.addLine(to: CGPoint(x: 250, y: 250))
        path.addLine(to: CGPoint(x: 50, y: 250))
        path.addLine(to: CGPoint(x: 100, y: 100))
    }

    var body: some View {
        self.pattern
            .frame(minWidth: 0, maxWidth: .infinity, minHeight: 0, maxHeight: .infinity)
            //.anchorPreference(key: <#T##PreferenceKey.Protocol#>, value: <#T##Anchor<A>.Source#>) { anchor in}
    }

}

struct PatternScene_Previews: PreviewProvider {
    static var previews: some View {
        PatternScene()
    }
}

appreciate any help!

Upvotes: 4

Views: 1093

Answers (2)

Asperi
Asperi

Reputation: 258285

Here it is a demo of approach how this could be done

SwiftUI Anchor center usage

Testing code:

struct TestPatternScene: View {
    var body: some View {
        VStack {
            PatternScene()
                .overlayPreferenceValue(PatternSceneCenterKey.self) { pref in
                    GeometryReader { g in
                        if pref.center != nil {
                            Circle()
                                .fill(Color.red)
                                .frame(width: 4, height: 4)
                                .position(g[pref.center!]) // !! read stored center point (already converted into .local space)
                        }
                    }
            }
            Spacer()
        }
    }
}

Main code:

struct PatternSceneCenter { // Pref value to store anchor
    var center: Anchor<CGPoint>? = nil
}

struct PatternSceneCenterKey: PreferenceKey { // Pref key 
    typealias Value = PatternSceneCenter

    static var defaultValue: PatternSceneCenter = PatternSceneCenter()

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

struct PatternScene: View {

    let pattern = Path { path in
        path.move(to: CGPoint(x: 50, y: 50))
        path.addLine(to: CGPoint(x: 250, y: 50))
        path.addLine(to: CGPoint(x: 250, y: 250))
        path.addLine(to: CGPoint(x: 50, y: 250))
        path.addLine(to: CGPoint(x: 100, y: 100))
    }

    var body: some View {
        self.pattern
            .fill(Color.yellow)
            .frame(minWidth: 0, maxWidth: 100, minHeight: 0, maxHeight: 100)
            .anchorPreference(key: PatternSceneCenterKey.self, 
                value: .center) { PatternSceneCenter(center: $0) } // store center anchor of current view into our custom pref value
    }

}

Upvotes: 2

gotnull
gotnull

Reputation: 27224

You need to create a data and key struct that conforms to PreferenceKey for .anchorPreference(...) to work:

Something like this:

struct MyTextPreferenceData {
    let viewIdx: Int
    let bounds: Anchor<CGRect>
}

struct MyTextPreferenceKey: PreferenceKey {
    typealias Value = [MyTextPreferenceData]

    static var defaultValue: [MyTextPreferenceData] = []

    static func reduce(value: inout [MyTextPreferenceData], nextValue: () -> [MyTextPreferenceData]) {
        value.append(contentsOf: nextValue())
    }
}

struct PatternScene: View {
    let idx: Int

    let pattern = Path { path in
        path.move(to: CGPoint(x: 50, y: 50))
        path.addLine(to: CGPoint(x: 250, y: 50))
        path.addLine(to: CGPoint(x: 250, y: 250))
        path.addLine(to: CGPoint(x: 50, y: 250))
        path.addLine(to: CGPoint(x: 100, y: 100))
    }

    var body: some View {
        self.pattern
            .frame(minWidth: 0, maxWidth: .infinity, minHeight: 0, maxHeight: .infinity)
            .anchorPreference(key: MyTextPreferenceKey.self, value: .bounds, transform: { [MyTextPreferenceData(viewIdx: self.idx, bounds: $0)] })
    }
}

struct PatternScene_Previews: PreviewProvider {
    static var previews: some View {
        PatternScene(idx: 0)
    }
}

Upvotes: 1

Related Questions