Map Objects
The MapKit SDK lets developers display objects on a map. All map objects are customizable, facilitating unique user scenarios tailored to the developer needs.
Placemarks
Add custom image placemarks to the map with the MMKMapObjectCollection.addPlacemark() method from the MMKMap.mapObjects field.
The method accepts the MMKPoint
with coordinates for the placemark and the UIImage
instance.
let placemark = map.mapObjects.addPlacemark()
placemark.geometry = MMKPoint(latitude: 25.1982, longitude: 55.272758)
placemark.setIconWith(UIImage(named: "icon_dollar")!)
The code above creates an instance of the MMKPlacemarkMapObject class that extends the MMKMapObject interface.
The MMKMapObject interface represents every visible object on the map. There are a few ways to configure map objects: changing visibility, allowing dragging, changing a z-index, setting a tap or drag event listener, and more.
For more details, see the MMKMapObject documentation.
Setting text
You can create text labels near placemarks. Use the MMKPlacemarkMapObject.setTextWithText(_:) method.
Use MMKTextStyle to change how labels look, including their text size, color, and position relative to the icon.
placemark.setTextWithText(
"Special place",
style: {
let textStyle = MMKTextStyle()
textStyle.size = 10.0
textStyle.placement = .right
textStyle.offset = 5.0
return textStyle
}()
)
Icon styles
You can customize how placemark icons are presented using the MMKIconStyle class. It lets you change the icon's anchor position, size, rotation type, z-index, tappable area, visibility, and flatness to the map.
let iconStyle = MMKIconStyle()
iconStyle.anchor = NSValue(cgPoint: CGPoint(x: 0.5, y: 0.5))
iconStyle.scale = 0.6
let placemark = map.mapObjects.addPlacemark()
placemark.geometry = point
placemark.setIconWith(image, style: iconStyle)
Composite icons
Combine multiple icons to create a composite one.
-
Create a default icon using MMKMapObjectCollection.addPlacemark() method.
-
Call MMKPlacemarkMapObject.useCompositeIcon() to create a composite icon.
-
Use MMKCompositeIcon.setIconWithName(_:image:style:) to add a new icon to the composite icon.
Complete sample code for creating a composite icon:
let placemark = map.mapObjects.addPlacemark()
placemark.geometry = GeometryProvider.compositeIconPoint
placemark.addTapListener(with: singlePlacemarkTapListener)
placemark.setTextWithText(
"Special place",
style: {
let textStyle = MMKTextStyle()
textStyle.size = 10.0
textStyle.placement = .right
textStyle.offset = 5.0
return textStyle
}()
)
let compositeIcon = placemark.useCompositeIcon()
compositeIcon.setIconWithName(
"pin",
image: UIImage(named: "icon_dollar")!,
style: {
let iconStyle = MMKIconStyle()
iconStyle.anchor = NSValue(cgPoint: CGPoint(x: 0.5, y: 1.0))
iconStyle.scale = 0.9
return iconStyle
}()
)
compositeIcon.setIconWithName(
"point",
image: UIImage(named: "icon_circle")!,
style: {
let iconStyle = MMKIconStyle()
iconStyle.anchor = NSValue(cgPoint: CGPoint(x: 0.5, y: 0.5))
iconStyle.scale = 0.5
iconStyle.flat = true
return iconStyle
}()
)
The result:
Animated placemarks
You can create an animated placemark from an animated png file.
-
Create the placemark using MMKMapObjectCollection.addPlacemark().
let animatedPlacemark = pinsCollection.addPlacemark() animatedPlacemark.geometry = GeometryProvider.animatedImagePoint
-
Call the MMKPlacemarkMapObject.useAnimation() method to create an animation object. Set the animation resource using the MRTAnimatedImageProvider instance.
let animatedImageProvider = YRTAnimatedImageProviderFactory.fromFile( Bundle.main.path(forResource: "animation", ofType: "png") ) as! YRTAnimatedImageProvider let animation = animatedPlacemark.useAnimation() animation.setIconWithImage(animatedImageProvider)
-
Start the animation, managing it with the MMKPlacemarkAnimation object.
animation.play()
Placemark collections
Placemark collections are used to group multiple placemarks into a new collection of nested map objects.
-
To create a collection of nested map objects, use the MMKMapObjectCollection.add() method.
let pinsCollection = map.mapObjects.add()
-
From now, you can use your new
pinsCollection
to display placemarks and other map objects.GeometryProvider.placemarkPoints.enumerated().forEach { pair in let point = pair.element let image = UIImage(named: "icon_dollar")! let placemark = map.mapObjects.addPlacemark() placemark.geometry = point placemark.setIconWith(image) placemark.isDraggable = true }
What it looks like after placemarks were added to a collection of new map objects:
After creating pinCollection
, you can add pins to it the same way as for MMKMap.mapObjects since they have the same MMKMapObjectCollection type.
Note
The MMKMapObjectCollection interface extends MMKMapObject. That is why it is allowed to create nested collections and add them to another collections.
All methods that have the MMKMapObject interface are also available in MMKMapObjectCollection.
You can iterate through MMKMapObjectCollection elements using the MMKBaseMapObjectCollection.traverse(with:) method.
Geometries
The MapKit SDK lets you draw primitive geometric objects like polygons, polylines, and circles on the map. They're all customizable, and they implement the MMKMapObject interface.
Polygons
Use a polygon when you need to display a map area to users.
-
Start by creating a MMKPolygon instance.
static let polygon: MMKPolygon = { var points = [ MMKPoint(latitude: 25.190614, longitude: 55.265616), MMKPoint(latitude: 25.187532, longitude: 55.275413), MMKPoint(latitude: 25.196605, longitude: 55.28094), MMKPoint(latitude: 25.198219, longitude: 55.272685) ] points.append(points[0]) let outerRing = MMKLinearRing(points: points) return MMKPolygon(outerRing: outerRing, innerRings: []) }()
-
Use the MMKMapObjectCollection.addPolygon(with:) method to create a polygon map object.
polygonMapObject = collection.addPolygon(with: GeometryProvider.polygon)
After the build is complete, you will see a default-styled polygon:
-
Define inner points while creating a polygon to exclude a section on the inside of the polygon.
static let polygon: MMKPolygon = { var points = [ MMKPoint(latitude: 25.190614, longitude: 55.265616), MMKPoint(latitude: 25.187532, longitude: 55.275413), MMKPoint(latitude: 25.196605, longitude: 55.28094), MMKPoint(latitude: 25.198219, longitude: 55.272685) ] points.append(points[0]) let outerRing = MMKLinearRing(points: points) var innerPoints = [ MMKPoint(latitude: 25.190978, longitude: 55.273982), MMKPoint(latitude: 25.191958, longitude: 55.27378), MMKPoint(latitude: 25.192516, longitude: 55.27204), MMKPoint(latitude: 25.192015, longitude: 55.271365) ] innerPoints.append(innerPoints[0]) let innerRing = MMKLinearRing(points: innerPoints) return MMKPolygon(outerRing: outerRing, innerRings: [innerRing]) }()
Polygon with inner points:
-
Let's change the default fill color and stroke using the MMKPolygonMapObject instance we created.
polygonMapObject.strokeWidth = 1.5 polygonMapObject.strokeColor = Palette.olive polygonMapObject.fillColor = Palette.oliveTransparent
For more details on how to configure polygons, see the MMKPolygonMapObject documentation.
Polylines
Polylines are often used to display routes and trajectories.
-
Create a MMKPolyline instance with the geometry you're looking for and add a polyline map object to the map using the MMKMapObjectCollection.addPolyline(with:) method.
let polyline: MMKPolyline = { MMKPolyline( points: [ MMKPoint(latitude: 25.190614, longitude: 55.265616), MMKPoint(latitude: 25.187532, longitude: 55.275413), MMKPoint(latitude: 25.196605, longitude: 55.28094), MMKPoint(latitude: 25.198219, longitude: 55.272685) ] ) }() let polylineMapObject = collection.addPolyline(with: polyline)
-
Configure polyline styles using the MMKPolylineMapObject variable.
polylineMapObject.strokeWidth = 5.0 polylineMapObject.setStrokeColorWith(.gray) polylineMapObject.outlineWidth = 1.0 polylineMapObject.outlineColor = .black
Once you've added the polyline to the map:
For more details, see the MMKPolylineMapObject documentation.
Circles
Circles are used to display circular areas.
-
Create a MMKCircle instance with the geometry you're looking for: a center point and a radius in meters.
var circleWithRandomRadius: MMKCircle { MMKCircle(center: MMKPoint(latitude: 25.1982, longitude: 55.272758), radius: 400.0) }
-
Using the MMKMapObjectCollection.addCircle(with:stroke:strokeWidth:fill:) method, add a circle object to the map.
let circle = pinsCollection.addCircle(with: GeometryProvider.circleWithRandomRadius) circle.strokeColor = Palette.red circle.strokeWidth = 2.0 circle.fillColor = Palette.redTransparent
After adding a circle to the map:
For more details on how to configure a circular map object, see the MMKCircleMapObject documentation.
Clusters
Clusterized collections are used to display multiple placemarks.
-
Start by creating a MMKClusterListener with a single MMKClusterListener.onClusterAdded(with:) method that controls the appearance of the cluster on the map.
final class ClusterListener: NSObject, MMKClusterListener, MMKClusterTapListener { // MARK: - Constructor init(controller: UIViewController) { self.controller = controller } // MARK: - Public methods func onClusterTap(with cluster: MMKCluster) -> Bool { AlertPresenter.present( from: controller, with: "Tapped the cluster", message: "With \(cluster.size) items" ) return true } func onClusterAdded(with cluster: MMKCluster) { let placemarks = cluster.placemarks.compactMap { $0.userData as? PlacemarkUserData } cluster.appearance.setViewWithView(MRTViewProvider(uiView: ClusterView(placemarks: placemarks))) cluster.addClusterTapListener(with: self) } // MARK: - Private properties private weak var controller: UIViewController? }
The MMKCluster.appearance property returns a MMKPlacemarkMapObject object. In our example, we're using the MMKPlacemarkMapObject.setViewWithView(_:) method to change how the cluster looks.
ClusterView
is a custom defined class. Check out its implementation in our Github repository. -
Create a new nested collection using the MMKMapObjectCollection.addClusterizedPlacemarkCollection(with:) method.
clusterizedCollection = collection.addClusterizedPlacemarkCollection(with: clusterListener)
-
Add multiple placemarks to the new
clusterizedCollection
.GeometryProvider.clusterizedPoints.enumerated().forEach { pair in let index = pair.offset let point = pair.element let type = PlacemarkType.random let image = type.image let iconStyle = MMKIconStyle() iconStyle.anchor = NSValue(cgPoint: CGPoint(x: 0.5, y: 0.5)) iconStyle.scale = 0.6 let placemark = clusterizedCollection.addPlacemark() placemark.geometry = point placemark.setIconWith(image, style: iconStyle) placemark.isDraggable = true placemark.setDragListenerWith(mapObjectDragListener) placemark.userData = PlacemarkUserData(name: "Data_\(index)", type: type) placemark.addTapListener(with: mapObjectTapListener) }
-
Call the MMKClusterizedPlacemarkCollection.clusterPlacemarks(withClusterRadius:minZoom:) method. It accepts two arguments:
clusterRadius
: the minimum distance in units between objects that remain in separate clusters.minZoom
: the minimum zoom level that displays clusters.
clusterizedCollection.clusterPlacemarks(withClusterRadius: Const.clusterRadius, minZoom: Const.clusterMinZoom)
Warning
The MMKClusterizedPlacemarkCollection.clusterPlacemarks(withClusterRadius:minZoom:) should be called explicitly whenever placemarks are added to or removed from clusterized collections.
Otherwise, clusterized placemarks will be not re-rendered.
Clusterized placemarks at different zooms: