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 MessageUIclass 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()
}
}
Solved! Go to Solution.
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.
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.
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!