banner



How To Create A Service Area Map

Update note: Andrew Tetlaw updated this tutorial for iOS xiii. Audrey Tam wrote the original.

MapKit is a powerful API available on iOS devices that makes it easy to display maps, mark locations, enhance with custom data and even draw routes or other shapes on elevation.

In this MapKit tutorial, yous'll make HonoluluArt, an app that zooms into a location in Honolulu and marks public artwork on a map. Y'all'll implement the marker's callout detail button to launch the Maps app and open driving directions to the artwork. Then, you'll parse a GeoJSON file from the Honolulu metropolis data portal to extract the public artwork features and mark them on the map.

In the procedure, you'll learn how to:

  • Add together a MapKit map to your app.
  • Zoom to a particular location.
  • Parse GeoJSON data to create custom map annotations.

A notation from the original author, Audrey Tam: This update uses public artworks data from Honolulu, where I was born and raised. Information technology's no longer my hometown, but the names and places bring back memories. If you're not lucky enough to live there, I hope you'll enjoy imagining yourself being there!

Getting Started

To get started, download the starter project using the Download Materials button at the tiptop or lesser of this tutorial. The project contains a GeoJSON file and some paradigm assets, but no maps yet!

Open up Main.storyboard and, from the Object library, drag a Map Kit View into the middle of the scene. Constrain the Map View to the super view (not the Rubber Area), setting 0 on all edges, so it stretches throughout the Rubber Area of notched devices.

Build and run. You at present have a fully zoomable and panable map showing the continent of your current location using Apple Maps!

Map view of Australia, Indonesia and Papua New Guinea.

So far, so good, eh?

But you don't want to start the map looking at the entire world, unless you're a super-villain, cue evil laugh… You want to zoom into a particular area. And to do that, you demand to go coding!

Open up ViewController.swift and add the following beneath the import UIKit argument:

import MapKit        

Next, you'll demand an outlet for the MKMapView in ViewController.swift.

Add the post-obit outlet lawmaking immediately before viewDidLoad():

@IBOutlet private var mapView: MKMapView!        

Then, go to Main.storyboard and link the Map View to your new outlet:

Connecting the Map View from  Storyboard to your Outlet

Setting the Visible Area

Go back to ViewController.swift, detect viewDidLoad() and add together the following to the terminate of the method:

// Set initial location in Honolulu let initialLocation = CLLocation(breadth: 21.282778, longitude: -157.829444)        

You'll use this to set the starting coordinates of the map view to a betoken in Honolulu.

When telling the map what to display, giving latitude and longitude is plenty to center the map. But, you must likewise specify the rectangular region to display to get a right zoom level.

Add the following private extension at the finish of ViewController.swift:

private extension MKMapView {   func centerToLocation(     _ location: CLLocation,      regionRadius: CLLocationDistance = g   ) {     let coordinateRegion = MKCoordinateRegion(       heart: location.coordinate,       latitudinalMeters: regionRadius,       longitudinalMeters: regionRadius)     setRegion(coordinateRegion, blithe: truthful)   } }        

The location argument is the eye betoken. The region will have north-southward and due east-west spans based on a altitude of regionRadius, which has a default of 1000 meters, a little more than half a mile, which works well for plotting the public artwork information in the GeoJSON file.

setRegion(_:blithe:) tells MKMapView to brandish the region represented by MKCoordinateRegion. The map view automatically transitions the electric current view to the desired region with a slap-up zoom blitheness, with no extra lawmaking required!

Back in viewDidLoad(), add the following line to the end of the method:

mapView.centerToLocation(initialLocation)        

This calls the helper method to zoom into initialLocation on startup.

Build and run. You lot'll find yourself in the centre of Waikiki. Aloha! :]

Map of downtown Waikiki.

Constraining the Photographic camera

And so far, you've been able to become anywhere you desire on the map, merely we're only interested in the island of Oahu. You've also been able to pinch in to zoom the map so far that the island is merely a few pixels! MapKit is capable of constraining the user to pan and zoom the map over a specified area.

Note: To zoom in the Simulator, hold Selection and elevate in the map view.

Once again in viewDidLoad(), add the following lines to the end of the method:

          let oahuCenter = CLLocation(breadth: 21.4765, longitude: -157.9647)     let region = MKCoordinateRegion(       center: oahuCenter.coordinate,       latitudinalMeters: 50000,       longitudinalMeters: 60000)     mapView.setCameraBoundary(       MKMapView.CameraBoundary(coordinateRegion: region),       animated: truthful)          let zoomRange = MKMapView.CameraZoomRange(maxCenterCoordinateDistance: 200000)     mapView.setCameraZoomRange(zoomRange, animated: true)        

Build and run. Now when you lot zoom out, you can't make Oahu every bit small as before. You tin can merely pan the map view to run into the northern, southern, eastern and westernmost edges of the isle.

MapKit uses an internal camera to decide where the signal of view for the map is, how expansive the field of view is and to animate view movement. When you lot specify a photographic camera boundary with a center and a region rectangle, the camera center always stays within this region.

If the user tries to pan further out of the region, the view doesn't scroll any further. Information technology keeps them focused on the area you desire them to see. A region size of 60,000 meters wide by 50,000 meters high keeps Oahu nicely constrained inside the map view.

The MapKit view camera keeps rail of its distance from the view center when zooming in and out. Setting the camera zoom range maximum center distance constraint limits how far the view zooms out and how tiny the island of Oahu becomes. This is even more than helpful when adding points of involvement to the map, which is the next step!

Obtaining Public Art Data

The adjacent step is to plot interesting data effectually the electric current location. Just where in the world tin can you get such stuff?

Well, it depends on your current location. Honolulu, similar many cities, has an Open Data Portal to improve public access to government information.

1 convenient feature of Honolulu's information portal is the ability to export the data prepare in GeoJSON format — a flavor of JSON that'south used to represent geospatial features along with their metadata. One of MapKit'southward recent features makes it super-easy to use GeoJSON information in your app, as yous'll shortly see.

Note: After you end this tutorial, look around to meet if a nearby urban center has another dataset in GeoJSON format you can use. Once you lot come across how easy it is, you may find it interesting plotting different datasets together on the aforementioned map.

For this tutorial, you lot'll use the Honolulu Public Art dataset. To keep things unproblematic, I've already exported this data from the portal and included information technology in the starter project, nicely formatted for readability, of course. Information technology's the least I could do.

To become a feeling for the items in this dataset, open PublicArt.geojson in the Xcode editor. At the top level you'll see:

{   "type": "FeatureCollection",   "features": [ ... ] }        

The value for the key features is an array of GeoJSON objects of the type Feature. Each ane of these objects contains some standard keys, but also a properties lexicon with some custom fields created past the data portal. The geometry key is where y'all'll find the coordinates of the characteristic.

Have a look at the first one:

{   "blazon":"Feature",   "properties":{     "location":"Lester McCoy Pavilion",     "latitude":"21.290824",     "description":"...",     "thumb":goose egg,     "credit":"Funded past the Works Progress Administration",     "objectid":"1930.01.01",     "creator":"Robert Lee Eskridge",     "longitude":"-157.85131",     "imagefile":"http://....JPG",     "date":"1935",     "discipline":"Mural",     "championship":"The Makahiki Festival - The Makai Mural",     "access":"Express"   },   "geometry":{     "type":"Point",     "coordinates":[-157.85131,21.290824]   } }        

GeoJSON Backdrop

Endeavour not to become likewise worried about the GeoJSON data format. Every bit you'll soon encounter, importing information technology is more often than not automated! The essential parts are the properties dictionary and the coordinates.

For this tutorial, yous'll only utilize a few properties: The artwork'due south location name, discipline, title, latitude and longitude:

  • Location name: Lester McCoy Pavilion.
  • Discipline: Landscape.
  • Title: The Makahiki Festival – The Makai Mural.
  • Latitude: 21.290824.
  • Longitude: -157.85131.

Note: If you want to learn more nearly the format, there'southward a whole world to explore. The official website is a fleck sparse, the RFC is highly technical, but the Wikipedia article is readable. :]

It's a widely supported format for all things geospatial. Some useful tools include geojson.io, a useful site for testing and editing GeoJSON data, and GitHub, which volition automatically render whatsoever .geojson file in a repository on a map.

Later in this tutorial, you'll use the whole dataset. But first, to jump direct into the MapKit fun, you'll plot one of the artworks on the map.

Showing Artwork on the Map

In PublicArt.geojson, press Command-L and leap to line 1354. It'southward a statuary statue of King David Kalakaua in Waikiki Gateway Park.

The backdrop for this item are:

  • Location proper name: Waikiki Gateway Park
  • Discipline: Sculpture
  • Title: King David Kalakaua
  • Latitude: 21.283921
  • Longitude: -157.831661

To show this on the map view, y'all must create a map annotation. Map annotations are small pieces of information tied to a particular location. Apple's Maps app usually represents them as little pins.

To create your annotations, you lot create a class that conforms to MKAnnotation, add the annotation to the map and tell the map how the annotation should be displayed.

The Artwork Class

First, right-click the HonoluluArt binder in the Projection navigator and pick New File…. Choose Swift File and name your new file Artwork.swift.

Open Artwork.swift in the editor and add together the following below import Foundation:

import MapKit  class Artwork: NSObject, MKAnnotation {   permit title: Cord?   let locationName: String?   let discipline: String?   let coordinate: CLLocationCoordinate2D    init(     title: Cord?,     locationName: String?,     discipline: String?,     coordinate: CLLocationCoordinate2D   ) {     self.title = title     self.locationName = locationName     self.discipline = bailiwick     cocky.coordinate = coordinate      super.init()   }    var subtitle: String? {     return locationName   } }        

To arrange to MKAnnotation, Artwork must subclass NSObject, because MKAnnotation is an NSObjectProtocol.

MKAnnotation requires the coordinate property. If you want your annotation view to display a title and subtitle when the user taps a marker, your class besides needs properties named title and subtitle.

Information technology's perfectly sensible for the Artwork class to have stored properties named title and coordinate, but none of the PublicArt.geojson backdrop naturally map to the idea of subtitle. To arrange to MKAnnotation, you brand subtitle a computed holding that returns locationName.

The MKAnnotation protocol properties title and subtitle are defined as optional strings, simply yous may wonder why you've used String? equally the type for the locationName and discipline properties. Since these properties are set from an external information source, the PublicArt.geojson file, you can't guarantee they'll always exist. Better to be safety.

OK, so you'll use the championship, locationName and coordinate properties for the MKAnnotation object, but what's the discipline property for? You lot'll find out later in this tutorial! ;]

Adding an Annotation

Next, you'll add an Artwork object to the map view for every artwork you lot want to plot. For now, you lot're calculation merely one artwork, and so switch to ViewController.swift and add together the following lines to the stop of viewDidLoad():

// Bear witness artwork on map let artwork = Artwork(   championship: "King David Kalakaua",   locationName: "Waikiki Gateway Park",   subject: "Sculpture",   coordinate: CLLocationCoordinate2D(latitude: 21.283921, longitude: -157.831661)) mapView.addAnnotation(artwork)        

Here, you create a new Artwork object and add information technology equally an annotation to the map view. MKMapView as well provides addAnnotations(_:), which you'll use after in this tutorial when you take an array of annotations to add to the map view.

Build and run. Now you lot can come across that King David Kalakaua's statue is at the gateway to Waikiki!

Map of downtown Waikiki with pin showing statue's location.

The default annotation marking view shows the location with the championship below the marker. Select the mark. Information technology grows and now shows the subtitle, too:

Zoomed in view of map with pin, title of statue and location in Waikiki Gateway Park.

Well, that's OK, but you've seen that tapping a marker in other apps shows a callout: a little, foursquare oral communication bubble. For that, you must configure the annotation view.

Configuring the Annotation View

1 way to configure the annotation view is to implement the map view's mapView(_:viewFor:) delegate method. Your chore in this consul method is to render an instance of MKAnnotationView to present every bit a visual indicator of the annotation.

In this case, ViewController is the consul for the map view. To avert clutter and improve readability, you lot'll create an extension of ViewController.

Add together the post-obit at the bottom of ViewController.swift:

extension ViewController: MKMapViewDelegate {   // 1   func mapView(     _ mapView: MKMapView,      viewFor notation: MKAnnotation   ) -> MKAnnotationView? {     // 2     guard let annotation = annotation every bit? Artwork else {       return aught     }     // 3     permit identifier = "artwork"     var view: MKMarkerAnnotationView     // 4     if let dequeuedView = mapView.dequeueReusableAnnotationView(       withIdentifier: identifier) every bit? MKMarkerAnnotationView {       dequeuedView.annotation = annotation       view = dequeuedView     } else {       // 5       view = MKMarkerAnnotationView(         notation: annotation,         reuseIdentifier: identifier)       view.canShowCallout = truthful       view.calloutOffset = CGPoint(x: -5, y: 5)       view.rightCalloutAccessoryView = UIButton(blazon: .detailDisclosure)     }     return view   } }        

Here's what you're doing:

  1. mapView(_:viewFor:) gets called for every note you add to the map — like tableView(_:cellForRowAt:) when working with table views — to return the view for each note.
  2. Your app might use other annotations, like user location, so check that this note is an Artwork object. If information technology isn't, return nil to let the map view apply its default notation view.
  3. You create each view every bit an MKMarkerAnnotationView. Later in this tutorial, you'll create MKAnnotationView objects to brandish images instead of markers.
  4. Too similarly to tableView(_:cellForRowAt:), a map view reuses annotation views that are no longer visible. And so yous check to see if a reusable notation view is available before creating a new ane. When you dequeue a reusable annotation, you give it an identifier.

    If you take multiple styles of annotations, be sure to have a unique identifier for each one. Over again, it'southward the aforementioned idea backside a cell identifier in tableView(_:cellForRowAt:).

  5. Here you create a new MKMarkerAnnotationView object if an annotation view could not be dequeued. It uses the title and subtitle properties of your Artwork class to determine what to testify in the callout.

The Map View Delegate

All that's left is setting ViewController equally the consul of the map view. You can do this in Main.storyboard, only it's more visible if you lot do it in code. In ViewController.swift, add this line to viewDidLoad(), before the statement that creates artwork:

mapView.delegate = self        

And that's it! Build and run. Tap the mark to pop upwardly the callout bubble:

Map of downtown Waikiki with callout bubble for the statue.

mapView(_:viewFor:) configures the callout to include a item disclosure info button on the right side, but tapping that push doesn't do annihilation yet. Yous could implement it to bear witness an warning with more info or to open up a particular view controller.

Here's a neat 3rd option. When the user taps the info push button, your app launches the Maps app, complete with driving, walking and transit directions to get from the simulated user location to the artwork!

Launching the Maps App

To provide this bully user experience, open Artwork.swift and add together this import argument, below the other 2:

import Contacts        

This adds the Contacts framework, which contains lexicon key constants such as CNPostalAddressStreetKey, for when yous need to set the accost, city or land fields of a location.

To tell the Maps app where to go, you lot must laissez passer information technology an MKMapItem. This form describes a betoken of interest on the map. To create i, you must first create an MKPlacemark to depict the bespeak.

Next, add together the following belongings to the course:

var mapItem: MKMapItem? {   guard let location = locationName else {     render nil   }    let addressDict = [CNPostalAddressStreetKey: location]   let placemark = MKPlacemark(     coordinate: coordinate,     addressDictionary: addressDict)   allow mapItem = MKMapItem(placemark: placemark)   mapItem.name = title   return mapItem }        

You employ your existing location information as the accost to create an MKPlacemark. You then create and configure the MKMapItem you lot need for communicating with Maps.

Handling the Callout

Adjacent, you have to tell MapKit what to do when the user taps the callout button. Open ViewController.swift, and add together this method to the MKMapViewDelegate extension:

func mapView(   _ mapView: MKMapView,   annotationView view: MKAnnotationView,   calloutAccessoryControlTapped control: UIControl ) {   baby-sit let artwork = view.annotation as? Artwork else {     return   }    let launchOptions = [     MKLaunchOptionsDirectionsModeKey: MKLaunchOptionsDirectionsModeDriving   ]   artwork.mapItem?.openInMaps(launchOptions: launchOptions) }        

When the user taps a map annotation marker, the callout shows an info button. If the user taps this info push button, iOS calls mapView(_:annotationView:calloutAccessoryControlTapped:).

In this method, you grab the Artwork object this tap refers to, then launch Maps past creating an associated MKMapItem and calling openInMaps(launchOptions:) on the map item.

Notice you're passing a dictionary to this method. This allows you to specify a few different options. Here, the DirectionsModeKey is set to Driving.

This causes Maps to testify driving directions from the user's electric current location to this location. Neat!

Note: Explore the MKMapItem documentation to see other launch option dictionary keys, and the openMaps(with:launchOptions:) method that lets you laissez passer an array of MKMapItem objects.

Setting Your Simulated Location

Earlier you build and run, you should movement to Honolulu. Well, just fix your simulated location to Honolulu.:]

In Xcode, go to Production ► Scheme ► Edit Scheme…, select Run from the left menu, then select the Options tab. Check Allow Location Simulation and select Honolulu, How-do-you-do, USA equally the Default Location. Then click the Shut button:

Xcode dialog box with Honolulu, HI, USA selected as default location.

Build and run. You'll see the map zoom in on Waikiki, every bit before. Tap the marker, so tap the info button in the callout and watch it launch Maps to show the statue'due south location and driving directions to information technology:

Map with driving route from a location to the statue.

This calls for a celebration with your favorite tropical drink!

Note: The first time you lot open Maps, information technology prompts you to allow Maps to access your location — tap Allow While Using App — and displays a Safety Warning.

Decoding GeoJSON with MKGeoJSONDecoder

Now that you lot know how to show one artwork on the map and how to launch Maps from the mark's callout info push button, information technology'southward time to parse the dataset into an array of Artwork objects. Then you'll add them as annotations to the map view to display all artworks located in the current map region.

MapKit has MKGeoJSONDecoder, a super-useful characteristic. It can decode GeoJSON data and render an assortment of objects that implement the MKGeoJSONObject protocol. MapKit likewise provides i concrete course that implements this protocol: MKGeoJSONFeature, which is all you'll need for this tutorial.

Add this failable initializer to Artwork.swift, below the initializer:

init?(feature: MKGeoJSONFeature) {   // 1   baby-sit      let point = feature.geometry.first every bit? MKPointAnnotation,     let propertiesData = feature.properties,     allow json = try? JSONSerialization.jsonObject(with: propertiesData),     let properties = json as? [Cord: Any]      else {       return zip   }    // 3   title = properties["championship"] equally? String   locationName = properties["location"] as? String   bailiwick = properties["discipline"] as? Cord   coordinate = point.coordinate   super.init() }        

Here's what you're doing:

  1. MKGeoJSONFeature has a geometry property representing i or more shapes associated with the feature. All the features in PublicArt.geojson are signal locations and MapKit helpfully creates a MKPointAnnotation for y'all. This is where y'all'll detect the coordinate every bit a CLLocationCoordinate2D.
  2. Next, you read the feature's properties, which is of type Data? and contains a serialized JSON lexicon. You use JSONSerialization to decode the data into a Swift dictionary.
  3. At present that the properties are decoded, you can set the appropriate Artwork properties from the dictionary values.

Making Annotations

To apply this initializer, open ViewController.swift and add together the following property, an array to hold the Artwork objects from the GeoJSON file, to the class:

private var artworks: [Artwork] = []        

Next, add the following helper method to the class:

private func loadInitialData() {   // 1   guard      permit fileName = Parcel.main.url(forResource: "PublicArt", withExtension: "geojson"),     let artworkData = effort? Data(contentsOf: fileName)      else {       render   }    do {     // two     let features = try MKGeoJSONDecoder()       .decode(artworkData)       .compactMap { $0 as? MKGeoJSONFeature }     // 3     let validWorks = features.compactMap(Artwork.init)     // iv     artworks.suspend(contentsOf: validWorks)   } grab {     // v     print("Unexpected error: \(error).")   } }        

Hither'south what you lot're doing in this code:

  1. To begin, you read PublicArt.geojson into a Data object.
  2. You use MKGeoJSONDecoder to obtain an assortment of GeoJSON objects only but continue instances of MKGeoJSONFeature using compactMap.
  3. You transform the MKGeoJSONFeature objects into Artwork objects using its failable initializer you lot added and compactMap again.
  4. You lot append the resulting validWorks to the artworks array.
  5. Considering MKGeoJSONDecoder's decode(_ :) method can throw an error, you grab it and impress the error to the Xcode console.

Plotting the Artwork

You now have an array of all the public artwork in the dataset, which you'll add to the map.

Still in ViewController.swift, add the following code at the cease of viewDidLoad():

loadInitialData() mapView.addAnnotations(artworks)        

Note: Be sure to use the plural addAnnotationsouthward , non the singular addAnnotation!

Delete the lines that create the single King David Kalakaua map annotation. You don't need them at present that loadInitialData() creates the artworks array.

Build and run. Cheque out all the markers!

Map with many pins showing art locations.

Move the map around to see other markers appear. Tap a marker to open its callout bubble, and then tap its info button to launch the Maps. Yep, everything y'all did with the King Kalakaua statue works with all the new artwork as well!

If you're worried near adding annotations to the map when they're not visible, don't be! Apple recommends adding all the annotations right away, whether or not they're visible in the map region. When you motion the map, it automatically displays the visible annotations.

And that'south it! You lot've built an app that parses a GeoJSON file into an assortment of artworks, then displays them equally annotation markers, with a callout info push button that launches Maps. Gloat with a hula dance effectually your desk! :]

Just await, there are still a few bits of bling to add.

Customizing Annotations

Recall the discipline property in the Artwork form? Its values are things like Sculpture and Landscape. In fact, the most numerous disciplines are Sculpture, Plaque, Mural and Monument.

It'south easy to color-lawmaking the markers, so the nigh numerous disciplines each take their own colored marker, and all the other disciples accept green markers.

Markers with Color-Coding and Text

In Artwork.swift, add this holding:

var markerTintColor: UIColor  {   switch discipline {   instance "Monument":     return .red   case "Mural":     return .cyan   instance "Plaque":     return .blue   instance "Sculpture":     return .purple   default:     return .green   } }        

Now, yous could keep calculation code to mapView(_:viewFor:), simply that would clutter the view controller. There's a more than elegant way, similar to what y'all can do for tabular array view cells. Create a new Swift file named ArtworkViews.swift and add this lawmaking, beneath the import statement:

import MapKit  class ArtworkMarkerView: MKMarkerAnnotationView {   override var annotation: MKAnnotation? {     willSet {       // 1       guard allow artwork = newValue every bit? Artwork else {         return       }       canShowCallout = true       calloutOffset = CGPoint(x: -five, y: five)       rightCalloutAccessoryView = UIButton(type: .detailDisclosure)        // 2       markerTintColor = artwork.markerTintColor       if let letter = artwork.discipline?.first {         glyphText = Cord(letter of the alphabet)       }     }   } }        

Soon, you'll register this class as a reusable annotation view for Artwork annotations. The organization passes it an annotation as newValue, and so here's what you're doing:

  1. These lines do the same matter as your mapView(_:viewFor:), configuring the callout.
  2. Then you ready the marker's tint color and as well supervene upon its pivot icon, or glyph, with the start letter of the alphabet of the notation's discipline.

Color My World

At present switch to ViewController.swift, and add this line to viewDidLoad(), earlier calling loadInitialData():

mapView.register(   ArtworkMarkerView.self,   forAnnotationViewWithReuseIdentifier:      MKMapViewDefaultAnnotationViewReuseIdentifier)        

Here, y'all register your new class with the map view'southward default reuse identifier. For an app with more annotation types, you would register classes with custom identifiers.

Ringlet down to the extension and delete mapView(_:viewFor:).

Build and run. And then move the map around to see the different colored and labeled markers:

Map with red, green, blue and purple markers.

In this section of the map, there'southward much more than art than the map view shows. It reduces clutter by clustering markers that are too shut together. In the next department, yous'll see all the annotations.

Only starting time, fix the glyph's prototype instead of its text. Add the following property to Artwork.swift:

var paradigm: UIImage {   baby-sit let proper noun = discipline else {      render #imageLiteral(resourceName: "Flag")    }    switch name {   example "Monument":     return #imageLiteral(resourceName: "Monument")   instance "Sculpture":     return #imageLiteral(resourceName: "Sculpture")   case "Plaque":     return #imageLiteral(resourceName: "Plaque")   case "Mural":     return #imageLiteral(resourceName: "Landscape")   default:     render #imageLiteral(resourceName: "Flag")   } }        

These images from icons8.com are already in Assets.xcassets.

Then, in ArtworkViews.swift, replace the glyphText lines with:

glyphImage = artwork.prototype        

Build and run to run into unlike colored markers with images:

Map with different colored markers.

And that's a segue to some other customization option and your next task: Replace the markers with images!

Annotations with Images

In ArtworkViews.swift, add the post-obit form:

course ArtworkView: MKAnnotationView {   override var annotation: MKAnnotation? {     willSet {       guard let artwork = newValue equally? Artwork else {         return       }        canShowCallout = truthful       calloutOffset = CGPoint(10: -5, y: v)       rightCalloutAccessoryView = UIButton(type: .detailDisclosure)        image = artwork.epitome     }   } }        

At present, you're using a manifestly former MKAnnotationView instead of an MKMarkerAnnotationView, and the view has an image property.

Back in ViewController.swift, in viewDidLoad(), register this new grade, instead of ArtworkMarkerView:

mapView.register(   ArtworkView.self,   forAnnotationViewWithReuseIdentifier:      MKMapViewDefaultAnnotationViewReuseIdentifier)        

Build and run to come across all the icons:

Map with many different types and colored markers.

Custom Callout Accessory Views

The right callout accessory is an info push button, but tapping it opens Maps. So, now y'all'll modify the button to prove the Maps icon.

Find this line in ArtworkView:

rightCalloutAccessoryView = UIButton(blazon: .detailDisclosure)        

Supervene upon this line with the following lawmaking:

allow mapsButton = UIButton(frame: CGRect(   origin: CGPoint.zero,    size: CGSize(width: 48, height: 48))) mapsButton.setBackgroundImage(#imageLiteral(resourceName: "Map"), for: .normal) rightCalloutAccessoryView = mapsButton        

Here, you lot create a UIButton, set its background image to a map icon, also from icons8.com in Assets.xcassets, and so set the view's right callout accessory to this button.

Build and run. Then tap a view to see the new Maps push:

Map with callout bubble for statue with a Maps button.

The final customization is the detail callout accessory. It'south a unmarried line, which is enough for brusk location text, just some of the longer location values are truncated like this i:

Map with callout button with a truncated location name.

Now y'all need a multi-line characterization. Add the following code to ArtworkView'southward willSet:

permit detailLabel = UILabel() detailLabel.numberOfLines = 0 detailLabel.font = detailLabel.font.withSize(12) detailLabel.text = artwork.subtitle detailCalloutAccessoryView = detailLabel        

Build and run. Then tap a view to see the long location text in full.

Where To Go From Here?

You tin can download the completed version of the project using the Download Materials push at the peak or lesser of this tutorial.

Now you lot know the nuts of using MapKit, only there's more yous tin can add together: map display customizations, geocoding, geofencing, custom map overlays, and more. Apple tree's MapKit documentation and Location and Maps Programming Guide are great places to detect more information.

Also await at WWDC 2019 Session 236: What's New in MapKit and MapKit JS, to detect more cool features added in iOS xiii.

At that place's also take a terrific video course, MapKit and Core Location, that covers many awesome topics.

Core Location Tutorial for iOS: Tracking Visited Locations explains how to track your location and display it using MapKit.

If y'all have any questions as you use MapKit in your apps, or tips for other MapKit users, delight join in the forum discussion below!

Source: https://www.raywenderlich.com/7738344-mapkit-tutorial-getting-started

Posted by: byaskentemad1984.blogspot.com

0 Response to "How To Create A Service Area Map"

Post a Comment

Iklan Atas Artikel

Iklan Tengah Artikel 1

Iklan Tengah Artikel 2

Iklan Bawah Artikel