GeometryEditor.geometry is only triggering events on start and stop?

445
2
Jump to solution
12-29-2023 02:31 AM
dmc76
by
New Contributor III

I have a .task( id: geometryEditor.geometry ) on my MapView (I have tried .onChange( of: ) and it behaves the same).  It triggers on geometryEditor.start() or .stop(), but it doesn't trigger on any interactive edits (adding/moving points, etc.)

I'm attempting to use the GeometryEditor as a convenient way to measure along a polyline or the area or edges of a polygon, so I really just need to update a Text() view after doing a few calculations on the current .geometry whenever it changes.  Am I missing something obvious? Is there something more I need to do than to add a .task or .onChange with the .geometry to observe?

Thanks!

-Dave

0 Kudos
1 Solution

Accepted Solutions
Ting
by Esri Contributor
Esri Contributor

Thanks for asking this question! The geometry property is a "Streamed" property, which means its projected value (accessed with the dollar sign) is an asynchronous stream. In order to get updates from the stream, the new Swift Concurrency for-await-in syntax needs to be used.

Consider the snippet below. Whenever the geometry of the geometryEditor changes, the async stream will give an update.

If you aren't familiar with this topic, I recommend reading this blog (by me 😉) to get familiar with the gist of Swift Concurrency in ArcGIS Maps SDK.

Happy holidays!

import SwiftUI
import ArcGIS

struct ContentView: View {
    private class Model: ObservableObject {
        let map = Map(basemapStyle: .arcGISTopographic)
        let geometryEditor: GeometryEditor = {
            let editor = GeometryEditor()
            editor.tool = VertexTool()
            return editor
        }()
    }
    
    @StateObject private var model = Model()
    
    var body: some View {
        MapView(map: model.map)
            .geometryEditor(model.geometryEditor)
            .task {
                for await geometry in model.geometryEditor.$geometry {
                    print("Geometry \(geometry?.extent) Changed")
                }
            }
            .onAppear {
                model.geometryEditor.start(withType: Polyline.self)
            }
    }
}

 

View solution in original post

0 Kudos
2 Replies
Ting
by Esri Contributor
Esri Contributor

Thanks for asking this question! The geometry property is a "Streamed" property, which means its projected value (accessed with the dollar sign) is an asynchronous stream. In order to get updates from the stream, the new Swift Concurrency for-await-in syntax needs to be used.

Consider the snippet below. Whenever the geometry of the geometryEditor changes, the async stream will give an update.

If you aren't familiar with this topic, I recommend reading this blog (by me 😉) to get familiar with the gist of Swift Concurrency in ArcGIS Maps SDK.

Happy holidays!

import SwiftUI
import ArcGIS

struct ContentView: View {
    private class Model: ObservableObject {
        let map = Map(basemapStyle: .arcGISTopographic)
        let geometryEditor: GeometryEditor = {
            let editor = GeometryEditor()
            editor.tool = VertexTool()
            return editor
        }()
    }
    
    @StateObject private var model = Model()
    
    var body: some View {
        MapView(map: model.map)
            .geometryEditor(model.geometryEditor)
            .task {
                for await geometry in model.geometryEditor.$geometry {
                    print("Geometry \(geometry?.extent) Changed")
                }
            }
            .onAppear {
                model.geometryEditor.start(withType: Polyline.self)
            }
    }
}

 

0 Kudos
dmc76
by
New Contributor III

I appreciate the help, the for/await was what I needed.  This is my first, and hopefully last Swift project.  I guess I'm just a dinosaur now and my 35 years of experience in the various flavors of C no longer translates to these hipster languages.

0 Kudos