GMSMarker iconView weird behaviour when transform the marker - ios

I am currently using Google Maps in an iOS application where I used iconView for the Marker when I tapped on the marker and scale the current selected marker other marker looks weird.
func mapView(_ mapView: GMSMapView, didTap marker: GMSMarker) -> Bool
{
if marker.userData != nil
{
let index : Int = Int(marker.userData as! String)!
//small all the marker
_ = markers.map { (marker) in
marker.iconView?.transform = CGAffineTransform.identity
}
markers[index].iconView?.transform = CGAffineTransform(scaleX: 1.5, y: 1.5)
setVenuePin(index: index)
}
return false
}

Related

How to customize default pin marker using Google Cluster Manager?

How to customize default NOT CLUSTER, but red pin marker using Google Cluster Manager? There are some similar questions around but no working answer.
When I using:
func renderer(_ renderer: GMUClusterRenderer, willRenderMarker marker: GMSMarker) {
marker.icon = UIImage(named: "my_marker")
marker.setIconSize(scaledToSize: .init(width: 18, height: 24))
}
It customizes clusters and icons too. How to customize pin marker only not cluster marker?
marker has a property iconView which is a UIView. Since it's a UIView you can customize however you want.
func renderer(_ renderer: GMUClusterRenderer, willRenderMarker marker: GMSMarker) {
marker.iconView = MyView()
}
Works in Swift 5
class POIItem: NSObject, GMUClusterItem {
var position: CLLocationCoordinate2D
var name: String!
var icon: UIImage
init(position: CLLocationCoordinate2D, name: String, icon: UIImage) {
self.position = position
self.name = name
self.icon = icon
}
}
class PrincipalViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
self.google_map.clear()
let iconGenerator = GMUDefaultClusterIconGenerator()
let algorithm = GMUNonHierarchicalDistanceBasedAlgorithm()
let renderer = GMUDefaultClusterRenderer(mapView: self.google_map, clusterIconGenerator: iconGenerator)
renderer.delegate = self
self.clusterManager = GMUClusterManager(map: self.google_map, algorithm: algorithm, renderer: renderer)
self.clusterManager.setDelegate(self, mapDelegate: self)
//insert your markers type POIItem
//self.clusterManager.add(item)
self.clusterManager.cluster()
}
}
extension PrincipalViewController: GMUClusterRendererDelegate {
func renderer(_ renderer: GMUClusterRenderer, willRenderMarker marker: GMSMarker) {
if marker.userData is POIItem {
if let item = marker.userData as? POIItem {
marker.icon = item.icon
marker.title = item.name
}
}
if marker.userData is GMUStaticCluster {
if let staticCluster = marker.userData as? GMUStaticCluster {
//this is a custom UIView (.xib) contain a UIImage with custom marker and one label (countLabel) where show number of grouped markers
let customClusterMarker:CustomClusterMarker = CustomClusterMarker()
customClusterMarker.countLabel.text = "\(staticCluster.count)"
let view = UIView(frame: CGRect(x: 0, y: 0, width: 52, height: 70))
view.addSubview(customClusterMarker)
marker.iconView = view
}
}
}
}
extension PrincipalViewController: GMUClusterManagerDelegate {
func clusterManager(_ clusterManager: GMUClusterManager, didTap clusterItem: GMUClusterItem) -> Bool {
print("didTap clusterItem")
return true
}
func clusterManager(_ clusterManager: GMUClusterManager, didTap cluster: GMUCluster) -> Bool {
print("didTap cluster")
return true
}
}

why annotationView cannot be selected when moving animation

When the animation is executing , i try to click the moving annotationView ,but cannnot be selected, the mapView(_ mapView: MKMapView, didSelect view: MKAnnotationView) hasn't been called
func addMoveAnimation() {
guard let ano = annotation as? Annotation else {
return
}
animator = UIViewPropertyAnimator.init(duration: 10, curve: .linear, animations: {
ano.coordinate = CLLocationCoordinate2D(latitude: 32.449819, longitude: 112.292726)
})
animator?.startAnimation()
animator?.addCompletion({ (position) in
print(position.des,"coor:", ano.coordinate)
})
}
i try to add a UITapGestureRecognizer for the annotationView, and it really works, but then quickly changed to be deseleted, and the mapView(_ mapView: MKMapView, didDeselect view: MKAnnotationView) also be called
#objc func handleGes() {
print("tap ges click")
removeAnimation()
let currentFrame = (layer.presentation() as! CALayer).frame
layer.removeAllAnimations()
let point = CGPoint.init(x: currentFrame.midX, y: currentFrame.midY)
let coor = mapView?.convert(point, toCoordinateFrom: mapView)
guard let ano = annotation as? Annotation, let coordinate = coor else {
return
}
ano.coordinate = coordinate
print(ano.coordinate)
mapView?.selectAnnotation(ano, animated: false)
}

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
}

didTapAtCoordinate not showing selected Marker - Google Maps IOS

I want to change the icon of my selected marker to a deselected one if the user taps on the map. I am using the following delegate method :
internal func mapView(_ mapView: GMSMapView, didTapAt coordinate: CLLocationCoordinate2D) {
print("\(map.selectedMarker) ===> Selected Marker")
}
however map.selectedMarker always comes nil. Even when the documentation says This is called before deselecting any currently selected marker (the implicit action for tapping on the map)
so I was expecting to be able to see my selected marker.
This is the code I am running when a marker gets tapped
internal func mapView(_ mapView: GMSMapView, didTap marker: GMSMarker) -> Bool {
if map.selectedMarker == marker {
return true
}
if let selectedMarker = map.selectedMarker {
deselectActiveMarker(currentSelectedMarker: selectedMarker)
}
selectMarker(marker: marker)
return true
}
the selectMarker(marker: marker) method is the following one:
private func selectMarker(marker: GMSMarker) {
marker.iconView?.setAnchorPoint(anchorPoint: CGPoint(x: 0.5, y: 0))
if let cluster = marker.userData as? GMUCluster {
let count = "\(cluster.count)" as NSString
if let icon = UIImage(named: "clusterSelected") {
marker.iconView = UIImageView(image: createIconWithCount(drawText: count, inImage: icon, isSelected: true))
}
}
else {
if let icon = UIImage(named: "pinSelected") {
marker.iconView = UIImageView(image: icon)
}
}
marker.iconView?.transform = CGAffineTransform(scaleX: 0, y: 0)
UIView.animate(withDuration: 0.3, delay: 0, usingSpringWithDamping: 0.8, initialSpringVelocity: 5, options: .curveEaseIn, animations: {
marker.iconView?.transform = CGAffineTransform(scaleX: 1, y: 1)
}, completion: {
[weak self = self]
_ in
guard let instance = self else { return }
instance.map.selectedMarker = marker
})
}
Hopefully you can help me. Thanks

Polyline won't show up in MapKit

I'm using Xcode 8.3.2 so first I import mapkit. Then I set markers to the map. Then I add the following code to add a polyline to the map but it won't show any.
class ViewController: UIViewController, MKMapViewDelegate {
#IBOutlet weak var mapView: MKMapView!
override func viewDidLoad() {
self.mapView.delegate = self
super.viewDidLoad()
let template = "http://tile.openstreetmap.org/{z}/{x}/{y}.png"
let point1 = CLLocationCoordinate2D(latitude: 6.9271, longitude: 79.8612);
let point2 = CLLocationCoordinate2D(latitude: 9.6615, longitude: 80.0255);
let overlay = MKTileOverlay(urlTemplate: template)
overlay.canReplaceMapContent = true
let location = CLLocationCoordinate2DMake(6.878069, 79.892119)
mapView.add(overlay, level: .aboveLabels)
mapView.setRegion(MKCoordinateRegionMakeWithDistance(location, 1100, 1100), animated: true)
let pin = PinAnnotation(title: "Nimbus", subtitle: "Best", coordinate: location)
mapView.addAnnotation(pin)
let points: [CLLocationCoordinate2D]
points = [point1, point2]
let polyline = MKGeodesicPolyline(coordinates: points, count: 3)
mapView.add(polyline)
UIView.animate(withDuration: 1.5, animations: { () -> Void in
let span = MKCoordinateSpanMake(0.01, 0.01)
let region1 = MKCoordinateRegion(center: point1, span: span)
self.mapView.setRegion(region1, animated: true)
})
}
func mapView(_ mapview: MKMapView, rendererFor overlay: MKOverlay) ->MKOverlayRenderer{
if let overlayGeodesic = overlay as? MKGeodesicPolyline
{
let overLayRenderer = MKPolylineRenderer(polyline: overlayGeodesic)
overLayRenderer.lineWidth = 5
overLayRenderer.strokeColor = UIColor.blue
return overLayRenderer
}
return MKOverlayRenderer(overlay: overlay)
}
First you need to add this line, I think you already have added but anyway
self.mapView.delegate = self
After that you need to implement this MKMapViewDelegate method func mapView(_ mapView: MKMapView, rendererFor overlay: MKOverlay) -> MKOverlayRenderer and return the MKOverlayRenderer needed for your current overlay in this case MKPolylineRenderer this is an important part if you don't implement this method then you never will have your polyline rendered
implementation will be something like this
func mapView(_ mapView: MKMapView, rendererFor overlay: MKOverlay) -> MKOverlayRenderer {
if let overlayGeodesic = overlay as? MKGeodesicPolyline
{
let overLayRenderer = MKPolylineRenderer(polyline: overlayGeodesic)
overLayRenderer.lineWidth = 5
overLayRenderer.strokeColor = UIColor.blue
return overLayRenderer
}
if let overlayTile = overlay as? MKTileOverlay{
let overLayRenderer = MKTileOverlayRenderer(tileOverlay: overlayTile)
return overLayRenderer
}
return MKOverlayRenderer(overlay: overlay)
}
And voila! there is your polyLine rendered

Resources