-
Notifications
You must be signed in to change notification settings - Fork 1.3k
Move callout customization away from MGLMapViewDelegate towards custom views #4392
Comments
Some addenda:
Providing a reuse identifier inspectable for ordinary UIViews would be tricky. We can’t add a stored property to UIView via a category. However, we could have the category-defined getter and setter work with an associated object on the view. If the developer wants the standard bubble look but forgets to set MGLCompactCalloutView as the custom class, should the callout really be transparent and borderless?
There are two likely models here:
What happens when we add support for showing callouts on shape and line overlays? It may make sense to have prototype callout views be independent of any prototype annotation view. Where should the callout’s anchor position or anchor edge be exposed? As a property of the callout view or the annotation view? |
Working in the I’m currently exploring how to deprecate the old delegate-based callouts without removing them outright. |
Noting also that the callout view’s title and subtitle labels should update (and the callout view itself should resize) when the represented annotation object’s It also doesn’t look straightforward to add dynamic content updates to SMCalloutView, because it doesn’t expose its labels publicly and lays itself out manually. SMCalloutView is written to support iOS 5.0 and above, while Auto Layout was introduced in iOS 6.0. We only support iOS 7.0 and above, so any replacement for SMCalloutView should use constraints to avoid a similar mess. |
I'd love to discuss this more, especially if we are anticipating having MapKit parity with some sort of similar callout view as part of this more abstract solution. SMCalloutView is mature, we have a good relationship with the developer (👋 @nfarina), and it'd take a lot of work to replicate. |
SMCalloutView is a great library, but the current situation is unfortunate: we only make use of a tiny fraction of SMCalloutView, so there’s plenty of dead code around iOS 6 support and various customization options. Due to the way we’ve integrated SMCalloutView, developers can’t even bring in their own copy of SMCalloutView that they can use more fully (#1757). Meanwhile, many developers are eschewing the built-in callout API for custom callout views, either because they want more flexibility with the bubble callout design (#3950) or because they want to imitate the bottom panel affordance found in Google Maps and (now in iOS 10) Apple Maps. We need the ability to dynamically update the callout’s title and subtitle through KVO, for parity with the Android SDK (#5353) and macOS SDK, but that’s currently impossible because of how SMCalloutView is laid out. Instead of hacking around that limitation, I think we should move to an implementation that uses Auto Layout. The existing custom callout API requires a lot of code, because it’s trying to fit within the paradigm of SMCalloutView. I think we can greatly simplify the API in a way that allows developers to bring in SMCalloutView if that’s what they want but get a reasonable default that matches MapKit if they don’t bring in SMCalloutView. The implementation in #4948 already replicates much of the SMCalloutView functionality we’ve been using, but with far less code. I think we can also consider it fairly mature for what it does, given that it’s based on the custom callout example. |
My plan so far in #4948 is to minimally reproduce SMCalloutView’s features, but do so in a way that’s as efficient as possible for this project. Primarily, I want to reduce the number of delegate methods and more closely align to MapKit’s property-based callout↔annotation connections. Our current custom callout API is entirely too complicated and this effort is about improving that. SMCalloutView itself is great and the changes we’re discussing here should actually make it easier for developers to more fully use it. For those developers who don’t need SMCalloutView, unbundling it from our SDK will make their projects marginally lighter weight. (I do think, though, that iOS 10’s Maps.app move away from bubble-style callouts is the beginning of the end for SMCalloutView — the bubble is still a useful paradigm, but separate floating views will probably at least enjoy some faddish popularity.) |
I think this is an excellent idea. |
This issue has been automatically detected as stale because it has not had recent activity and will be archived. Thank you for your contributions. |
This issue has been automatically detected as stale because it has not had recent activity and will be archived. Thank you for your contributions. |
The current annotation callout API is implemented as a series of delegate methods in MGLMapViewDelegate that configure SMCalloutView. SMCalloutView provides a lot of customization options, but we’re only exposing a few basic ones.
SMCalloutView is great for callout views that need a certain layout, but many developers need more flexibility and don’t mind setting up the layout and drawing themselves. The current API for custom callout views can be very confusing for a developer who wants something more freeform – “Why do I have to implement accessory views?” And you’re basically on your own in terms of styling as soon as you go the custom callout route.
Let’s drop the dependency on SMCalloutView and deprecate the current callout API – both the delegate methods and the protocol – in favor of a more deliberate, coherent callout API. The proposal below is aimed at aligning the iOS SDK’s annotations API with that of the OS X SDK, which manages callouts with NSPopoverControllers and allows you to specify your own.
You should be able to drag a custom view into a storyboard, turn it into an MGLMapView, and design the custom callout views directly inside the storyboard. You’d drag a custom view into the scene dock above the view controller and optionally set the custom class to MGLCompactCalloutView, which provides the standard bubble look and feel (surfaced in the storyboard via a designable). You’d specify a reuse identifier for the callout view, then drag a connection from the callout view to the map view’s
prototypeCalloutViews
outlet collection. The callout view can be customized extensively without any work on our part:rightAccessoryView
outlet so that-[MGLMapViewDelegate mapView:annotation:calloutAccessoryControlTapped:]
would get called.When configuring an MGLAnnotationView (#1784) or MGLAnnotationImage programmatically, you’d choose which callout view to use with the annotation, identifying one of the prototype callout views either by indexing into the outlet collection or by specifying a reuse identifier. This part differs from how MapKit’s MKAnnotationView API works, but I think it’s worth diverging to offer better storyboard support and more flexibility. Notably, setting up the annotation model object is the only part of the workflow that absolutely requires code.
If possible, we’d provide a compatibility shim for the old API that could get removed in a future major version. But if you want to work with SMCalloutView specifically, then you’d be able to pull in SMCalloutView and customize it to your liking without depending on SDK changes.
The entire API would still be usable programmatically for more advanced use cases. But the goal is that the “First steps” guide, which is intended for beginners, would have only a few lines of code and the rest would be in Interface Builder. Some future directions, somewhat out of scope for this issue, would further reduce the need for code:
prototypeAnnotationViews
outlet collection, and optionally connecting a callout view to the annotation view’scalloutView
outlet.A lot of the code in this custom callout view example can be reused to implement a snazzy-looking default callout view.
/cc @friedbunny @boundsj @tmcw
The text was updated successfully, but these errors were encountered: