Add a label on MGLPolygon - ios

I have a situation where I need to draw an MGLPolygon on a map(MapBox) and I also want to give a UILabel like text on the polygon. The label has to be at the centroid of the polygon and it should be always visible. I found a code with which I can find the centroid of a given polygon, But I couldn't add a label to polygon. I have done the coding in SWIFT so swift developers please help me. Thanks in advance and Happy Coding :)

func mapView(_ mapView: MGLMapView, viewFor annotation: MGLAnnotation) -> MGLAnnotationView? {
if let currentAnnotation = annotation as? AreaAnnotation {
let reuseIdentifier = currentAnnotation.areaTitle
var annotationView = mapView.dequeueReusableAnnotationView(withIdentifier: reuseIdentifier!)
if annotationView == nil {
annotationView = MGLAnnotationView(reuseIdentifier: reuseIdentifier)
annotationView?.frame = CGRect(x: 0, y: 0, width: 120, height: 90)
annotationView!.backgroundColor = UIColor.clear
let detailsLabel:UILabel = UILabel()
detailsLabel.frame = CGRect(x: 30, y: 60, width: 60, height: 25)
detailsLabel.textAlignment = .center
detailsLabel.text = currentAnnotation.areaTitle
// detailsLabel.textColor = UIColor(red:175/255 ,green:255/255, blue:255/255 , alpha:0.75)
detailsLabel.textColor = UIColor.white
detailsLabel.font = UIFont(name: "HelveticaNeue-CondensedBlack", size: 15)
let strokeTextAttributes = [NSAttributedStringKey.strokeColor : UIColor.black, NSAttributedStringKey.strokeWidth : -5.0,] as [NSAttributedStringKey : Any]
detailsLabel.attributedText = NSAttributedString(string: titleLabel.text!, attributes: strokeTextAttributes)
detailsLabel.backgroundColor = UIColor.black.withAlphaComponent(1.0)
detailsLabel.clipsToBounds = true
detailsLabel.layer.cornerRadius = 5.0
detailsLabel.layer.borderWidth = 2.0
detailsLabel.layer.borderColor = UIColor.white.cgColor
annotationView?.addSubview(detailsLabel)
}
return annotationView
}
return nil
}
Thanks #jmkiley but I wanted to clear out that issue as fast as possible so I used this tweak, which was the exact thing I wanted.

If you have the center point of the polygon, you could use it to create a MGLPointFeature. Then create a MGLShapeSource and MGLSymbolStyleLayer with it. Provide the text to that layer. For example:
import Mapbox
class ViewController: UIViewController, MGLMapViewDelegate {
var mapView : MGLMapView!
var line: MGLPolyline?
override func viewDidLoad() {
super.viewDidLoad()
mapView = MGLMapView(frame: view.bounds)
view.addSubview(mapView)
mapView.delegate = self
let coords = [
CLLocationCoordinate2D(latitude: 38.0654, longitude: -88.8135),
CLLocationCoordinate2D(latitude: 41.7549, longitude: -88.8135),
CLLocationCoordinate2D(latitude: 41.7549, longitude: -83.1226),
CLLocationCoordinate2D(latitude: 38.0654, longitude: -83.1226)
]
let polygon = MGLPolygon(coordinates: coords, count: UInt(coords.count))
mapView.addAnnotation(polygon)
}
func mapView(_ mapView: MGLMapView, didFinishLoading style: MGLStyle) {
let point = MGLPointFeature()
point.coordinate = CLLocationCoordinate2D(latitude: 40.0781, longitude: -85.6714)
let source = MGLShapeSource(identifier: "point-source", features: [point], options: nil)
style.addSource(source)
let layer = MGLSymbolStyleLayer(identifier: "point-layer", source: source)
layer.text = MGLStyleValue(rawValue: "Polygon A")
style.addLayer(layer)
}
}

Related

Xcode and iOS: debugQuickLookObject() showing MKMapView

In Xcode if you hover over a variable of type CLLocation and klick on the eye symbol, Xcode shows that location on a map.
To find bugs in data that is not mine, I wanted to have the same behaviour for objects of type MKPolyline.
First the test code:
import XCTest
import MapKit
class PolylineQuicklookTests: XCTestCase {
func testPolylineQuicklook() throws {
let wilhelma = CLLocationCoordinate2D(latitude: 48.804513, longitude: 9.206237)
let fernsehturm = CLLocationCoordinate2D(latitude: 48.755890, longitude: 9.190290)
let path = [wilhelma, fernsehturm]
let polyline = MKPolyline(coordinates: path, count: path.count)
print("set breakpoint here and test polyline Quicklook")
}
}
extend MKPolyline to invoke Quicklook:
extension MKPolyline {
#objc public func debugQuickLookObject() -> Any? {
//return "MKPolyline \(self.coordinates.count)"
quickLookMapVC = QuickLookMapVC(overlays: [self], annotations: [])
let view = quickLookMapVC?.view
return view
}
}
// hold reference:
fileprivate var quickLookMapVC: QuickLookMapVC?
And a simple implementation:
fileprivate class QuickLookMapVC: UIViewController {
var overlays: [MKOverlay] = []
var annotations: [MKAnnotation] = []
var mapView = MKMapView(frame: CGRect(x: 0, y: 0, width: 400, height: 400))
var testLabel = UILabel()
init() {
super.init(nibName: nil, bundle: nil)
}
convenience init(overlays: [MKOverlay], annotations: [MKAnnotation]) {
self.init()
print("QuickLookMapVC init \(overlays.count), \(annotations.count)")
self.overlays = overlays
self.annotations = annotations
}
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
// MARK: - View lifecycle
override func viewDidLoad() {
super.viewDidLoad()
print("QuickLookMapVC start viewDidLoad")
/*
testLabel.text = "Test"
testLabel.translatesAutoresizingMaskIntoConstraints = false
self.view.addSubview(self.testLabel)
let constraints = [
testLabel.topAnchor.constraint(equalTo: view.topAnchor),
testLabel.leftAnchor.constraint(equalTo: view.leftAnchor),
view.bottomAnchor.constraint(equalTo: testLabel.bottomAnchor),
view.rightAnchor.constraint(equalTo: testLabel.rightAnchor)
]
NSLayoutConstraint.activate(constraints)
*/
mapView.delegate = self
mapView.translatesAutoresizingMaskIntoConstraints = false
self.view.addSubview(self.mapView)
let constraints = [
mapView.topAnchor.constraint(equalTo: view.topAnchor),
mapView.leftAnchor.constraint(equalTo: view.leftAnchor),
view.bottomAnchor.constraint(equalTo: mapView.bottomAnchor),
view.rightAnchor.constraint(equalTo: mapView.rightAnchor)
]
NSLayoutConstraint.activate(constraints)
mapView.mapType = .standard
mapView.addOverlays(overlays)
mapView.addAnnotations(annotations)
let stuttgart = MKCoordinateRegion(center: CLLocationCoordinate2D(latitude: 48.775846, longitude: 9.182932),
latitudinalMeters: 5000, longitudinalMeters: 5000)
mapView.region = stuttgart
/*
if annotations.count > 0 {
mapView.showAnnotations(annotations, animated: true)
}
if let firstOverlay = overlays.first {
let mapRect = firstOverlay.boundingMapRect
print(mapRect)
mapView.visibleMapRect = mapRect
}
*/
}
}
extension QuickLookMapVC: MKMapViewDelegate {
func mapView(_ mapView: MKMapView, rendererFor overlay: MKOverlay) -> MKOverlayRenderer {
if let polyline = overlay as? MKPolyline {
print("rendererFor polyline")
// for real applications do reuse instead of creating a new one each time:
let polylineRenderer = MKPolylineRenderer(polyline: polyline)
polylineRenderer.strokeColor = .red
// lineWith: defaults to 0, which is MKRoadWidthAtZoomScale(currentZoomScale)
return polylineRenderer
}
if let polygon = overlay as? MKPolygon {
print("rendererFor polygon")
let polygonrenderer = MKPolygonRenderer(polygon: polygon)
polygonrenderer.fillColor = .red
return polygonrenderer
}
print("rendererFor overlay")
return MKOverlayRenderer(overlay: overlay)
}
}
I'd expect so see at least a map.
What I'm seeing is an MKMapView with the usual Apple copyright symbols but no map.
The copyright symbols let me assume that the mapView is at least sized correctly and rendered.
Console shows
QuickLookMapVC init 1, 0
QuickLookMapVC start viewDidLoad
rendererFor polyline
When I replace MKMapView with a UILabel, the label is shown correctly.
This lets me assume that the invocation and the UIViewController parts work fine and only MKMapView is a problem.
What can I do that my code actually shows map data and a polyline?

How to get different icons to show on Annotation View in Swift?

I am new to swift. I am creating an AR app with AR annotation View, where I have created a places object to show on Annotation AR view, but I can't get different icons to show based on locations in AR view. I only get one specific icon to all the places. Please have a look at my code to help me out with this issue. Thank you very much!
Here is my code:
import UIKit
import AVFoundation
protocol AnnotationViewDelegate {
func didTouch(annotationView: AnnotationView)
}
class AnnotationView: ARAnnotationView {
var titleLabel: UILabel?
var distanceLabel: UILabel?
var delegate: AnnotationViewDelegate?
var backgroundView: UIView?
var pinImage: UIImageView?
let pinoImage = ["bakeries", "banks", "barber", "bars", "beaches", "breweries", "cardealer", "carrepair", "church", "cinema",
"coffee", "college", "dentist", "dining", "doctors", "drycleaning", "fastfood", "firetruck", "fitness", "gas",
"grocery", "hospital", "hotel", "library", "lounges", "motorcycledealers", "musicvenues", "park", "petstore",
"pharmacy", "police", "postoffice", "train", "transportation", "zoo"]
override func didMoveToSuperview() {
super.didMoveToSuperview()
loadUI()
}
func getRandomColor() -> UIColor{
let red:CGFloat = CGFloat(drand48())
let green:CGFloat = CGFloat(drand48())
let blue:CGFloat = CGFloat(drand48())
return UIColor(red:red, green: green, blue: blue, alpha: 1.0)
}
func loadUI() {
titleLabel?.removeFromSuperview()
distanceLabel?.removeFromSuperview()
backgroundView?.removeFromSuperview()
pinImage?.removeFromSuperview()
backgroundView = UIView(frame: CGRect(x: 0, y: 0, width: self.frame.size.width, height: 70))
backgroundView?.backgroundColor = #colorLiteral(red: 0, green: 0, blue: 0, alpha: 0.5)
backgroundView?.layer.cornerRadius = 10.0
self.addSubview(backgroundView!)
pinImage = UIImageView(frame: CGRect(x: 16, y: 8, width: 37.76, height: 54))
pinImage?.contentMode = UIViewContentMode.scaleAspectFit
self.backgroundView?.addSubview(pinImage!)
let label = UILabel(frame: CGRect(x: 0, y: 0, width: self.frame.size.width, height: 22.0))
label.font = UIFont(name: "AvenirNext", size: 3)
label.numberOfLines = 0
label.textAlignment = .center
label.textColor = UIColor.white
self.backgroundView?.addSubview(label)
self.titleLabel = label
distanceLabel = UILabel(frame: CGRect(x: 66, y: 47, width: self.frame.size.width, height: 15.0))
distanceLabel?.textColor = UIColor.black
distanceLabel?.font = UIFont(name: "Montserrat-Regular", size: 12)
self.backgroundView?.addSubview(distanceLabel!)
if let annotation = annotation as? Place {
titleLabel?.text = annotation.placeName
distanceLabel?.text = String(format: "%.2f mi", annotation.distanceFromUser * 0.000621371)
pinImage?.image = UIImage(named: "FastFood")
}
}
override func layoutSubviews() {
super.layoutSubviews()
backgroundView?.frame = CGRect(x: 0, y: 0, width: 170, height: 80)
titleLabel?.frame = CGRect(x: 50, y: 8, width: self.frame.size.width - 66, height: 22.0)
distanceLabel?.frame = CGRect(x: 50, y: 30, width: self.frame.size.width, height: 20)
pinImage = UIImageView(frame: CGRect(x: 16, y: 8, width: 37.76, height: 54))
}
override func touchesEnded(_ touches: Set<UITouch>, with event: UIEvent?) {
delegate?.didTouch(annotationView: self)
}
}
MapViewController
import UIKit
import MapKit
import CoreLocation
class MapViewController: BaseViewController, UITabBarDelegate{
#IBOutlet weak var leadingConstraints: NSLayoutConstraint!
#IBOutlet weak var mapView: MKMapView!
fileprivate let locationManager = CLLocationManager()
fileprivate var startedLoadingPOIs = false
fileprivate var places = [Place]()
fileprivate var arViewController: ARViewController!
#IBOutlet weak var activityIndicator: UIActivityIndicatorView!
var nearMeIndexSelected = NearMeIndexTitle()
var place: Place?
override func viewDidLoad() {
super.viewDidLoad()
mapView.delegate = self
locationManager.delegate = self
locationManager.desiredAccuracy = kCLLocationAccuracyNearestTenMeters
locationManager.startUpdatingLocation()
locationManager.requestWhenInUseAuthorization()
}
#IBAction func showARController(_ sender: Any) {
arViewController = ARViewController()
arViewController.dataSource = self
arViewController.maxVisibleAnnotations = 30
arViewController.headingSmoothingFactor = 0.05
arViewController.setAnnotations(places)
self.present(arViewController, animated: true, completion: nil)
}
}
extension MapViewController: CLLocationManagerDelegate, MKMapViewDelegate {
func mapView(_ mapView: MKMapView,
viewFor annotation: MKAnnotation) -> MKAnnotationView? {
if annotation is MKUserLocation {
mapView.tintColor = #colorLiteral(red: 0.08235294118, green: 0.7058823529, blue: 0.9450980392, alpha: 1)
return nil
} else {
let pin = mapView.view(for: annotation) ?? MKAnnotationView(annotation: annotation, reuseIdentifier: nil)
pin.image = UIImage(named: "pins")
return pin
}
}
func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
if locations.count > 0 {
let location = locations.last!
print("Accuracy: \(location.horizontalAccuracy)")
if location.horizontalAccuracy < 100 {
manager.stopUpdatingLocation()
let span = MKCoordinateSpan(latitudeDelta: 0.013, longitudeDelta: 0.013)
let region = MKCoordinateRegion(center: location.coordinate, span: span)
mapView.region = region
if !startedLoadingPOIs {
DispatchQueue.main.async {
self.activityIndicator.startAnimating()
}
startedLoadingPOIs = true
let loader = PlacesLoader()
loader.loadPOIS(location: location, radius: 1500) { placesDict, error in
if let dict = placesDict {
guard let placesArray = dict.object(forKey: "results") as? [NSDictionary] else { return }
for placeDict in placesArray {
let latitude = placeDict.value(forKeyPath: "geometry.location.lat") as! CLLocationDegrees
let longitude = placeDict.value(forKeyPath: "geometry.location.lng") as! CLLocationDegrees
let reference = placeDict.object(forKey: "reference") as! String
let name = placeDict.object(forKey: "name") as! String
let address = placeDict.object(forKey: "vicinity") as! String
let location = CLLocation(latitude: latitude, longitude: longitude)
let place = Place(location: location, reference: reference, name: name, address: address)
self.places.append(place)
let annotation = PlaceAnnotation(location: place.location!.coordinate, title: place.placeName)
DispatchQueue.main.async {
self.mapView.addAnnotation(annotation)
}
}
DispatchQueue.main.async {
self.activityIndicator.stopAnimating()
self.mapView.isHidden = false
}
}
}
}
}
}
}
}
extension MapViewController: ARDataSource {
func ar(_ arViewController: ARViewController, viewForAnnotation: ARAnnotation) -> ARAnnotationView {
let annotationView = AnnotationView()
arViewController.title = "MyApp"
annotationView.annotation = viewForAnnotation
annotationView.delegate = self
annotationView.frame = CGRect(x: 0, y: 0, width: 150, height: 50)
return annotationView
}
}
In Mapview class add the below code
func mapView(_ mapView: MKMapView, viewFor annotation: MKAnnotation) -> MKAnnotationView? {
if (annotation is MKUserLocation) {
return nil
}
let reuseId = "reuseId"
let anView : AnnotationView = mapView.dequeueReusableAnnotationView(withIdentifier: reuseId) as! AnnotationView
if let annotation = annotation as? Place {
anView.titleLabel?.text = annotation.placeName
anView.distanceLabel?.text = String(format: "%.2f mi", annotation.distanceFromUser * 0.000621371)
if(annotation.placeName == "bakeries"){
anView.pinImage?.image = UIImage(named: "Bakery")
}
else{
anView.pinImage?.image = UIImage(named: "FastFood")
}
}
anView.canShowCallout = false
return anView
}
by the above the method you can change pin custom image

GMSMarker infoWindow not updating

I'm using Google map and it's marker. For displaying information on the marker I'm using custom View to display it. But values are not updating once I init it.Below is my code for that.
func mapView(_ mapView: GMSMapView!, markerInfoWindow marker: GMSMarker) -> UIView? {
let location = CLLocation(latitude: marker.position.latitude, longitude: marker.position.longitude
var markerView : MarkerInfoView = Bundle.main.loadNibNamed("MarkerInfoView", owner: self, options: nil)![0] as! MarkerInfoView
let geoCoder = CLGeocoder()
geoCoder.reverseGeocodeLocation(location) { (placemarkers, error) in
if let placemarker = placemarkers?.last {
var strAddress = ""
if let str = placemarker.name {
strAddress += str
}
if let str = placemarker.subAdministrativeArea {
strAddress += ", " + str
}
print(strAddress)
markerView.deviceInfo.text = "HELLO TESTING"
print(markerView.deviceInfo.text!) // This is printing "HELLO TESTING", but not updating on marker
markerView.addressInfo.text = strAddress
}
}
if let str = marker.snippet {
markerView.deviceInfo.text = str.components(separatedBy: "|")[0]
//TODO: add time
markerView.dateInfo.text = str.components(separatedBy: "|")[1]
// markerView.addressInfo.text = ""
}
else {
markerView.deviceInfo.text = ""
markerView.dateInfo.text = ""
// markerView.addressInfo.text = ""
}
return markerView
}
Please guide me how to update values in infoWindow.
Try this code
// MARKER - GoogleMaps delegate
func mapView(_ mapView: GMSMapView, markerInfoContents marker: GMSMarker) -> UIView? {
print("title \(markerTitle)")
var infoView:UIView!
infoView = UIView()
infoView.frame = CGRect(x: 0, y: 0, width: 300, height: 75)
infoView.backgroundColor = .black
let orderIDLbl = UILabel(frame: CGRect(x: 0, y: 0, width: 300, height: 75))
orderIDLbl.text = "markerTitle" //Your title here
orderIDLbl.font = UIFont.systemFont(ofSize: 15)
orderIDLbl.textAlignment = NSTextAlignment.center
orderIDLbl.numberOfLines = 0
orderIDLbl.textColor = .white
infoView.addSubview(orderIDLbl)
return infoView
}

MapView annotation showing image and title

I am developing an app in which I should present MapView annotations showing an image and a title. The following View Controller Swift code shows a default pin image with the desired title right below:
import UIKit
import MapKit
class ViewController: UIViewController, MKMapViewDelegate, CLLocationManagerDelegate {
#IBOutlet weak var mapView: MKMapView!
var locationManager = CLLocationManager()
override func viewDidLoad() {
super.viewDidLoad()
mapView.delegate = self
locationManager.delegate = self
// Define zoom
let deltaLat: CLLocationDegrees = 1.0
let deltaLon: CLLocationDegrees = 1.0
// Define location of center coordinates
let location: CLLocationCoordinate2D = CLLocationCoordinate2DMake(-15.3, -47.0)
// Define area to be viwed
let areaVisual: MKCoordinateSpan = MKCoordinateSpanMake(deltaLat, deltaLon)
let region = MKCoordinateRegionMake(location, areaVisual)
let annotation = MKPointAnnotation()
annotation.coordinate = location
annotation.title = "SDKP"
mapView.addAnnotation(annotation)
// Show map region defined by the above parameters
mapView.setRegion(region, animated: true)
}
/*
// Show an image for annotation
func mapView(_ mapView: MKMapView, viewFor annotation: MKAnnotation) -> MKAnnotationView? {
let annotationView = MKAnnotationView(annotation: annotation, reuseIdentifier: nil)
annotationView.image = imageLiteral(resourceName: "AnnotationImage")
return annotationView
}
*/
}
This is the MapView I get with this:
When I un-comment the view for annotation method, I get the desired annotation image, but not the title:
Any ideas on how can I get both the image and title at the same time for the annotation?
I found a solution in which I use the func imageFromLabel(_:) in code below to extend UIImage to create an image from a label text which is the title for the annotation. Then I combine the annotation image with this title image through the func combineImageAndTitle(_:_:). Finally, this combined image is showed by the mapView delegate method viewFor annotation.
Since I am still a beginner with Swift, I am not sure if it is the best way to do that. But this solution is working fine for me.
import UIKit
import MapKit
class ViewController: UIViewController, MKMapViewDelegate, CLLocationManagerDelegate {
#IBOutlet weak var mapView: MKMapView!
var locationManager = CLLocationManager()
override func viewDidLoad() {
super.viewDidLoad()
mapView.delegate = self
locationManager.delegate = self
// Define zoom
let deltaLat: CLLocationDegrees = 1.0
let deltaLon: CLLocationDegrees = 1.0
// Define location of center coordinates
let location: CLLocationCoordinate2D = CLLocationCoordinate2DMake(-15.3, -47.0)
// Define area to be viwed
let areaVisual: MKCoordinateSpan = MKCoordinateSpan(latitudeDelta: deltaLat, longitudeDelta: deltaLon)
let region = MKCoordinateRegion(center: location, span: areaVisual)
let annotation = MKPointAnnotation()
annotation.coordinate = location
annotation.title = "SDKP"
mapView.addAnnotation(annotation)
// Show map region defined by the above parameters
mapView.setRegion(region, animated: true)
}
// Delegate method for mapView
func mapView(_ mapView: MKMapView, viewFor annotation: MKAnnotation) -> MKAnnotationView? {
let annotationView = MKAnnotationView(annotation: annotation, reuseIdentifier: nil)
let imageForAnnotation = #imageLiteral(resourceName: "BaseImage")
let annotationTitle = (annotation.title ?? "") ?? ""
//annotationView.image = imageForAnnotation
annotationView.image = combineImageAndTitle(image: imageForAnnotation, title: annotationTitle)
return annotationView
}
/// Combine image and title in one image.
func combineImageAndTitle(image: UIImage, title: String) -> UIImage {
// Create an image from ident text
let label = UILabel(frame: CGRect(x: 0, y: 0, width: 100, height: 20))
label.numberOfLines = 1
label.textAlignment = .center
label.textColor = UIColor.black
label.text = title
let titleImage = UIImage.imageFromLabel(label: label)
// Resulting image has a 100 by 100 size
let contextSize = CGSize(width: 100, height: 100)
UIGraphicsBeginImageContextWithOptions(contextSize, false, UIScreen.main.scale)
let rect1 = CGRect(x: 50 - Int(image.size.width / 2), y: 50 - Int(image.size.height / 2), width: Int(image.size.width), height: Int(image.size.height))
image.draw(in: rect1)
let rect2 = CGRect(x: 0, y: 53 + Int(image.size.height / 2), width: Int(titleImage.size.width), height: Int(titleImage.size.height))
titleImage.draw(in: rect2)
let combinedImage = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()
return combinedImage!
}
}
extension UIImage {
/// Convert a label to an image
class func imageFromLabel(label: UILabel) -> UIImage {
UIGraphicsBeginImageContextWithOptions(label.bounds.size, false, 0.0)
label.layer.render(in: UIGraphicsGetCurrentContext()!)
let img = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()
return img!
}
}
And this is the resulting MapView.
You can use MKMarkerAnnotationView and glyphImage property. Try the following code
func mapView(_ mapView: MKMapView, viewFor annotation: MKAnnotation) -> MKAnnotationView? {
let annotationView = MKMarkerAnnotationView(annotation: annotation, reuseIdentifier: nil)
annotationView.glyphImage = UIImage(named: "Laugh")
return annotationView
}

add a permanent label below a marker swift

I want to add multiple markers to the map view. Each marker having a text label below it always i.e it should always be visible. Also I want to add my own image as its icon.
Herewith I am attaching a screenshot of what I want.
Code Work
func addGroundOverlay(position: CLLocationCoordinate2D, veh_num: String) {
let overlay = GMSGroundOverlay(position: position, icon: newImage(text: veh_num, size: CGSize(width: 150.0, height: 150.0)), zoomLevel: 10)
overlay.bearing = 0
overlay.map = (self.view as! GMSMapView)
}
func newImage(text: String, size: CGSize) -> UIImage {
let data = text.data(using: String.Encoding.utf8, allowLossyConversion: true)
let drawText = NSString(data: data!, encoding: String.Encoding.utf8.rawValue)
let textFontAttributes = [
NSAttributedStringKey.font: UIFont(name: "Helvetica Bold", size: 10)!,
NSAttributedStringKey.foregroundColor: UIColor.red,
]
UIGraphicsBeginImageContextWithOptions(size, false, 0)
drawText?.draw(in: CGRect(x: 0,y: 0, width: size.width, height: size.height), withAttributes: textFontAttributes)
let newImage = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()
return newImage!
}
Image for what I have tried
result image
I found out the solution, as lack of time I tried for Apple Map, but you try for google map also.
Steps
Get the location where you wanted to show annotation.
Add this point annotation on Map.
Create a UILabel(says, lbl) with text as you wanted.
Add this text on a view (says, viewAn).
Now capture the viewAn and make it image.
Use this image for location marker.
Below is the code work for Apple Map and out of simulator is added below it and it is working properly. Follow the above steps and definatly it will work for google map also.
Code Work
import UIKit
import MapKit
class MapVC: UIViewController, MKMapViewDelegate {
#IBOutlet weak var mapView: MKMapView! // Apple mapview Outlet
var location: CLLocationCoordinate2D = CLLocationCoordinate2D(latitude: 28.5961279, longitude: 77.1587375)
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
let anno = MKPointAnnotation();
anno.coordinate = location;
mapView.addAnnotation(anno);
}
// To capture view
func captureScreen(_ viewcapture : UIView) -> UIImage {
UIGraphicsBeginImageContextWithOptions(viewcapture.frame.size, viewcapture.isOpaque, 0.0)
viewcapture.layer.render(in: UIGraphicsGetCurrentContext()!)
let image = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()
return image!;
}
func mapView(_ mapView: MKMapView, viewFor annotation: MKAnnotation) -> MKAnnotationView? {
// Don't want to show a custom image if the annotation is the user's location.
guard !(annotation is MKUserLocation) else {
return nil
}
// Better to make this class property
let annotationIdentifier = "AnnotationIdentifier"
var annotationView: MKAnnotationView?
if let dequeuedAnnotationView = mapView.dequeueReusableAnnotationView(withIdentifier: annotationIdentifier) {
annotationView = dequeuedAnnotationView
annotationView?.annotation = annotation
}
else {
annotationView = MKAnnotationView(annotation: annotation, reuseIdentifier: annotationIdentifier)
annotationView?.rightCalloutAccessoryView = UIButton(type: .detailDisclosure)
}
if let annotationView = annotationView {
// Configure your annotation view here
// view for annotation
let viewAn = UIView()
viewAn.frame = CGRect(x: 0, y: 0, width: 80, height: 18)
// label as required
let lbl = UILabel()
lbl.text = "ABC 123"
lbl.textColor = UIColor.black
lbl.backgroundColor = UIColor.cyan
// add label to viewAn
lbl.frame = viewAn.bounds
viewAn.addSubview(lbl)
// capture viewAn
let img = self.captureScreen(viewAn)
annotationView.canShowCallout = true
// set marker
annotationView.image = img
}
return annotationView
}
}
OutPut :
Edit : image trasparency
use this below func
func changeWhiteColorTransparent(_ image: UIImage) -> UIImage {
let rawImageRef = image.cgImage as! CGImage
let colorMasking : [CGFloat] = [222, 255, 222, 255, 222, 255]
UIGraphicsBeginImageContext(image.size)
let maskedImageRef: CGImage = rawImageRef.copy(maskingColorComponents: colorMasking)!
do {
//if in iphone
UIGraphicsGetCurrentContext()?.translateBy(x: 0.0, y: image.size.height)
UIGraphicsGetCurrentContext()?.scaleBy(x: 1.0, y: -1.0)
}
UIGraphicsGetCurrentContext()?.draw(maskedImageRef, in: CGRect(x: 0, y: 0, width: image.size.width, height: image.size.height))
let result = UIGraphicsGetImageFromCurrentImageContext() as! UIImage
UIGraphicsEndImageContext()
return result ?? UIImage()
}
Func callie
Replace code of upper annotationview with below
let viewAn = UIView()
viewAn.frame = CGRect(x: 0, y: 0, width: 80, height: 18)
let lbl = UILabel()
lbl.text = "ABC 123"
lbl.textColor = UIColor.black
lbl.backgroundColor = UIColor.clear
viewAn.backgroundColor = UIColor.white
lbl.frame = viewAn.bounds
viewAn.addSubview(lbl)
let img = self.captureScreen(viewAn)
let aImgNew = self.changeWhiteColorTransparent(img)
annotationView.backgroundColor = UIColor.clear
annotationView.canShowCallout = true
annotationView.image = aImgNew
Output:

Resources