La historia de cómo actualicé Yandex MapKit en iOS o mapas, dinero, 2 mapas

Prólogo



Hola amigos , al principio explicaré de inmediato el propósito del artículo: ahorrar tiempo si necesita actualizar o insertar mapas de Yandex en su cliente móvil iOS, además del deseo de compartir su experiencia.

Una vez incorporamos la aplicación YandexMapkit (aproximadamente en octubre de 2017) en lugar de tarjetas de correo electrónico (nada personal, solo negocios). Después de aproximadamente 3 meses, en un hermoso día de invierno, la versión Androyd de las tarjetas salió de servicio el día 2 debido a las llaves, la tarjeta se convirtió en una calabaza) ¿Cuál es el consejo del manual: "En el Android, las tarjetas estaban rotas, no saben cómo arreglarlo" En ese momento como cliente iOS, esto no afectó. Pobres chicos del androide ... esta vez los chicos no tenían nada que ver. En aquellos días , muchos puntos bajos cayeron : el puesto de Rusia, el Ornitorrinco, ¿pueden recordarlo?



Quiero decir, cuando su aplicación está vinculada a servicios de terceros, sería bueno tener un plan "B" para este caso, por ejemplo, cambiar a la versión anterior de la implementación de tarjetas de Apple, y no reemplazar una por otra ...

Después de otros 3 meses, en algún lugar de marzo, llegó una carta de Yandex que finalmente habían actualizado sdk (ha pasado muy poco tiempo, 4-5 años desde la actualización anterior):
"-Actualización, apague el viejo en un año", en resumen. Antes de eso, simplemente había una versión antigua 1.0



Bueno, por supuesto, después de tal advertencia, no tiramos e inmediatamente comenzamos la transición ... después de 3 meses) en agosto.

Etapa de "comentarios" (Desactivar funcionalidad)


Dices, ja ... lo que se actualiza allí, el pod actualizado, se corrigió un par de lugares y eso es todo. Así que no, muchachos, la nueva API de mapas no es absolutamente compatible con la anterior, y además, como resultó más tarde, ¡incluso hay muchas necesidades vitales que están listas para usar en la versión anterior y otras bibliotecas de tarjetas!

Entonces, mapkit 3.0 (al escribir un artículo versión 3.1 fue lanzado), un enlace a la documentación .

¿Y por qué, además de una advertencia de Yandex? Mientras tanto, en una versión beta de Xcode 10, un proyecto con una ballena vieja estúpidamente no va a funcionar, porque C ++ se usa en algún lugar dentro, lo que está privado en la nueva versión. Es necesario cambiarle el nombre en la sublista, incluso actualizarlo allí, etc., en resumen, no hice esto, porque al final todavía necesito actualizar

1) Actualizamos SDK, en lugar de la versión 1.0 inmediatamente 3.0, por supuesto, la API ha cambiado, pero mucho ...

Entonces, el antiguo Protocolo de anotación YMK simplemente falta




En forma rápida, parece una tira forjada forzada (: eso no es un zumbido, y luego llevas un cartel "!" Para ti mismo ... Ejemplo de implementación de protocolo:



Bueno, volvamos a escribir) el nuestro, solo que en lugar del método coordinar () haremos las propiedades, todo es simple, el método es redundante; title! () se reemplaza por un título sin forma (), por otro lado, puede hacer una propiedad, bueno, mucho, donde tiene que cambiar el proyecto, así que simplemente eliminé el signo de exclamación.

En nuestro proyecto, fue necesario reemplazar en 3 controladores un par de veces, importar CoreLocation en otro, ya que ahora no se importa en ninguno de los encabezados Yandex MapPocket.

Para no cambiar el nombre del familiar YMKMapCoordinate (ballena vieja) a lo largo del proyecto, se hicieron typealias para YMKPoint (nueva ballena)



2) Además, declaremos algunas propiedades que necesitaremos en el futuro para trabajar con el mapa, principalmente getters:



3) Lo primero que hay que crear es YMKMapView (todo está bien, ese objeto todavía está disponible). Anteriormente, lo inicialicé de inmediato, ahora no puedes hacer esto, se bloqueará, ¡porque primero debes poner la llave! La clave actual no funcionará y debe solicitar una nueva. Agregar a AppDelegate, de acuerdo con la documentación. Solo después de configurar la clave, podemos crear YMKMapView y configurarlo de la manera que necesitamos en el método setupMap ()



Lo que sucede aquí, lo analizaremos en detalle más adelante en el curso de la necesidad de configuraciones apropiadas

4) ¿Qué sigue?, Y luego tuvimos la ubicación inicial de CLLocation, pero ahora para usarlo debe agregar el marco CoreLocation manualmente, o ... o reemplazarlo con YMKPoint desde el mapa de Yandex



5) Además, el mapa se centró en esta coordenada por un método muy simple, pero ahora no hay un simple



Pero hay un poco más complicado y un poco más profundo, el objeto de mapa) ... mapView.mapWindow.map! .Move. Aquí aprendemos sobre la existencia de un objeto como YMKCameraPosition.



6) A continuación, comentamos la configuración del mapa, ya que no existen tales api / propiedades. Ahora solo lo omitimos para comenzar al menos mínimamente.

Comentamos sobre agregar anotaciones (prestaré atención a que esta es la funcionalidad estándar), también comentamos sobre mostrar los puntos más cercanos (esto ya es algún tipo de nuestra funcionalidad).

Y todo el YMKMapViewDelegate también es un comentario, que no encontré en el nuevo marco, y un análogo similar también.



Omití la implementación, solo los métodos mismos:

- si mostrar la ubicación del usuario,
- qué vistas usar para los pines,
- reacción al hacer clic en la anotación,
- qué llamadas para anotación,
- La reacción al hacer clic en la llamada, es decir, todo lo que usamos habitualmente. Al final, hubo algún tipo de nuestro método, que también utilizaba una tarjeta API específica.

TODO descifrado con MapVC: esta es la clase principal donde se utilizó el mapkit

7) Un pequeño comentario sobre la llamada personalizada, ya no heredará YMKCalloutView, ya no hay más en la nueva ballena.

Hurra, ahora que el proyecto se ha reunido, pude comenzar todo y ... ver el cuaderno en la caja, porque después de que comienza, debes dar tiempo para "calentar")), pero no lo sabía y pensé que algo no estaba entonces, aunque sugerí que lleva tiempo activar la clave. Resulta que la suposición era correcta. Debe esperar aproximadamente una hora (tal vez algo ha cambiado ahora).

Con otro intento de modificar la antigua API de una manera nueva, se mostró el mapa.

Etapa dos: "búsqueda" (cómo implementar la funcionalidad anterior de una manera nueva)


Comencemos a restaurar la funcionalidad perdida. Por lo tanto, debe mostrar el bloqueo de usuario, pero a la antigua usanza simplemente no se puede cambiar la propiedad y configurar el delegado.

Ahora esto se hace a través de la capa, consulte el método 3 de setupMap ().



Echaremos un vistazo al ejemplo en la demostración ( descarga desde Yandex github ), ya que está allí. Por cierto, debes prestar atención a setAnchorWith. Más adelante diré por qué, está asociado con el zoom. Ok ubicación funciona.

2) Lo que sigue, por supuesto, anotaciones. No puede agregar a la antigua usanza, volvemos a ver la demostración. Hay una clase allí: MapObjectsViewController. En la nueva versión, para agregar pines al mapa, el delegado no es necesario, para esto necesita acceder a la propiedad mapObjects, llamar al método addPlacemark en el objeto y pasar la coordenada allí (todavía hay otras sobrecargas) Ejemplo:



Repetimos la colección de anotaciones (por ejemplo, después de recibir del servidor) y agregamos una al mapa. El método, por cierto, devuelve "placeMark" (etiqueta de lugar), que se puede utilizar para realizar configuraciones adicionales, por ejemplo, cambiar el orden de visualización a través de la propiedad zIndex.

Aquí, sin embargo, perdí el punto de que antes de eso, subí a buscar un delegado y no lo encontré de manera segura y ni un solo delegado (de hecho, simplemente comenzaron a llamarse de manera diferente, ahora son oyentes). Sé por experiencia previa con la ballena Apple y la vieja ballena Yandex que las anotaciones se reutilizan, al igual que con las celdas, pero solo hay addPlacemark en la demostración. A la pregunta sobre el plomo de las tarjetas Yandex (un pequeño conocido personal ayudó aquí) "- ¿Cómo optimizar el uso de memoria, reutilizar objetos?" Respuesta: "Por qué, entonces funciona bien" ... bueno, más o menos sí, funciona.

Nota: 1) Es importante tener en cuenta que Yandex.Maps usa un mapkit y no lo desarrolla. Esto lo hace el equipo de mapkit (el apodo de Nikolai en el centro: likhogrud @).

2) Explicación de por qué los objetos no se reutilizan:

En la antigua ballena, annotationViews eran vistas, fueron creadas por el usuario y, por supuesto, las vistas deben reutilizarse, porque crearlas no es barato. En la nueva ballena, el mapkit crea marcas de posición directamente en GL abierto. Y tal vez se reutilizan allí, pero esto es inexacto. En cualquier caso, esto es mucho más eficiente que crear una vista.

3) Desde el nuevo, por cierto, existe la posibilidad de modificar el icono de anotación para el usuario. Implementado de la siguiente manera: debe agregar un oyente (análogo del delegado), implementar el protocolo apropiado: 1 de 3 métodos, 2 simplemente dejar en blanco.

Al mismo tiempo, vuelva a cargar la marca de posición con nuestros iconos.



Además, llamo su atención sobre la propiedad del ancla. Después de presionar el botón de ubicación del usuario en el mapa, la cámara mueve el foco al centro de la ubicación. Pero el problema es que presionar la acción nuevamente no produce. Que? Comentamos sobre el método de anclaje y todo funciona.

4) Ahora debe mostrar el texto destacado, respectivamente, para calcular el clic. Hay varios métodos en las interfaces, el correcto es YMKMapObjectTapListener. Hay 1 método interesante importante con el que tuve que atormentarme más tarde, devuelve verdadero para no integrarse más si se encuentra un suscriptor. Le llamo la atención, primero debe suscribirse, se suscribirán los mapObjects (línea 149).





Entonces los clics se cumplen. ¡Hurra ! Aún así, sin embargo, hubo intentos de mostrar los pines solo en la zona visible, esto es superfluo, mostrar todo de una vez, así que vamos a dejarlo (solo porque no se ralentiza)

5) Entonces quería hacer que los botones se acerquen / alejen para mayor comodidad. Copie y pegue un poco por analogía con el botón de ubicación, y ya está.

Además, dado que conocemos la cámara, utilice el método de movimiento y, en consecuencia, el zoom actual + - 1 o 0.5, según lo necesite. Todo está bien aquí.



6) Pasamos a la función principal: llamada (este es un rectángulo con información adicional, con un triángulo en la parte inferior). Resulta que no hay API ("intoxicante en el verano" - Yandex reconoció mi discurso cuando leí las notas de un folleto para no escribir manualmente este artículo).



Como estan chicos 100 500 aplicaciones usan una llamada.

Escribimos bien en "soporte técnico" (Kolya) cómo hacer esto manualmente, descubrí. Cuales son tus opciones?

Convierta la vista en una imagen, ya que no puede agregar directamente una vista (agregó un archivo en 3.1), cambie el icono ...



Estas muletas se obtienen en un plano, parecía lugar.
De hecho, no muletas, por supuesto, sino simplemente la ausencia. Considero la funcionalidad básica.

7) Bien, primero agreguemos una llamada de prueba, como tal usamos un cuadrado rojo. Entonces, al hacer clic en nuestro pin, se llama al método delegado / oyente, donde se transfieren el punto de clic y el objeto. Sin esperar un truco, tomamos "punto" como el punto donde desea agregar la llamada. (Atención, ¿todo está hecho correctamente: "Hicieron clic, tomaron el punto, lo ataron?" Alrededor del 80% respondió correctamente, 20% - no)



Y llame al método auxiliar showCallout en el cuerpo del método:



línea 544
En el interior, cree una vista de prueba del color rojo cuarenta por cuarenta, conviértalo en una imagen, declare una constante x con un valor de 0.5, se usará para la posición del triángulo de llamada en el medio del punto. Rechazó la idea de cambiar su posición, luego prefirió mover la cámara para que la llamada seleccionada se muestre en el centro de la pantalla del teléfono

A continuación, declaramos el área de "inserción" de tappableArea, existe tal propiedad en el estilo de icono para el pin. Bueno, puedes limitar la zona de clic, y lo haremos. La zona varía de 0.0 a 1.1. necesitamos la parte inferior, donde supuestamente hay un botón que se transformó en una imagen antes (recuerde). Bien, esto significa la zona (0,0.5 - 1.1) ya que el botón está debajo.
La restricción de zona funciona, pero hay un matiz que niega todo. Si hay otro pin debajo del área no presionada, entonces presionar funcionará en él. El significado de esta área? ¿Harían una bandera o algo para que el clic no pase? Esta bien ...

Línea 550
creemos un estilo para el icono, puede especificar inmediatamente la posición del ancla en el primer parámetro, por ejemplo, lo hice a continuación en la línea 557. La posición y es 1.05 para elevar el triángulo sobre el pasador nuevamente verticalmente

Línea 559
cree nuestra llamada personalizada de cierto tamaño,
configuramos los campos que necesitamos utilizando la información de la anotación seleccionada Anotación seleccionada, en particular el título y el subtítulo, la inscripción en el botón para esta llamada. Entonces tú mismo puedes hacer lo que quieras. La anotación seleccionada se define anteriormente en el delegado. Pero por ahora, agregue el cuadrado rojo creado anteriormente
A continuación, agregue un pin a la colección mapObjects, el método nos devolverá la marca de posición agregada, guárdela en una variable,
Al hacer clic en la llamada en sí, se abre un controlador detallado, por lo que el matiz es que si debajo de la ventana emergente también ingresó otro pin, el delegado volverá a funcionar, por lo que aquí debe cambiar el orden en la jerarquía a través de zIndex. Establezca la visibilidad y mueva nuestra llamada al centro en la línea 564

Matices : la marca de posición variable es un puntero a la llamada.
Al principio no lo tenemos, después de hacer clic en el pin, parece que, después de hacer clic en el siguiente pin, necesitamos eliminar nuestro primer texto destacado y agregar uno nuevo. Por lo tanto, si la marca de posición variable! = Nil, debe eliminar la llamada anterior de la colección mapObjects)



Además, en el caso de las tapas en la tarjeta, debe ocultar la llamada, por lo que en el método de delegado asignamos una marca de posición, el observador funciona, la llamada se elimina, y borramos la anotación seleccionada

Para esto, nos registramos en YMKMapInputListener anteriormente



A su vez, el método para convertir vistas es el siguiente. (En la versión 3.1, se agregó la capacidad de agregar vistas al mapa)
No describo cómo hacer la vista), pero si habrá muchos problemas (es posible con un triángulo) con esto, entonces escriba, agregaré esta etapa



La magia 20 agregada a la altura es necesaria para un lugar debajo del triángulo a continuación, que deberá dibujar

También queremos que la ventana emergente aparezca (se adjunte) al pin en un lugar específico (izquierda, derecha, en el medio), para esto hay una propiedad de anclaje. Definido de la siguiente manera:
Dividimos el área visible del mapa en 3 zonas verticales y determinamos en cuál estamos, dependiendo de esto, cambiamos la posición del enlace. En el ejemplo de código, verificamos si estamos en el lado izquierdo, por analogía lo hacemos para el medio, si no para el izquierdo y no para el medio, respectivamente, el punto a la derecha es



Una función auxiliar para verificar si un punto cae en una región:



Inicio. Funciona Pero hay un matiz, parece que estamos tratando de hacer zoom, uno, dos, tres, y la llamada se aleja del pin. Que? Como?



7) Comenzamos a depurar, las coordenadas son las mismas



Luego hubo intentos de comprender qué está sucediendo y cómo funciona, otro regreso a la demostración, una búsqueda aún más atenta de las diferencias ...



Me doy cuenta de que las coordenadas se transmiten directamente, ¡y no la que está tocando! Pero debatí, está claro que las coordenadas son las mismas, es decir, el círculo y el cuadrado tienen la misma coordenada.
Es por eso que en el método no accedí inmediatamente al objeto, sino al punto pasado, que es incorrecto.



Pero, ¿necesita lanzar un objeto, tomar una propiedad (en todas partes todo se llama de manera diferente, luego coordinar, luego señalar, aquí ahora la geometría) ¿es esto tan creativo o qué? 493 líneas



Dado que necesitamos procesar dos opciones de presión: la primera para anclar, la segunda para llamar y no procesar clics si volvemos a hacer clic en el mismo pin, lo primero que hacemos es encontrar el pin en el que hicimos clic en la colección de pin, comparando coordina la línea 495, de lo contrario, devuelve verdadero, lo que indica que procesamos el clic y no es necesario ir más allá en la jerarquía

Segundo : lo determinamos haciendo clic en el pin o en la llamada, también compararemos las coordenadas de las etiquetas de la línea 499. Prueba de igualdad:



Además, si se trata de una llamada y queremos responder a un clic en el botón (o simular, ya que ahora es una imagen), y no a toda el área, entonces tenemos que hacer algunos cálculos con bolígrafos :)

  1. Convierta la coordenada mundial a la línea de la pantalla 501
    Nos consideramos: convertiremos las coordenadas del mapa a la pantalla, sabemos dónde estamos ubicados, luego agregando el ancho y la altura de la vista, obtenemos los puntos de las esquinas, pero por alguna razón no coinciden y los multipliqué manualmente por tres, en mi caso para el décimo iPhone). Como resultó más tarde, olvidé y no tomé en cuenta la cantidad de píxeles por punto. Que podemos tener 1x, (un punto 1 píxel), 2x, 3x un punto es tres píxeles.
  2. Calculemos la altura del botón: la altura de la llamada + la altura del triángulo multiplicado por la escala, información sobre la escala (línea 498). Luego, dividimos todo esto en dos, ya que la altura del botón es la mitad de la altura de la llamada
  3. Luego calculamos las coordenadas de los ángulos, en función del hecho de que el ancla (x: 0.5, y: 1), dada la escala y el área del triángulo)
  4. Luego convierta estas coordenadas de pantalla a mundo
  5. Crear un área visible basada en ellos, es una zona de botones
  6. Y verificamos si presionamos la zona del botón o no. Si presiona, verifique el tipo de anotación, dependiendo del tipo que llamemos a nuestro método: vaya a la pantalla detallada o seleccione esta tienda para la entrega en casos con StorePoint

De lo contrario, es un clic en el pin y necesitamos agregar un texto destacado, lo que en realidad hicimos anteriormente.

Eso es todo, en este conocimiento inicial de la nueva ballena ha terminado.

Qué más quiero decir, en la implementación actual de los mapas de mapkit, contiene una gran cantidad de funcionalidades que no se utilizan, esto también afecta el tamaño del binario resultante. ¿Estás listo para tales sacrificios? En el futuro, los chicos deberían ser demolidos en módulos después de todo . También escuché de colegas en el androide del taller que hay problemas de compatibilidad con Kotlin.

P.S. Si bien decidí y comencé a escribir un artículo, salió la actualización 3.1, donde a partir de los problemas anteriores se resolvieron e implementaron:

Agregado

Para Android, aparecieron las compilaciones arm64 y x86.
Puede agregar cualquier objeto Ver al mapa.
Enrutamiento de bicicletas ha aparecido.
Se agregaron anotaciones anulables para Android.

Cambiado

MapKit se divide en partes:
MapKit: solo un mapa;
Direcciones de MapKit: ruta del automóvil;
Transporte MapKit: enrutamiento peatonal, enrutamiento de transporte público y en bicicleta;
Búsqueda de MapKit: búsqueda y geocodificación;
MapKit Places - panoramas.
Para iOS, las anotaciones anulables se han vuelto más estrictas.

Fijo

Se han corregido varios errores.
Rendimiento mejorado.

tech.yandex.ru/maps/doc/mapkit/3.x/concepts/versions-docpage

Escribe tus comentarios, preguntas.

Source: https://habr.com/ru/post/es427611/


All Articles