Have 'sketchEditor.start(with:' keep previously drawn graphics when switching between drawing types

600
2
Jump to solution
01-22-2020 08:56 AM
StephenStrand3
New Contributor II

I'm new to Swift and am building a GIS app for IOS to learn more. Part of the app is giving someone the ability to draw temp graphics on top of the map. Right now when I switch between point/polyline/polygon, the graphics for whatever has been previously drawn are removed and I was wondering if there was a way to keep them there until the "CLEAR" button is clicked.

I believe the answer lies in self.sketchEditor.start(with: nil, creationMode: [draw style])

The "nil" is wiping out what was there before, but I cannot figure out what I need to replace it with to have it keep any currently drawn graphics.

Below is my code, any help would be much appreciated.

//
// ViewController.swift
// 
//
// 
// 
//

import UIKit
import ArcGIS
import MessageUI

class ViewController: UIViewController {

@IBOutlet weak var mapView: AGSMapView!
@IBOutlet weak var geometrySegmentedControl: UISegmentedControl!
@IBOutlet weak var undoBBI: UIButton!
@IBOutlet weak var clearBBI: UIButton!

private var map: AGSMap!
private var sketchEditor: AGSSketchEditor!

private func setupMap() {
let itemID = ""
let portal = AGSPortal(url: URL(string: "https://www.arcgis.com")!, loginRequired: false)
let portalItem: AGSPortalItem = AGSPortalItem(portal: portal, itemID: itemID)
mapView.map = AGSMap(item: portalItem)
}

private func showAlert(withStatus: String) {
let alertController = UIAlertController(title: "Alert", message:
withStatus, preferredStyle: UIAlertController.Style.alert)
alertController.addAction(UIAlertAction(title: "Dismiss", style: UIAlertAction.Style.default,handler: nil))
present(alertController, animated: true, completion: nil)
}

func setupLocationDisplay() {
mapView.locationDisplay.autoPanMode = AGSLocationDisplayAutoPanMode.compassNavigation
mapView.locationDisplay.start { [weak self] (error:Error?) -> Void in
if let error = error {
self?.showAlert(withStatus: error.localizedDescription)
}
}
}

override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.

setupMap()

setupLocationDisplay()

let itemID = ""
let portal = AGSPortal(url: URL(string: "https://www.arcgis.com")!, loginRequired: false)
let portalItem: AGSPortalItem = AGSPortalItem(portal: portal, itemID: itemID)
self.map = AGSMap(item: portalItem)

self.sketchEditor = AGSSketchEditor()
self.mapView.sketchEditor = self.sketchEditor

self.sketchEditor.start(with: nil, creationMode: .unset)

self.mapView.map = self.map
self.mapView.interactionOptions.isMagnifierEnabled = false

NotificationCenter.default.addObserver(self, selector: #selector(ViewController.respondToGeomChanged), name: .AGSSketchEditorGeometryDidChange, object: nil)
}

@objc
func respondToGeomChanged() {
//Enable/disable UI elements appropriately
self.undoBBI.isSelected = self.sketchEditor.undoManager.canUndo
self.clearBBI.isSelected = self.sketchEditor.geometry != nil && !self.sketchEditor.geometry!.isEmpty
}

// MARK: - Actions

@IBAction func geometryValueChanged(_ geometrySegmentedControl: UISegmentedControl) {
switch geometrySegmentedControl.selectedSegmentIndex {
case 0://multipoint
self.sketchEditor.start(with: nil, creationMode: .unset)

case 1://freehand polyline
self.sketchEditor.start(with: nil, creationMode: .freehandPolyline)

case 2://freehand polygon
self.sketchEditor.start(with: nil, creationMode: .freehandPolygon)

case 3://multipoint
self.sketchEditor.start(with: nil, creationMode: .multipoint)

default:
break
}

self.mapView.sketchEditor = self.sketchEditor
}

@IBAction func undo() {
if self.sketchEditor.undoManager.canUndo { //extra check, just to be sure
self.sketchEditor.undoManager.undo()
}
}

@IBAction func clear() {
self.sketchEditor.clearGeometry()
}
}

0 Kudos
1 Solution

Accepted Solutions
Nicholas-Furness
Esri Regular Contributor

As you work with the Sketch Editor, it maintains a current geometry (could be a point, polyline, polygon, etc. depending on the creationMode).

In your respondToGeomChanged function, you can read the geometry property of the AGSSketchEditor. That function will be called whenever the user has changed the sketched geometry in some way.

Hold on to that AGSGeometry to pass in to the Sketch Editor next time you call start(with:creationMode:).

Looks like your code is from the Sample app. You could try something like this:

private var previouslySketchedGeometries = [AGSSketchCreationMode:AGSGeometry]()

@objc
func respondToGeomChanged() {
    //Enable/disable UI elements appropriately
    undoBBI.isEnabled = sketchEditor.undoManager.canUndo
    clearBBI.isEnabled = sketchEditor.geometry != nil && !sketchEditor.geometry!.isEmpty
    
    // Store the current geometry for this mode
    if sketchEditor.isSketchValid {
        previouslySketchedGeometries[sketchEditor.creationMode] = sketchEditor.geometry
    }
}

// MARK: - Actions

@IBAction func geometryValueChanged(_ segmentedControl: UISegmentedControl) {
    var creationMode: AGSSketchCreationMode = .unset
    
    switch segmentedControl.selectedSegmentIndex {
    case 0://point
        creationMode = .point
    case 1://polyline
        creationMode = .polyline
    case 2://freehand polyline
        creationMode = .freehandPolyline
    case 3://polygon
        creationMode = .polygon
    case 4://freehand polygon
        creationMode = .freehandPolygon
    default:
        return
    }
    
    // If we previously drew something for this mode, get hold of it…
    let previousGeometryForMode = previouslySketchedGeometries[creationMode]
    
    self.sketchEditor.start(with: previousGeometryForMode, creationMode: creationMode)
    
    self.mapView.sketchEditor = self.sketchEditor
}‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍

Hope this helps.

View solution in original post

2 Replies
Nicholas-Furness
Esri Regular Contributor

As you work with the Sketch Editor, it maintains a current geometry (could be a point, polyline, polygon, etc. depending on the creationMode).

In your respondToGeomChanged function, you can read the geometry property of the AGSSketchEditor. That function will be called whenever the user has changed the sketched geometry in some way.

Hold on to that AGSGeometry to pass in to the Sketch Editor next time you call start(with:creationMode:).

Looks like your code is from the Sample app. You could try something like this:

private var previouslySketchedGeometries = [AGSSketchCreationMode:AGSGeometry]()

@objc
func respondToGeomChanged() {
    //Enable/disable UI elements appropriately
    undoBBI.isEnabled = sketchEditor.undoManager.canUndo
    clearBBI.isEnabled = sketchEditor.geometry != nil && !sketchEditor.geometry!.isEmpty
    
    // Store the current geometry for this mode
    if sketchEditor.isSketchValid {
        previouslySketchedGeometries[sketchEditor.creationMode] = sketchEditor.geometry
    }
}

// MARK: - Actions

@IBAction func geometryValueChanged(_ segmentedControl: UISegmentedControl) {
    var creationMode: AGSSketchCreationMode = .unset
    
    switch segmentedControl.selectedSegmentIndex {
    case 0://point
        creationMode = .point
    case 1://polyline
        creationMode = .polyline
    case 2://freehand polyline
        creationMode = .freehandPolyline
    case 3://polygon
        creationMode = .polygon
    case 4://freehand polygon
        creationMode = .freehandPolygon
    default:
        return
    }
    
    // If we previously drew something for this mode, get hold of it…
    let previousGeometryForMode = previouslySketchedGeometries[creationMode]
    
    self.sketchEditor.start(with: previousGeometryForMode, creationMode: creationMode)
    
    self.mapView.sketchEditor = self.sketchEditor
}‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍

Hope this helps.

StephenStrand3
New Contributor II

Nicholas,

Thank you for the quick and helpful response. I modified my code with your suggestions and it now saves each type of drawing. There is one hurdle left and that is that when I switch my Segmented Control between the drawing types, it only shows the one that is currently active on the control. I'm going to try and sort that out next, thank you for the huge step forward!

0 Kudos