I have a custom MKAnnotationView subclass. It is showing the view exactly as I want it to. In that view, I have a button. I want to capture events on the button to perform an action. This works just fine.
However, I do NOT want the callout to be dismissed or disappear. Basically, touching the button in the callout will start playing a sound, but I want to leave the annotation up so the user can press stop if they want to, without having to touch the map pin again to bring the annotation back up. In another instance, I want the button touch to animate more details in the callout, so I definitely don't want to dismiss the callout at that point.
How can I keep the callout from disappearing whenever the user selects the callout or a button inside the callout?
This may not be the best solution, but it definitely works. First off, I tried a number of things, like observing for context and such, but I never got past crashing, and it seemed cumbersome. So, this is what I did:
I first specified what the controlling factor was for keeping an alert viewable. In my case, I created a custom annotation view, and whenever the user clicks a button on that custom view, I want it to stay visible, and maybe even change the content. So, I set a delegate on that custom view so that my map can know when something changes. In my map view controller, I catch that message and set a class member variable to true to signify that I want the annotation view to stay.
NOTE: This will happen before the selection messages occur.
Now, in my didDeselectAnnotation method, I check the boolean value. If I want to keep it visible, I opt to NOT remove my annotation, I reset the boolean value, and I re-select the annotation manually, setting animation to NO. This lets the annotation view "stay" visible--maybe a cheat, but the user can't see the difference. Whenever that boolean value says that deselection is ok, I simply remove the annotation and all is well.
So, the workflow is this:
Touch pin
CustomAnnotationView is displayed
User clicks a button on CustomAnnotationView, which notifies the delegate (mapView) that the
action occurred
Set the class boolean value to know that you want to keep the annotation around
mapView then calls didDeselectAnnotation method
In didDeselectAnnotation method, use conditional to decide if you should remove the annotation, or keep it around by not removing the annotation and manually re-selecting it without animation.
I hope this helps others. It took me a while to figure this out, so I hope it saves you time.
If you find a better solution, by all means, please post it here!
you can suppress callout closing by using hittest, check this following post.
Detect tap on title of callout
Related
I have my screen split; 50% for the map and 50% for a list of elements. As the list of elements is scroll, the annotation will pop around the map based off whichever element is in the top of the list. This part is working fine.
However, when the user taps on the map, I don't want the annotation to disappear. I really want the user's tap to interactive with the MapView instead of the AnnotationView.
Is this possible? If so, can someone point me in the right direction? Thanks.
You have a couple of options:
You can intercept the built-in tap gesture recognizer or add a custom tap gesture recognizer. When the user taps the map, check if an annotation is selected. If one is selected, call mapView:selectAnnotation: to keep it selected.
You can call mapView:selectAnnotation: in the relevant mapView:deselectAnnotation: or mapView:deselectAnnotationView: delegate method.
How can I have my MKMapView follow my user around until they scroll, and then have a button to follow the user around again?
Here is the flow I would like it to have.
View Loads:
Zoom in and center on the users current location, then follow the user around.
User scrolls:
Do nothing until a button is pressed
Button pressed:
Same code as 'View Loads'
Your location manager is continuously providing you with new location information via the delegate method locationManager:didUpdateToLocation:fromLocation:. Change the map's region whenever you get an update. Before doing so, check a flag ("shouldFollowCurrentLocation" or similar) that is set by default. You will unset the flag when your map view delegate gets mapView:regionWillChangeAnimated: (you will of course have to keep track of the occasions when you cause the region to change programmatically) and reset it in the button's action method.
I have a somewhat complex iOS view hierarchy. One piece of text is an editable UITextField. When the user touches it, it becomes first responder, and is editable.
Here's the rub, though: Best practice should be that a touch anywhere outside the edit control causes it to resign first responder and end editing. What's the best way of accomplishing this?
Techniques I've tried:
Use the exclusiveTouch property, which stops the user from interacting with other controls, but doesn't cause editing to end. Also disallows user from interacting with my toolbar "Done" button.
Put a see-through UIView under the text field control and on top of everything else (except the toolbar), and use touches there to end editing. This works, but I end up reparenting the text field onto this other random view which sits above my whole hierarchy, which means I have to take care of the text field's layout in multiple places, since it no longer lives in the place where it lived originally, and I have to delegate all its behavior back and forth from its "shield" view to its native home container, which has all the related logic.
Is there an elegant solution to this problem that I'm missing? I figure it must be a common design issue.
Thanks.
Tile 4 "see-thru" views around the textview to capture/ignore touches. Doesn't require modifying or "lifting" the textview, and can be added to the parent view in a fairly modular way.
You can't mask a region without knowing what that mask will cover and what the mask will not cover. So any solution will require enough reach to gather both of those bounds. Either pass the text rect up, or the view rect/region to be disabled down, or both to something in-between. The controller for the stuff to be covered seems as good a place as any to consolidate both rects or regions, if not the controller for the text view.
The nub of the issue is what constitutes "best practice". The fact that the keyboard remains unless the user dismisses it is deliberate. For example, many apps need the user to be able to tap a button while still working in a text field.
The keyboard has a Return button. "Best practice" is to respond to the user tapping that button by resigning first responder. Otherwise, you should leave the keyboard there, since that's what the user expects.
However, if you insist on doing it your way, there's a simple solution: put a UITapGestureRecognizer on the background view. Its handler will be triggered if the user taps on the background or on any button or similar in the interface. So, presuming you have kept a record of what the first responder is, you can send resignFirstResponder to the first responder in the tap gesture recognizer's handler.
If you change your base view to a UIControl you can add an IBAction to that layer that resigns your text field as first responder.
Also, if you have multiple touch events, make sure they each becomeFirstResponder when touched.
I'd love to have some more details to qualify my explanations xD
I need to handle a touch event on my custom uiviewcotroller. I have a sub controller within the view that already handle touch event (it's a plot that handle zooming and scrolling).
I want to make a tabbar disappear when I tap the screen once. Actually it only works (even tought the tabbar doesn fade away but simply is no visible) in the areas in which the subcontrol is not present but I need it to work everywhere still handling the subcontrol events.
Make sure you're calling the superclass's event handler method in your event handler method to continue propagation of the event up the responder chain.
Also make sure the subcontrol's exclusiveTouch property is set to NO.
You might want to have a look at the event handling documentation.
Try to set userInteractionEnabled = NO in subcontrol view.
UPD: Try to add transparent button to subcontrol.
When you touch a UIButton it hides for a fraction of second and then it executes its action. This fast "blink" is the feedback the user needs to know that the button has been clicked.
In the project I am doing, I need to select the button programmatically, as if the user had clicked it. In other words, the same behavior has the button had been clicked by the user... a fast blink and execution of its action.
Is this possible to do?
thanks for any help.
The change in the appearance of the button is effected by setting the button's highlighted property. The property is automatically set to YES when the user touches down on the button, and back to NO when she releases.
The highlighted property is writable, so you can set it YES yourself to simulate a touch down. You'll probably want to use +[NSTimer scheduledTimerWithTimeInterval:invocation:repeats:] to set it back to NO after a short interval.
It is pretty simple, and probably there is a better solution.
First, use images to your button, and when you have to fire the button, you just change the button's image in the normal state to the pressed image, and after that, replace it back to the original. You can simply do it with a timer.