I'm trying to call the mapView(mapView: MKMapView, didDeselectAnnotationView view: MKAnnotationView) function programmatically using this code:
dispatch_async(dispatch_get_main_queue()) {
for item in self.largeMapView.selectedAnnotations {
self.largeMapView.deselectAnnotation(item, animated: false)
}
}
but this doesn't do anything. If I press on the map, it is called, but I want it to be called without the need to press.
Not exactly sure why, but this code in full seems to solve the problem :
dispatch_async(dispatch_get_main_queue()) {
for item in self.largeMapView.selectedAnnotations {
self.largeMapView.deselectAnnotation(item, animated: false)
}
myView.pinTintColor = UIColor.greenColor()
calloutView.hidden = true
}
Manually changing the pinTintColor to the "deselected" one, and manually hiding the calloutView solved the problem.
Related
I have the following function in an extension of MKMapView that let me reload a specific annotation and keep it selected if needed and the issue is every time the self.removeAnnotation is called, the whole map is reloaded (or at least all the pins "jumped" as if a reload occurred)
Is there a way to achieve a reload of a single annotation without having the visual of a whole map reloading ?
func reloadAnnotation(_ annotation: MKAnnotation, keepSelection: Bool = true) {
let isSelected = selectedAnnotations.contains(where: annotation.isEqual(_:))
//already tried **UIView.performWithoutAnimation** which decrease the jumping effect
// UIView.performWithoutAnimation {
self.removeAnnotation(annotation)
self.addAnnotation(annotation)
// }
guard isSelected && keepSelection else {
return
}
self.selectedAnnotations.append(annotation)
}
In my experience the unwanted "whole map reloading" visual effect comes from the recalculation of clusters which is triggered by self.removeAnnotation(annotation) and self.addAnnotation(annotation).
So you have to avoid this methods if you just want to update some visual information.
My assumption is that your callout and/or title changed dynamically while selected and you reload because you want to render the changed callout information.
func reloadAnnotation(_ annotation: MKAnnotation, keepSelection: Bool = true) {
let annotationView = mapView.view(for: annotation) as? MyCoolAnnotationView
if let annotationView {
// do stuff like
annotationView.setNeedsLayout()
}
}
annotationView will be nil if the annotation is not in the visible region or part of a cluster. In that case you don't want to reload anyways.
Instead of annotationView.setNeedsLayout() you might call your own method that does whatever you want.
I did notice an issue on IOS 11 when using MKMapView.
When I want to click on the button action from the pin dialog and there is another pin behind the button action, it does not get the gesture.
It should be something about zPosition, but I don't know if there is any way to modify just the zPosition of the dialog (MKAnnotationView.annotation) and put it in front of the pins (MKAnnotationView.image) position.
For IOS version < 11 it does work perfectly.
Is someone having the same trouble?
Thank you!
Finally I've found a solution!
Here it comes, if someone needs it:
func mapView(_ mapView: MKMapView, didSelect view: MKAnnotationView) {
if #available(iOS 11, *) {
for annotationView in mapView.annotations {
if mapView.view(for: annotationView) == view {
mapView.view(for: annotationView)?.isUserInteractionEnabled = true
mapView.view(for: annotationView)?.becomeFirstResponder()
}
else{
mapView.view(for: annotationView)?.isUserInteractionEnabled = false
}
}
}
}
All in order now!
I have an app that implements a MKMapView where I want to track and follow the user location, and I kind of managed to make that work, the only problem is that even when tracking is set to .none the map returns to the user location sometimes.
First of all, here's a GIF of it happening (uploaded to imgur because the file was too large for SO): http://i.imgur.com/2FoQCoi.gifv
The icon on the lower right is supposed to indicate if the map is tracking the user location, on the GIF it's grey because it's supposed to be off.
The code for the button is:
var isFollowing: Bool {
get {
return chkFollow.checked
}
set {
chkFollow.checked = newValue
if newValue {
mapView.setUserTrackingMode(.follow, animated: true)
print("did set to follow")
}
else {
mapView.setUserTrackingMode(.none, animated: true)
print("did set to none")
}
}
}
I also set up the mapView(_, regionWillChangeAnimated) method to be the following:
func mapView(_ mapView: MKMapView, regionWillChangeAnimated animated: Bool) {
isFollowing = false
}
and
func mapView(_ mapView: MKMapView, regionWillChangeAnimated animated: Bool) {
mapView.userTrackingMode = .none
}
Neither worked correctly.
When I click the button the print statement works and prints "did set to none" on the console correctly so I know that the method is being called, just for some reason it still follows the user.
If there's any other info that helps, I'll gladly send it. chkFollow is a custom checkbox control, I don't think it's code is relevant here.
Thanks in advance!
Sorry everybody, I got it when I was recreating it in a sample project.
The problem was, I wanted the app track the user's position on start up, so I set UserTrackingMode to .follow inside mapViewDidFinishRenderingMap. So when the map moved enough to re-render everything that was being called and the map started tracking the user back again.
To solve it I added a bool variable (isFirstLoad) and only set up UserTrackingMode when the user first loaded the app. Thanks for the comments and sorry to take your time with this :)
Currently I have a map that has several Annotations.
For the Annotations I have
func mapView(_ mapView: MKMapView, didSelect view: MKAnnotationView){
// Do your annotation click work
}
Is it possible to do this for tapping the Map only and not the Annotation and how can I do it?
In ViewWillAppear method :
let gestureRecognizer = UITapGestureRecognizer(target: self, action:"triggerTouchAction:")
mapView.addGestureRecognizer(gestureRecognizer)
And Whatever information you want to show just add code in following method :
func triggerTouchAction(gestureReconizer: UITapGestureRecognizer) {
//Add alert to show it works
}
Hope it going to help you to resolve issue.
I want to loop through view and its subviews to highlight them. Firstly, I use selector like this:
func highlightViewAndSubviews(view: UIView, highlighted: Bool) {
if view.respondsToSelector(Selector("setHighlighted:")) {
view.performSelector(Selector("setHighlighted:"), withObject: highlighted)
}
for subview in view.subviews {
highlightViewAndSubviews(subview, highlighted: highlighted)
}
}
But it doesn't work when highlighted is false or view is UILabel. Then I use type cast to achieve this. It works perfectly.
func highlightViewAndSubviews(view: UIView, highlighted: Bool) {
if let imageView = view as? UIImageView {
imageView.highlighted = highlighted
}
if let label = view as? UILabel {
label.highlighted = highlighted
}
for subview in view.subviews {
highlightViewAndSubviews(subview, highlighted: highlighted)
}
}
My question is why. And I prefer selector because it works for label,button,image view and so on. Many thanks in advance.
The problem is that this line doesn't do what you think:
view.performSelector(Selector("setHighlighted:"), withObject: highlighted)
Use key-value coding instead:
view.setValue(highlighted, forKey:"highlighted")