I'm trying to implement an annotation with user picture, it works, but then, tap annotation recognition stops working.
How can I delegate subview tap to map ?
Here is my override function
func mapView(mapView: MKMapView, viewForAnnotation annotation: MKAnnotation) -> MKAnnotationView? {
if annotation.isKindOfClass(MKUserLocation) {
let reuseId = "test"
var anView = mapView.dequeueReusableAnnotationViewWithIdentifier(reuseId)
if anView == nil
{
let imgUserPic: UIImageView = UIImageView(frame: CGRect(x: 0, y: 0, width: 60, height: 60))
if (userPic != nil) {
imgUserPic.autoresizingMask = UIViewAutoresizing.FlexibleBottomMargin.intersect(UIViewAutoresizing.FlexibleHeight).intersect(UIViewAutoresizing.FlexibleRightMargin).intersect(UIViewAutoresizing.FlexibleLeftMargin).intersect(UIViewAutoresizing.FlexibleTopMargin).intersect(UIViewAutoresizing.FlexibleWidth)
imgUserPic.contentMode = UIViewContentMode.ScaleAspectFill
imgUserPic.layer.cornerRadius = 30
imgUserPic.layer.masksToBounds = true
imgUserPic.layer.borderColor = UIColor.whiteColor().CGColor
imgUserPic.layer.borderWidth = 1.0
imgUserPic.image = userPic
imgUserPic.userInteractionEnabled = true
let info: MKPointAnnotation = MKPointAnnotation()
info.title = NSLocalizedString("MYLOCATION", comment: "")
info.coordinate = annotation.coordinate
anView = MKAnnotationView(annotation: info, reuseIdentifier: reuseId)
anView?.addSubview(imgUserPic)
anView?.calloutOffset = CGPointMake(0, 32)
anView!.canShowCallout = true
}
} else {
anView?.annotation = annotation
}
return anView
} else {
return nil
}
}
Related
I have a map view in my app that displays the user's location. when the user's location is tapped an image is displayed as below:
is there a way to make this image customized to my liking, so for instance I would like to show the photo that the user has in his own profile, or any other static image that I would like to add.
similar to how the apple maps would show your profile picture in your location dot.
how can I do that here?
here is my code:
func mapView(_ mapView: MKMapView, viewFor annotation: MKAnnotation) -> MKAnnotationView? {
if annotation is MKUserLocation {
print("user location image tapped")
return nil
}
let reuseId = "pin"
var pinView = mapView.dequeueReusableAnnotationView(withIdentifier: reuseId) as? MKPinAnnotationView
if pinView == nil {
pinView = MKPinAnnotationView(annotation: annotation, reuseIdentifier: reuseId)
pinView?.animatesDrop = true
pinView?.canShowCallout = true
pinView?.isDraggable = true
// pinView?.pinColor = .purple
let rightButton: AnyObject! = UIButton(type: UIButton.ButtonType.detailDisclosure)
pinView?.rightCalloutAccessoryView = rightButton as? UIView
}
else {
pinView?.annotation = annotation
}
return pinView
}
any help on this? thank you.
let imageView = UIImageView(frame: CGRect(0, 0, 25, 25))
imageView.image = UIImage(named: "userpic");
imageView.layer.cornerRadius = imageView.layer.frame.size.width / 2
imageView.layer.masksToBounds = true
anotationView.frame = imageView.frame
I'm trying to update the colour of the mapView pins based on whether the hotspot has been visited or not.
See my code below. Below is the hotspot class that subscribes to the MKAnnotation delegate. The property that determines pin colour is the visited Bool.
init(title: String, hotspotName: String,coordinate: CLLocationCoordinate2D, ARType:String, hotspotId:String)
{
//assing values to properties
self.hotspotTitle = title
self.hotspotName = hotspotName
self.ARType = ARType
self.coordinate = coordinate
self.hotspotId = hotspotId
super.init()
}
var visited: Bool {
return self.completed
}
var title: String?
{
return hotspotTitle
}
var subtitle: String?
{
return hotspotName
}
Below is the mapKit delegate method I'm using to try and update pin colour.
func mapView(_ mapView: MKMapView, viewFor annotation: MKAnnotation) -> MKAnnotationView? {
// check if annotation is of type Hotspot, as we dont want to alter other types of annotations
guard annotation is Hotspot else {
return nil
}
let identifier = "Hotspot"
var annotationView = mapView.dequeueReusableAnnotationView(withIdentifier: identifier)
let pinView = MKPinAnnotationView(annotation:annotation,reuseIdentifier: identifier)
if annotationView == nil
{
if let hotspot = annotationView?.annotation as? Hotspot {
if !hotspot.visited
{
pinView.pinTintColor = UIColor(red:0.32, green:0.82, blue:0.4, alpha:1)
pinView.tintColor = UIColor(white: 0.0, alpha: 0.5)
}
else
{
pinView.pinTintColor = UIColor(red:0.0, green:0.0, blue:0.90, alpha:1)
pinView.tintColor = UIColor(white: 0.0, alpha: 0.5)
}
}
pinView.frame = mapView.frame
pinView.isEnabled = true
pinView.canShowCallout = true
pinView.animatesDrop = true
let rightButton = UIButton(type: .detailDisclosure)
rightButton.addTarget(self,action: #selector(getDirections),for: .touchUpInside)
pinView.rightCalloutAccessoryView = rightButton
annotationView = pinView
}
if let annotationView = annotationView
{
annotationView.annotation = annotation
// 5
let button = annotationView.rightCalloutAccessoryView as! UIButton
if let index = trail.hotspots.index(of: annotation as! Hotspot)
{
button.tag = index
}
}
return annotationView
}
Update mapView pin colour out of if annotationView == nil statement.
func mapView(_ mapView: MKMapView, viewFor annotation: MKAnnotation) -> MKAnnotationView? {
// check if annotation is of type Hotspot, as we dont want to alter other types of annotations
guard annotation is Hotspot else {
return nil
}
let identifier = "Hotspot"
var annotationView = mapView.dequeueReusableAnnotationView(withIdentifier: identifier)
let pinView = MKPinAnnotationView(annotation:annotation,reuseIdentifier: identifier)
if annotationView == nil
{
pinView.frame = mapView.frame
pinView.isEnabled = true
pinView.canShowCallout = true
pinView.animatesDrop = true
let rightButton = UIButton(type: .detailDisclosure)
rightButton.addTarget(self,action: #selector(getDirections),for: .touchUpInside)
pinView.rightCalloutAccessoryView = rightButton
annotationView = pinView
}
if let hotspot = annotationView?.annotation as? Hotspot {
if !hotspot.visited
{
annotationView.pinTintColor = UIColor(red:0.32, green:0.82, blue:0.4, alpha:1)
annotationView.tintColor = UIColor(white: 0.0, alpha: 0.5)
}
else
{
annotationView.pinTintColor = UIColor(red:0.0, green:0.0, blue:0.90, alpha:1)
annotationView.tintColor = UIColor(white: 0.0, alpha: 0.5)
}
}
if let annotationView = annotationView
{
annotationView.annotation = annotation
// 5
let button = annotationView.rightCalloutAccessoryView as! UIButton
if let index = trail.hotspots.index(of: annotation as! Hotspot)
{
button.tag = index
}
}
return annotationView
}
I can't display all the addresses in my variable
var allAddress: [Address] = []
In this variable i get from firebase a small amount of addresses and i want to display all addresses in my annotationView, but when i try to display all addresses i see only one address in all annotationView though if i make printed my using for..in.. index i see index0, index1, index2, index3 and other... as well if i printed this:
print("address - \(allAddress[index].address)")
i get all address which i have in firebase, their total 6.
It's print my index and allAddress[index].address
index 1
address - Москва, ул. Правды д.24, строение 3
index 2
address - Москва, ул.Электрозаводская д.21
index 3
address - Москва, ул.Бутырская д.8
index 4
address - Москва, 2-Я Звенигородская улица 12 строение 21
index 5
address - Москва, Николоямская 52, стр. 1
It's my code:
let centerInfo = UILabel(frame: CGRect(x: 0, y: 0, width: 150, height: 100))
for index in 0..<allAddress.count {
print("index \(index)")
centerInfo.text = allAddress[index].address
centerInfo.numberOfLines = 0
centerInfo.lineBreakMode = .byWordWrapping
print("address - \(allAddress[index].address)")
}
annotationView?.detailCalloutAccessoryView = centerInfo
How i can display all addresses in my centerInfo.text?
And pls check .gif which shows the same address on all annotationView
P.S. in annotation.title don't need to use, me do not fit
UPDATED. All code:
class AllAddressMapViewController: UIViewController, MKMapViewDelegate, CLLocationManagerDelegate {
#IBOutlet weak var mapView: MKMapView!
var allAddress: [Address] = []
var studioRef: DatabaseReference!
override func viewDidLoad() {
super.viewDidLoad()
studioRef = Database.database().reference(withPath: "Photo1")
studioRef.observe(.value, with: { (snapshot) in
for imageSnap in snapshot.children {
let studioObj = Studio(snapshot: imageSnap as! DataSnapshot)
self.allAddress.append(studioObj)
for index in 0..<self.allAddress.count {
let geocoder = CLGeocoder()
geocoder.geocodeAddressString(self.allAddress[index].address, completionHandler: { (placemarks, error) in
guard error == nil else { return }
guard let placemarks = placemarks else { return }
if let placemark = placemarks.first {
let annotation = MKPointAnnotation()
guard let address = placemark.location else { return }
annotation.coordinate = address.coordinate
self.mapView.addAnnotation(annotation)
}
geocoder.cancelGeocode()
})
}
}
})
mapView.delegate = self
mapView.mapType = .standard
mapView.isZoomEnabled = true
mapView.isScrollEnabled = true
}
func mapView(_ mapView: MKMapView, viewFor annotation: MKAnnotation) -> MKAnnotationView? {
guard !(annotation is MKUserLocation) else { return nil }
let annotationID = "PinMap"
var annotationView = mapView.dequeueReusableAnnotationView(withIdentifier: annotationID) as? MKPinAnnotationView
if annotationView == nil {
annotationView = MKPinAnnotationView(annotation: annotation, reuseIdentifier: annotationID)
annotationView?.canShowCallout = true
} else {
annotationView?.annotation = annotation
}
let leftImageNavigationButton = UIImage(named: "auto")
let tintedColorleftImageNavigationButton = leftImageNavigationButton?.withRenderingMode(.alwaysTemplate)
let leftNavigationButton = UIButton(type: .custom)
leftNavigationButton.frame = CGRect(x: 0, y: 0, width: 40, height: 40)
leftNavigationButton.setImage(tintedColorleftImageNavigationButton, for: UIControlState())
leftNavigationButton.tintColor = #colorLiteral(red: 0, green: 0.4784313725, blue: 1, alpha: 1)
annotationView?.leftCalloutAccessoryView = leftNavigationButton
let rightButtonInfo = UIButton(type: .detailDisclosure)
annotationView?.rightCalloutAccessoryView = rightButtonInfo
let centerInfo = UILabel(frame: CGRect(x: 0, y: 0, width: 150, height: 100))
for index in 0..<allAddress.count {
print("index \(index)")
centerInfo.text = allAddress[index].address
centerInfo.numberOfLines = 0
centerInfo.lineBreakMode = .byWordWrapping
print("address - \(allAddress[index].address)")
}
annotationView?.detailCalloutAccessoryView = centerInfo
annotationView?.calloutOffset = CGPoint(x: -8, y: 0)
return annotationView
}
}
From your code, it looks , you are using same UILabel for all annotation and in loop you are setting the text property of the same UILabel every time. That's why it's showing the last address on all annotation.
Try to assign a separate UILabel for each annotation and set text property to the designated address
Well, the idea is to get all annotations on your map like that and try to find the right annotation index to reuse it into your allAddress array :
var indexValue = 0
for annotationInMap in mapView.annotations {
if annotation == annotationInMap {
let centerInfo = UILabel(frame: CGRect(x: 0, y: 0, width: 150, height: 100))
centerInfo.text = allAddress[indexValue].address
centerInfo.numberOfLines = 0
centerInfo.lineBreakMode = .byWordWrapping
annotationView?.detailCalloutAccessoryView = centerInfo
}
indexValue = indexValue + 1
}
How about setting address to annotation.title in viewDidLoad, and get annotation.title in viewFor method.
class AllAddressMapViewController: UIViewController, MKMapViewDelegate, CLLocationManagerDelegate {
#IBOutlet weak var mapView: MKMapView!
var allAddress: [Address] = []
var studioRef: DatabaseReference!
override func viewDidLoad() {
super.viewDidLoad()
studioRef = Database.database().reference(withPath: "Photo1")
studioRef.observe(.value, with: { (snapshot) in
for imageSnap in snapshot.children {
let studioObj = Studio(snapshot: imageSnap as! DataSnapshot)
self.allAddress.append(studioObj)
for index in 0..<self.allAddress.count {
let geocoder = CLGeocoder()
geocoder.geocodeAddressString(self.allAddress[index].address, completionHandler: { (placemarks, error) in
guard error == nil else { return }
guard let placemarks = placemarks else { return }
if let placemark = placemarks.first {
let annotation = MKPointAnnotation()
guard let address = placemark.location else { return }
annotation.coordinate = address.coordinate
annotation.title = self.allAddress[index].address
self.mapView.addAnnotation(annotation)
}
geocoder.cancelGeocode()
})
}
}
})
mapView.delegate = self
mapView.mapType = .standard
mapView.isZoomEnabled = true
mapView.isScrollEnabled = true
}
func mapView(_ mapView: MKMapView, viewFor annotation: MKAnnotation) -> MKAnnotationView? {
guard !(annotation is MKUserLocation) else { return nil }
let annotationID = "PinMap"
var annotationView = mapView.dequeueReusableAnnotationView(withIdentifier: annotationID) as? MKPinAnnotationView
if annotationView == nil {
annotationView = MKPinAnnotationView(annotation: annotation, reuseIdentifier: annotationID)
annotationView?.canShowCallout = true
} else {
annotationView?.annotation = annotation
}
let leftImageNavigationButton = UIImage(named: "auto")
let tintedColorleftImageNavigationButton = leftImageNavigationButton?.withRenderingMode(.alwaysTemplate)
let leftNavigationButton = UIButton(type: .custom)
leftNavigationButton.frame = CGRect(x: 0, y: 0, width: 40, height: 40)
leftNavigationButton.setImage(tintedColorleftImageNavigationButton, for: UIControlState())
leftNavigationButton.tintColor = #colorLiteral(red: 0, green: 0.4784313725, blue: 1, alpha: 1)
annotationView?.leftCalloutAccessoryView = leftNavigationButton
let rightButtonInfo = UIButton(type: .detailDisclosure)
annotationView?.rightCalloutAccessoryView = rightButtonInfo
let centerInfo = UILabel(frame: CGRect(x: 0, y: 0, width: 150, height: 100))
for index in 0..<allAddress.count {
print("index \(index)")
centerInfo.text = annotation.title
centerInfo.numberOfLines = 0
centerInfo.lineBreakMode = .byWordWrapping
print("address - \(allAddress[index].address)")
}
annotationView?.detailCalloutAccessoryView = centerInfo
annotationView?.calloutOffset = CGPoint(x: -8, y: 0)
return annotationView
}
I have MKAnnotationView where I am showing title,subtitle and info button, on tap of location pin.
I have added the following code
func mapView(mapView: MKMapView, viewForAnnotation annotation: MKAnnotation) -> MKAnnotationView? {
if annotation is MKUserLocation {
//return nil so map view draws "blue dot" for standard user location
return nil
}
let reuseId = "pin"
let pinView = MKPinAnnotationView(annotation: annotation, reuseIdentifier: reuseId)
pinView.canShowCallout = true
pinView.animatesDrop = true
pinView.pinTintColor = UIColor.darkGrayColor()
pinView.draggable = true
let btn = UIButton(type: .DetailDisclosure)
pinView.rightCalloutAccessoryView = btn
let tapGesture = UITapGestureRecognizer(target: self,action: #selector(MapView.calloutTapped(_:)))
pinView.addGestureRecognizer(tapGesture)
return pinView
}
func calloutTapped(sender: UITapGestureRecognizer) {
// if sender.state != UIGestureRecognizerState.Began { return }
let annView: MKAnnotationView! = sender.view as? MKAnnotationView
let ann:MKAnnotation! = annView!.annotation
print("handlePinButtonTap: ann.title \(ann!.title!!) and \(ann!.subtitle!!)")
let touchLocation = sender.locationInView(mapView)
let locationCoordinate = mapView.convertPoint(touchLocation, toCoordinateFromView: mapView)
print("Tapped at lat: \(locationCoordinate.latitude) long: \(locationCoordinate.longitude) " )
let storyboard : UIStoryboard = UIStoryboard(name: "ShoppingCart", bundle: nil)
let vc : ShoppingCartController = storyboard.instantiateViewControllerWithIdentifier("ShoppingCart") as! ShoppingCartController
let navigationController = UINavigationController(rootViewController: vc)
self.presentViewController(navigationController, animated: true, completion: nil)
}
However upon using this code,on tap of the pin on the map, user is navigated to the ShoppingCart storyboard. I want to present that ViewController on the tap of info button along with the title,subtitle, latitude and longitude of the event that has been tapped.
Here is the working solution
func mapView(mapView: MKMapView, viewForAnnotation annotation: MKAnnotation) -> MKAnnotationView? {
if annotation is MKUserLocation {
//return nil so map view draws "blue dot" for standard user location
return nil
}
let reuseId = "pin"
let pinView = MKPinAnnotationView(annotation: annotation, reuseIdentifier: reuseId)
pinView.canShowCallout = true
pinView.animatesDrop = true
pinView.pinTintColor = UIColor.darkGrayColor()
pinView.draggable = true
let btn = UIButton(type: .DetailDisclosure)
pinView.rightCalloutAccessoryView = btn
let tapGesture = UITapGestureRecognizer(target: self,action: #selector(MapView.calloutTapped(_:)))
pinView.addGestureRecognizer(tapGesture)
return pinView
}
func calloutTapped(sender: UITapGestureRecognizer) {
// if sender.state != UIGestureRecognizerState.Began { return }
let annView: MKAnnotationView! = sender.view as? MKAnnotationView
let ann:MKAnnotation! = annView!.annotation
print("handlePinButtonTap: ann.title \(ann!.title!!) and \(ann!.subtitle!!)")
let touchLocation = sender.locationInView(mapView)
let locationCoordinate = mapView.convertPoint(touchLocation, toCoordinateFromView: mapView)
print("Tapped at lat: \(locationCoordinate.latitude) long: \(locationCoordinate.longitude) " )
}
i'm trying to create a MKAnnonationView, but when i tap the annonations they appear with a transparent background. When i press the segmentControllr which shows tableView instead of MKMapView then its white until i tap the annonation again then it become transperent again.
viewdidLoad
pointMapView = MKMapView(frame: CGRectMake(0, 0, self.tableView.frame.width, self.tableView.frame.height))
pointMapView?.showsUserLocation = true
add MKAnnonations
func setGeoPoint(geoPoint:PFGeoPoint, titleString:NSString, imageFile:PFFile, theId:NSString, descString:NSString, dateString:NSString) {
var coordinate = CLLocationCoordinate2DMake(geoPoint.latitude, geoPoint.longitude) as CLLocationCoordinate2D
var pinView:AnnonationClass = AnnonationClass()
imageFile.getDataInBackgroundWithBlock {
(imageData: NSData!, error: NSError!) -> Void in
if error == nil {
let theImage = UIImage(data:imageData)
pinView.itemImage = theImage
pinView.setCoordinate(coordinate)
pinView.title = titleString
pinView.subtitle = dateString
self.pointMapView!.addAnnotation(pinView)
}
}
viewForAnnonation
func mapView(mapView: MKMapView!, viewForAnnotation annotation: AnnonationClass!) -> MKAnnotationView! {
let reuseId = "pin"
var pinView = mapView.dequeueReusableAnnotationViewWithIdentifier(reuseId) as? MKPinAnnotationView
if pinView == nil {
pinView = MKPinAnnotationView(annotation: annotation, reuseIdentifier: reuseId)
pinView!.canShowCallout = true
pinView!.animatesDrop = true
pinView!.pinColor = .Purple
var rightButton: AnyObject! = UIButton.buttonWithType(UIButtonType.DetailDisclosure)
//MapPointAnnotation *point = (MapPointAnnotation*)pinView.annotation;
//rightButton.venue = point.venue;
rightButton.titleForState(UIControlState.Normal)
rightButton.addTarget(self, action: "rightButtonTapped:", forControlEvents: UIControlEvents.TouchUpInside)
pinView!.rightCalloutAccessoryView = rightButton as UIView
var leftImage: UIImageView = UIImageView(frame: CGRectMake(0, 0, 44, 44))
leftImage.image = annotation.itemImage
pinView!.leftCalloutAccessoryView = leftImage
}
else {
pinView!.annotation = annotation
}
return pinView
}