Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Swift 3 - Mapbox - Customize User Location Annotation

Tags:

ios

swift

mapbox

I'm Looking to change the appearance of the users location annotation. I understand this is now possible using MGLUserLocationAnnotationView, however, I'm unsure how to implement this. Can anyone provide a simple example of how this is done?

Thanks

like image 766
JordanW Avatar asked Dec 15 '22 01:12

JordanW


1 Answers

You are right. The MapBox API MGLUserLocationAnnotationView description is very short. The user location view customisation is available since MapBox iOS SDK 3.4.0. See also the feature comments on the MapBox GitHub

It is important to note: The MGLUserLocationAnnotationView is a subclass of the MGLAnnotationView. It means the MGLUserLocationAnnotationView acts just like a normal annotation view.

Here is an example how to customise the user location view. Create a new class (e.g. CustomUserLocationAnnotationView) and override a layoutSubviews() to add a custom code. In this example I use an UIImage UserLocationIcon.png to visualise the user position on the map.

import Foundation
import UIKit
import Mapbox

final class CustomUserLocationAnnotationView: MGLUserLocationAnnotationView {
    override init(reuseIdentifier: String?) {
        super.init(reuseIdentifier: reuseIdentifier)
    }

    override init(frame: CGRect) {
        super.init(frame: CGRect(x: 0, y: 0, width: 30, height: 30))
    }

    required init?(coder aDecoder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }

    override func layoutSubviews() {
        super.layoutSubviews()

        // Force the annotation view to maintain a constant size when the map is tilted.
        scalesWithViewingDistance = false

        layer.contentsScale = UIScreen.main.scale
        layer.contentsGravity = kCAGravityCenter

        // Use your image here
        layer.contents = UIImage(named: "UserLocationIcon")?.cgImage
    }
}

In your UIViewController or whatever else (e.g. Service class) implement the MGLMapViewDelegate with at least two functions -mapViewDidFinishLoadingMap: and -mapView:viewForAnnotation:. See my comments inline:

extension ViewController: MGLMapViewDelegate {
    // Wait until the map is loaded before proceed with other actions on map
    func mapViewDidFinishLoadingMap(_ mapView: MGLMapView) {
        // Show the user location here
        mapView.showsUserLocation = true
    }

    func mapView(_ mapView: MGLMapView, viewFor annotation: MGLAnnotation) -> MGLAnnotationView? {
        // Customise the user location annotation view
        if annotation is MGLUserLocation {
            var userLocationAnnotationView = mapView.dequeueReusableAnnotationView(withIdentifier: "CustomUserLocationAnnotationViewIdentifier") as? CustomUserLocationAnnotationView

            if userLocationAnnotationView == nil {
                userLocationAnnotationView = CustomUserLocationAnnotationView(reuseIdentifier: "CustomUserLocationAnnotationViewIdentifier")
            }

            // Optional: You can save the annotation object for later use in your app
            self.userLocationAnnotation = annotation

            return userLocationAnnotationView
        }

        // Customise your annotation view here...

        return customAnnotationView
    }
}

The MapView -mapView:viewForAnnotation: delegate function is called for every annotation view instance including the user annotation view.

Optionally: To get your CustomUserLocationAnnotationView instance, you can use this function everywhere in your code:

    // The userLocationAnnotation was previously saved in your ViewController in the -mapView:viewForAnnotation: delegate function
    let view = mapView.view(for: self.userLocationAnnotation) as? CustomUserLocationAnnotationView
like image 151
dzensik Avatar answered Dec 28 '22 06:12

dzensik