Como informáticos, siempre debemos estar preparados para el cambio, y Xamarin.Forms no es la excepción.
Luego de los últimos updates a Xamarin.Forms, la implementación de MapRenderer
cambió un poco. Este cambio ha resultado un tanto molesto para algunos, ya que, si teníamos un Custom Renderer de mapas en Xamarin.Forms y actualizábamos a la última versión (ahora 2.3.4) algunas cosas podían dejar de funcionar mágicamente en Android al implementar IOnMapReadyCallback
en nuestro renderer.
Este fue mi caso hace un par de días cuando andaba preparando un prototipo ligero de una app. La explicación a este problema la encontré en nuestro viejo amigo StackOverFlow (ver la respuesta completa).
El problema
Si nos dirigimos al código fuente de MapRenderer
, podremos ver que dicha clase ahora ya implementa IOnMapReadyCallback
. Es por esta razón que ya no se hace necesario reimplementar dicha interfaz en nuestro renderer; de lo contrario, podríamos causar conflictos como los que me tocaron a mí.
Como parte de los cambios, ahora también podemos obtener la instancia de nuestro GoogleMap
a través de la propiedad NativeMap
, por lo cual tampoco será necesario guardarla en una variable dentro de nuestro renderer.
Solución
Para este caso, he encontrado 2 salidas: refactorizar el código del renderer para adaptarlo a la nueva implementación, o simplemente realizar un pequeño hack que describiré a continuación.
Opción 1: Hack simple
La solución más rápida que hizo funcionar mi código sin tocar absolutamente nada fue agregar el siguiente método en mi renderer:
Y llamarlo en la primera línea de nuestro método OnMapReady
. De esta forma:
Si tienes mucho apuro, esta puede ser una salida fácil al problema, aunque personalmente recomendaría ir por la opción 2.
Opción 2: Adaptar el código de nuestro renderer
Las soluciones podrán variar dependiendo cada caso, pero a continuación describiré puntos a tomar en cuenta para refactorizar el código exitosamente.
- Dejaremos de hacer que nuestra clase renderer implemente la interfaz
IOnMapReadyCallback
. - Ya no se hará necesaria la sentencia
Control?.GetMapAsync(this)
. - El método
OnMapReady
que se ejecutaba por la llamada deIOnMapReadyCallBack
quedará sin efecto, por lo tanto... - El código que colocábamos en dicho método habrá que ponerlo en otro lado. En mi caso, ahora lo llamo desde
OnElementPropertyChanged
. - Podemos quitar nuestra variable local
GoogleMap map
, y reemplazarla por la propiedad heredadaNativeMap
.
Precaución: Hay que tener cuidado al usar
NativeMap
, ya que al principio puede sernull
.
Mi clase renderer con esta solución quedó así:
Este ejemplo es para detectar clics en el mapa, pero, repito, puede variar según el caso.
Ejemplo vivo
Subí a Github el proyecto completo de esta solución. Al principio apliqué la solución 1 (puedes revisar los commits), pero ahora logré refactorizarlo y hacer que todo funcione normalmente con la solución 2.
Por cierto, pueden contribuir al proyecto si desean :D.
Eso es todo
Queda a criterio de cada uno la solución que se le dé a este problema, pero espero que les sirva este granito de arena de mi parte. Si tienen alguna otra solución interesante, ¡por favor, compártanmela!
¡Saludos!