Prefácio
Olá amigos , no começo, descreverei imediatamente o objetivo do artigo:
economizando seu tempo se você precisar
atualizar ou incorporar mapas Yandex em seu cliente móvel iOS, além do desejo de compartilhar sua experiência.
Certa vez, criamos o aplicativo YandexMapkit (aproximadamente em outubro de 2017) em vez de cartões de e-mail (nada pessoal - apenas negócios). Depois de cerca de 3 meses, em um lindo dia de inverno, a versão dos cartões Androyd ficou fora de ordem no dia 2 por causa das teclas, o cartão acabou se transformando em abóbora) Qual é a dica do manual: "No android, os cartões estavam quebrados, eles não sabem como consertá-lo". como um cliente iOS, isso não afetou. Pobres no andróide ... desta vez os caras não tinham nada a ver. Naqueles dias
, muitas lojas caíram : o posto da Rússia, o ornitorrinco, talvez vocês se lembrem?

Isso significa que, quando seu aplicativo estiver vinculado a serviços de terceiros, seria bom ter um plano "B" para este caso, por exemplo, alterne para a versão anterior dos cartões da Apple e não substitua um pelo outro ...
Depois de mais três meses, em algum lugar de março, chegou uma carta da Yandex informando que eles finalmente haviam atualizado o sdk (muito pouco tempo se passou, 4-5 anos a partir da atualização anterior):
"-Atualize, desligue o antigo em um ano", em suma. Antes disso, havia simplesmente uma versão antiga 1.0

Bem, é claro, após esse aviso, não retiramos e imediatamente iniciamos a transição ... após 3 meses)) em agosto.
Estágio de "comentar"! (Desativar funcionalidade)
Você diz, ha ... o que é atualizado lá, o pod atualizado, corrigido alguns lugares e é tudo. Então, não, pessoal, a nova API de mapas não é absolutamente compatível com a antiga e, além disso, como se viu mais tarde, existem muitas necessidades vitais que estão prontas para uso na versão antiga e em outras bibliotecas de cartões!
Portanto, o mapkit 3.0 (ao escrever um artigo versão 3.1 foi lançado), um
link para a documentação .
E por que, além de um aviso da Yandex? Enquanto isso, em uma versão beta do Xcode 10, um projeto com uma baleia velha não é estupidamente aceito, porque o C ++ é usado em algum lugar do interior, o que é desprezado na nova versão. É necessário renomeá-lo na sub-lista, até atualizá-lo lá, etc., enfim, não fiz isso, porque no final ainda preciso atualizar
1) Atualizamos o sdk, em vez da versão 1.0 imediatamente 3.0, é claro que a API mudou, mas muito ....
Portanto, o antigo protocolo YMKAnnotation está simplesmente ausente

No momento, parece um trecho forjado (não está zumbindo e você sai carregando um sinal "!" Para si mesmo ... Exemplo de implementação de protocolo:

Bem, vamos escrever novamente) o nosso, somente em vez do método coordenate () criaremos as propriedades, tudo é simples, o método é redundante; title! () é substituído por um título não formado (), por outro lado, você pode criar uma propriedade, bem, muito, onde é necessário alterar o projeto, então acabei de remover o ponto de exclamação.
Em nosso projeto, foi necessário substituir em três controladores algumas vezes, importar o CoreLocation em outro, pois agora ele não é importado em nenhum dos cabeçalhos do Yandex MapPocket.
Para não renomear o familiar YMKMapCoordinate (baleia antiga) ao longo do projeto, fiz tipealias para o YMKPoint (nova baleia)

2) Além disso, vamos declarar algumas propriedades que precisaremos no futuro para trabalhar com o mapa, principalmente getters:

3) A primeira coisa a criar é o YMKMapView (tudo está bem com isso, esse objeto ainda está disponível). Anteriormente, eu o inicializei imediatamente, agora você não pode fazer isso, ele irá travar, porque primeiro você precisa colocar a chave! A chave atual não funcionará e você precisará solicitar uma nova. Adicione ao AppDelegate, de acordo com a documentação. Somente após definir a chave, podemos criar o YMKMapView e configurá-lo da maneira que precisamos no método setupMap ()

O que acontece aqui, analisaremos em detalhes mais adiante, no decorrer da necessidade de configurações apropriadas
4) O que vem a seguir?, E então tínhamos o local inicial do CLLocation, mas agora para usá-lo, você precisa adicionar a estrutura CoreLocation manualmente ou ... ou substituí-la pelo YMKPoint no Yandex mapkit

5) Além disso, o mapa estava centrado nessa coordenada por um método muito simples, mas agora não há

Mas há um pouco mais complicado e um pouco mais profundo, o objeto do mapa) ... mapView.mapWindow.map! .Move. Aqui aprendemos sobre a existência de um objeto como YMKCameraPosition.

6) Em seguida, comentamos a configuração do mapa, uma vez que não existem tais APIs / propriedades. Agora, apenas o omitimos para começar pelo menos minimamente.
Comentamos sobre a adição de anotações (prestarei atenção em que essa é uma funcionalidade padrão), também comentamos sobre a exibição dos pontos mais próximos (isso já é algum tipo de nossa funcionalidade).
E todo o YMKMapViewDelegate também é um comentário, que não encontrei na nova estrutura, e um análogo semelhante também.

Omiti a implementação, apenas os métodos em si:
- se deseja exibir a localização do usuário,
- quais visualizações usar para pinos,
- reação ao clicar na anotação,
- quais frases de destaque para anotação,
- A reação ao clicar na frase de destaque, ou seja, tudo o que costumamos usar. No final, houve algum tipo de método, que também usou um cartão API específico.
TUDO descoberto com o MapVC - esta é a classe principal em que o mapkit foi usado
7) Um pequeno comentário sobre a frase de destaque personalizada, ela não herdará mais o YMKCalloutView, não há mais na nova baleia.
Viva, agora que o projeto se reuniu, eu pude começar tudo e ... ver o caderno na caixa, porque depois que ele começa, você precisa dar um tempo para se aquecer))), mas eu não sabia e achava que algo não estava portanto, embora eu tenha sugerido que leva tempo para ativar a chave. Acontece que a suposição estava correta. Você precisa esperar cerca de uma hora (talvez algo tenha mudado agora).
Com outra tentativa de modificar a API antiga de uma nova maneira, o mapa foi exibido.
Etapa dois - "pesquisa" (como implementar a funcionalidade antiga de uma nova maneira)
Vamos começar a restaurar a funcionalidade perdida. Portanto, você precisa exibir o bloqueio do usuário, mas da maneira antiga, basta alterar a propriedade e definir o delegado.
Agora isso é feito através da camada, consulte o método 3 do setupMap (), ponto 3.
Vamos dar uma olhada no exemplo da demonstração (
download do Yandex github ), já que está lá. A propósito, você precisa prestar atenção ao setAnchorWith. Mais tarde vou dizer o porquê, está associado ao zoom. Ok, a localização funciona.
2) O que vem a seguir, é claro, anotações. Você não pode adicionar da maneira antiga, veremos a demonstração novamente. Há uma classe lá - MapObjectsViewController. Na nova versão, para adicionar pinos ao mapa, o delegado não é necessário; para isso, é necessário acessar a propriedade mapObjects, chamar o método addPlacemark no objeto e passar a coordenada para lá (ainda existem outras sobrecargas).

Repetimos a coleção de anotações (por exemplo, após o recebimento do servidor) e adicionamos uma ao mapa. O método, a propósito, retorna “placeMark” (rótulo do local), que pode ser usado para fazer configurações adicionais, por exemplo, alterar a ordem de exibição através da propriedade zIndex.
Aqui, no entanto, eu perdi o ponto de que antes disso eu subi para procurar um delegado e não o encontrei com segurança e nem um único delegado (na verdade, eles começaram a ser chamados de forma diferente, agora são ouvintes). Sei pela experiência anterior com a baleia Apple e a baleia Yandex antiga que as anotações são reutilizadas, assim como nas células, mas há apenas o addPlacemark na demonstração. À pergunta sobre o lead de cartões Yandex (um pequeno conhecido pessoal ajudado aqui) "- Como otimizar o uso de memória, reutilizar objetos?" Resposta: "Por que, então funciona bem" ... bem, mais ou menos sim, funciona.
Nota: 1) É importante observar que o Yandex.Maps usa um mapkit e não o desenvolve. Isso é feito pela equipe do mapkit (apelido de Nikolai no hub - likhogrud @).
2) Explicação por que os objetos não são reutilizados:
Na baleia antiga, annotationViews eram visualizações, elas foram criadas pelo usuário e, é claro, as visualizações precisam ser reutilizadas, porque criá-las não é barato. Na nova baleia, os marcadores são criados pelo mapkit diretamente no GL aberto. E talvez eles sejam reutilizados lá, mas isso é impreciso. De qualquer forma, isso é muito mais eficiente do que criar uma exibição.
3) A partir da nova, a propósito, existe a possibilidade de modificar o ícone de anotação para o usuário. Implementado da seguinte forma: você precisa adicionar um ouvinte (análogo do delegado), implementar o protocolo apropriado - 1 de 3 métodos, 2 apenas deixar em branco.
Ao mesmo tempo, recarregue o marcador com nossos ícones.

Além disso, chamo sua atenção para a propriedade da âncora. Depois de pressionar o botão de localização do usuário no mapa, a câmera move o foco para o centro da localização. Mas o problema é que pressionar a ação novamente não produz. O que? Comentamos o método âncora e tudo funciona.
4) Agora você precisa mostrar as frases explicativas, respectivamente, para entender o clique. Existem vários métodos nas interfaces, o correto é YMKMapObjectTapListener. Existe um método interessante e importante com o qual tive que me atormentar mais tarde; ele retorna verdadeiro para não integrar ainda mais se um assinante for encontrado. Chamo sua atenção, você precisa se inscrever primeiro, o mapObjects será assinado (linha 149).


Portanto, os cliques cumprem.
Viva . No entanto, houve tentativas de exibir pinos apenas na zona visível, isso é supérfluo, mostra tudo de uma só vez, então vamos deixá-lo (apenas porque não diminui a velocidade)
5) Então eu queria fazer os botões aumentar / diminuir o zoom por conveniência. Um pouco de copiar e colar e editar por analogia com o botão de localização, e pronto.
Além disso, como sabemos sobre a câmera, use o método de movimentação e, consequentemente, o zoom atual + - 1 ou 0,5, conforme necessário. Está tudo bem aqui.

6) Passamos à chamada principal funcional (este é um retângulo com informações adicionais, com um triângulo na parte inferior). Acontece que não há API (“intoxicante no verão” - o Yandex reconheceu meu discurso quando leio notas de um folheto para não digitar manualmente este artigo).

Como vocês estão? 100 500 aplicativos usam uma frase de destaque.
Escrevemos bem em "suporte técnico" (Kolya) como fazer isso manualmente, eu descubro. Quais são as suas opções?
Converta a vista em uma imagem, já que você não pode adicionar diretamente uma vista (adicionado um arquivo no 3.1), altere o ícone ...

Essas muletas são obtidas em um apartamento, parecia lugar.
De fato, não muletas, é claro, mas simplesmente a ausência que considero a funcionalidade básica
7) Ok, vamos primeiro adicionar um texto explicativo de teste, como tal, usamos um quadrado vermelho. Assim, clicando em nosso alfinete, o método delegado / ouvinte é chamado, onde o ponto de clique e o objeto são transferidos. Sem esperar um truque, consideramos "point" como o ponto em que você deseja adicionar a frase de destaque. (Atenção, tudo foi feito corretamente: “Eles clicaram, entenderam e amarraram?” Cerca de 80% responderam corretamente, 20% - não)

E chame o método auxiliar showCallout no corpo do método:

linha 544
No interior, crie uma visualização de teste da cor vermelha de quarenta por quarenta, converta-a em uma imagem, declare um x constante com um valor de 0,5; ela será usada para a posição do triângulo da chamada no meio do ponto. Ele recusou a ideia de mudar de posição, mais tarde preferiu mover a câmera para que a frase de destaque selecionada fosse exibida no meio da tela do telefone.
Em seguida, declaramos a área "push" de tappableArea, existe uma propriedade no estilo de ícone do pino. Bem, você pode limitar a zona de cliques, e nós o faremos. A zona varia de 0,0 a 1,1. precisamos da parte inferior, onde supostamente existe um botão que foi transformado em imagem antes (lembre-se). Ok, isso significa a zona (0,0,5 - 1,1), pois o botão está abaixo.
A restrição de zona funciona, mas há uma nuance, de tal modo que ela nega tudo. Se houver outro pino sob a área não prensada, a pressão funcionará nele. O significado desta área? Eles fariam uma bandeira ou algo assim para que o clique não passasse. Ok ...
Linha 550
vamos criar um estilo para o ícone, você pode especificar imediatamente a posição da âncora no primeiro parâmetro, por exemplo, fiz abaixo na linha 557. A posição y é 1,05 para elevar o triângulo acima do pino novamente na vertical
Linha 559
crie nossa frase de destaque personalizada de um determinado tamanho,
configuramos os campos necessários usando as informações da anotação selecionada selectedAnnotation, em particular o título e o subtítulo, a inscrição no botão para esta frase de destaque. Então você mesmo pode fazer o que quiser. A anotação selecionada é definida anteriormente no delegado. Mas, por enquanto, adicione o quadrado vermelho criado anteriormente
Em seguida, adicione um alfinete à coleção mapObjects, o método retornará o marcador adicionado para nós, salve-o em uma variável,
Ao clicar no texto explicativo em si, um controlador detalhado é aberto e, assim, a nuance é que, se no pino pop-up outro pino também aparecer, o delegado funcionará novamente; portanto, é necessário alterar a ordem na hierarquia através do zIndex. Defina a visibilidade e mova nossa chamada de destaque para o centro na linha 564
Nuances : o marcador de variável é um ponteiro para a frase de destaque.
No começo, não temos, depois de clicar no alfinete, ao que parece, depois de clicar no próximo alfinete, precisamos excluir nossa primeira frase de destaque e adicionar uma nova. Portanto, se o marcador de variável! = Nil, você precisará remover a frase de destaque antiga da coleção mapObjects)

Além disso, no caso de tapas no cartão, você precisa ocultar a frase de destaque; portanto, no método delegado, atribuímos um marcador, o observador trabalha, a frase de destaque é excluída e a anotação selecionada é apagada.
Para isso, inscrevemos-se no YMKMapInputListener anteriormente

Por sua vez, o método para converter visualizações é o seguinte. (Na versão 3.1, foi adicionada a capacidade de adicionar visualizações ao mapa)
Não descrevo como fazer a visualização), mas se houver muitos problemas (é possível com um triângulo) com isso, escreva, acrescentarei esta etapa

A mágica 20 adicionada à altura é necessária para um lugar abaixo do triângulo abaixo, que você terá que desenhar
Também queremos que o pop-up apareça (seja anexado) ao pino em um local específico (esquerda, direita, no meio), pois existe uma propriedade âncora. Definido da seguinte forma:
Dividimos a área visível do mapa em 3 zonas verticais e determinamos em qual delas estamos, dependendo disso, alteramos a posição da encadernação. No exemplo de código, verificamos se estamos do lado esquerdo, por analogia, para o meio, se não para a esquerda e para o meio, respectivamente, o ponto à direita é

Uma função auxiliar para verificar se um ponto cai em uma região:

Iniciar. Isso funciona. Mas há uma nuance, parece que estamos tentando ampliar um, dois, três, e a frase de destaque voa para longe do alfinete. O que? Como

7) Começamos a depuração, as coordenadas são as mesmas

Houve tentativas de entender o que está acontecendo e como funciona, outro retorno à demo, uma busca ainda mais atenta às diferenças ...

Percebo que as coordenadas são transmitidas diretamente, e não a que está na torneira! Mas eu fiquei desapontado, é claro que as coordenadas são as mesmas, ou seja, o círculo e o quadrado têm a mesma coordenada.
Por isso, no método, não acessei imediatamente o objeto, mas passei o ponto, que está incorreto.

Mas você precisa converter um objeto, obter uma propriedade (em todos os lugares tudo é chamado de maneira diferente, depois coordenar, depois apontar, aqui agora geometria) isso é criativo ou não? 493 linhas

Como precisamos processar duas opções prementes: a primeira a fixar, a segunda a destacar e não a processar cliques se clicarmos no mesmo pino novamente, a
primeira coisa que fazemos é encontrar o pino em que clicamos na coleção de pinos, comparando coordena a linha 495; caso contrário, retorne verdadeiro, dizendo que processamos o clique e não precisamos ir mais longe na hierarquia
Segundo : determinamos isso clicando no alfinete ou na frase de destaque, também comparamos as coordenadas dos rótulos das 499 linhas. Teste de Igualdade:
Além disso, se este é um texto explicativo e queremos responder a um clique no botão (ou simular, já que agora é uma imagem), e não a toda a área, precisamos fazer alguns cálculos com canetas :)
- Converter coordenadas mundiais na tela da linha 501
Nós nos consideramos: converteremos as coordenadas do mapa em tela, saberemos onde estamos localizados e, adicionando a largura e a altura da vista, obteremos os pontos de canto, mas por algum motivo eles não coincidem e eu multiplico manualmente por três, no meu caso para o 10º iPhone)). Como se viu depois, esqueci e não levei em conta o número de pixels por ponto. Que podemos ter 1x, (um ponto 1 pixel), 2x, 3x um ponto é três pixels. - Vamos calcular a altura do botão - a altura da frase de destaque + a altura do triângulo multiplicado pela escala, informações sobre a escala (linha 498). Em seguida, dividimos tudo isso em dois, pois a altura do botão é metade da altura da frase de destaque
- Em seguida, calculamos as coordenadas dos ângulos, com base no fato de que a âncora (x: 0,5, y: 1), dada a escala e a área do triângulo))
- Em seguida, converta essas coordenadas da tela em mundo
- Crie uma área visível com base nelas, é uma zona de botão
- E verificamos se atingimos a zona dos botões ou não. Se você acertar, verifique o tipo de anotação, dependendo do tipo que chamamos de método: vá para a tela detalhada ou selecione esta loja para entrega nos casos com StorePoint
Caso contrário, é apenas um clique no alfinete e precisamos adicionar uma frase de destaque, o que realmente fizemos acima.
Isso é tudo, desde que você conheceu a nova baleia.
O que mais eu quero dizer, na implementação atual dos mapas do mapkit, ele contém muitas funcionalidades que não são usadas, isso também afeta o tamanho do binário resultante. Você está pronto para esses sacrifícios? No futuro, os caras devem ser demolidos em módulos, afinal . Também ouvi de colegas no androide do workshop que existem problemas de compatibilidade com o Kotlin.
P.S. Enquanto eu decidi e comecei a escrever um artigo, a atualização 3.1 saiu, onde os problemas acima foram resolvidos e implementados:
Adicionado
Para o Android, apareceram as compilações arm64 e x86.
Você pode adicionar qualquer objeto View ao mapa.
O roteamento de bicicletas apareceu.
Adicionadas anotações anuláveis para o Android.
Alterado
O MapKit é dividido em partes:
MapKit - apenas um mapa;
Direções do MapKit - roteamento de automóveis;
Transporte MapKit - roteamento de pedestres, roteamento de transporte público e roteamento de bicicleta;
Pesquisa no MapKit - pesquisa e geocodificação;
MapKit Places - panoramas.
Para iOS, as anotações anuláveis se tornaram mais rigorosas.
Fixed
Vários bugs foram corrigidos.
Melhor desempenho.
tech.yandex.ru/maps/doc/mapkit/3.x/concepts/versions-docpageEscreva seus comentários, perguntas.