Search code examples
iphoneiossdkmkannotationviewcallouts

Custom MKAnnotationView - How to capture touches and NOT dismiss the callout?


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?


Solution

  • 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:

    1. Touch pin
    2. CustomAnnotationView is displayed
    3. User clicks a button on CustomAnnotationView, which notifies the delegate (mapView) that the action occurred
    4. Set the class boolean value to know that you want to keep the annotation around
    5. mapView then calls didDeselectAnnotation method
    6. 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!