Alguém pode me dizer como eu posso imitar a folha de baixo no novo aplicativo Maps no iOS 10?
No Android, você pode usar um BottomSheet
que imita esse comportamento, mas não consegui encontrar nada parecido no iOS.
É uma visualização de rolagem simples com um conteúdo inserido, de modo que a barra de pesquisa fique na parte inferior?
Eu sou bastante novo na programação do iOS, portanto, se alguém pudesse me ajudar a criar esse layout, isso seria muito apreciado.
Isto é o que quero dizer com "folha de baixo":
Respostas:
Não sei exatamente como a parte inferior do novo aplicativo do Google Maps responde às interações do usuário. Mas você pode criar uma exibição personalizada que se pareça com a das capturas de tela e adicioná-la à exibição principal.
Presumo que você saiba como:
1- crie controladores de exibição por storyboards ou usando arquivos xib.
2- use o googleMaps ou o MapKit da Apple.
Exemplo
1- Crie 2 controladores de exibição, por exemplo, MapViewController e BottomSheetViewController . O primeiro controlador hospedará o mapa e o segundo é a própria folha de baixo.
Configurar o MapViewController
Crie um método para adicionar a visualização da folha inferior.
E chame-o no método viewDidAppear:
Configurar BottomSheetViewController
1) Preparar o histórico
Crie um método para adicionar efeitos de desfoque e vibração
chame esse método na sua viewWillAppear
Certifique-se de que a cor de fundo da visualização do seu controlador seja clara.
2) Animar aparência bottomSheet
3) Modifique seu xib como desejar.
4) Adicione o Pan Gesture Recognizer à sua exibição.
No seu método viewDidLoad, adicione UIPanGestureRecognizer.
E implemente seu comportamento gestual:
Folha inferior rolável:
Se sua visualização personalizada for uma visualização de rolagem ou qualquer outra visualização herdada, você terá duas opções:
Primeiro:
Projete a vista com uma vista de cabeçalho e adicione o panGesture ao cabeçalho. (má experiência do usuário) .
Segundo:
1 - Adicione o panGesture à vista de folha inferior.
2 - Implemente o UIGestureRecognizerDelegate e defina o delegado panGesture no controlador.
3- Implemente a função delegar shouldRecognizeSimultaneousWith e desabilite a propriedade scrollView isScrollEnabled em dois casos:
Caso contrário, ative a rolagem.
NOTA
Caso você defina .allowUserInteraction como uma opção de animação, como no projeto de amostra, será necessário ativar a rolagem no fechamento da conclusão da animação se o usuário estiver rolando para cima.
Projeto de exemplo
Criei um projeto de amostra com mais opções neste repositório, o que pode lhe fornecer informações melhores sobre como personalizar o fluxo.
Na demonstração, a função addBottomSheetView () controla qual visualização deve ser usada como uma folha inferior.
Exemplo de capturas de tela do projeto
- Vista parcial
- Vista completa
- Visualização rolável
fonte
Lancei uma biblioteca com base na minha resposta abaixo.
Ele imita a sobreposição do aplicativo Atalhos. Veja este artigo para detalhes.
O principal componente da biblioteca é o
OverlayContainerViewController
. Ele define uma área na qual um controlador de exibição pode ser arrastado para cima e para baixo, ocultando ou revelando o conteúdo abaixo dele.Implemente
OverlayContainerViewControllerDelegate
para especificar o número de entalhes desejados:Resposta anterior
Eu acho que há um ponto significativo que não é tratado nas soluções sugeridas: a transição entre o pergaminho e a tradução.
No Maps, como você deve ter notado, quando o tableView chega
contentOffset.y == 0
, a folha inferior desliza para cima ou para baixo.A questão é complicada, porque não podemos simplesmente ativar / desativar a rolagem quando nosso gesto de panorâmica inicia a tradução. Pararia o pergaminho até um novo toque começar. Este é o caso na maioria das soluções propostas aqui.
Aqui está minha tentativa de implementar esta moção.
Ponto de partida: aplicativo do Google Maps
Para iniciar nossa investigação, vamos visualizar a vista hierarquia de Mapas (iniciar Mapas em um simulador e selecione
Debug
>Attach to process by PID or Name
>Maps
no Xcode 9).Não diz como o movimento funciona, mas me ajudou a entender a lógica dele. Você pode jogar com o lldb e o depurador da hierarquia de visualizações.
Nossas pilhas de controladores de exibição
Vamos criar uma versão básica da arquitetura do Maps ViewController.
Começamos com um
BackgroundViewController
(nossa visualização de mapa):Colocamos o tableView em um dedicado
UIViewController
:Agora, precisamos de um VC para incorporar a sobreposição e gerenciar sua tradução. Para simplificar o problema, consideramos que ele pode converter a sobreposição de um ponto estático
OverlayPosition.maximum
para outroOverlayPosition.minimum
.Por enquanto, ele possui apenas um método público para animar a mudança de posição e possui uma visão transparente:
Finalmente, precisamos de um ViewController para incorporar tudo:
Em nosso AppDelegate, nossa sequência de inicialização se parece com:
A dificuldade por trás da tradução da sobreposição
Agora, como traduzir nossa sobreposição?
A maioria das soluções propostas usa um reconhecedor de gesto de panorâmica dedicado, mas na verdade já temos um: o gesto de panorâmica da exibição da tabela. Além disso, precisamos manter o pergaminho e a tradução sincronizados e
UIScrollViewDelegate
todos os eventos de que precisamos!Uma implementação ingênua usaria um segundo gesto de panorâmica e tentaria redefinir a
contentOffset
exibição da tabela quando a tradução ocorrer:Mas não funciona. O tableView atualiza
contentOffset
quando sua própria ação do reconhecedor de gestos de movimento é acionada ou quando seu retorno de chamada displayLink é chamado. Não há nenhuma chance de que nosso reconhecedor seja acionado logo após aqueles para substituir com êxito ocontentOffset
. Nossa única chance é participar da fase de layout (substituindolayoutSubviews
as chamadas de exibição de rolagem em cada quadro da exibição de rolagem) ou responder aodidScroll
método do delegado chamado toda vez que acontentOffset
modificação for modificada. Vamos tentar este.A tradução Implementation
Adicionamos um delegado ao nosso
OverlayVC
para despachar os eventos do scrollview ao nosso manipulador de traduções, oOverlayContainerViewController
:Em nosso contêiner, acompanhamos a tradução usando uma enumeração:
O cálculo da posição atual é semelhante a:
Precisamos de 3 métodos para lidar com a tradução:
O primeiro diz-nos se precisamos iniciar a tradução.
O segundo realiza a tradução. Ele usa o
translation(in:)
método do gesto de panorâmica do scrollView.O terceiro anima o final da tradução quando o usuário solta o dedo. Calculamos a posição usando a velocidade e a posição atual da vista.
A implementação delegada da nossa sobreposição simplesmente se parece com:
Problema final: despachar os toques do contêiner de sobreposição
A tradução agora é bastante eficiente. Mas ainda há um problema final: os retoques não são entregues à nossa visão de segundo plano. Todos eles são interceptados pela visão do contêiner de sobreposição. Não podemos definir
isUserInteractionEnabled
como,false
porque isso também desativaria a interação em nossa visualização de tabela. A solução é aquela usada maciçamente no aplicativo MapsPassThroughView
:Ele se remove da cadeia de respostas.
Em
OverlayContainerViewController
:Resultado
Aqui está o resultado:
Você pode encontrar o código aqui .
Por favor, se você encontrar algum erro, me avise! Observe que sua implementação pode, é claro, usar um segundo gesto de panorâmica, especialmente se você adicionar um cabeçalho em sua sobreposição.
Atualização 23/08/18
Podemos substituir
scrollViewDidEndDragging
por, emwillEndScrollingWithVelocity
vez deenabling
/disabling
o rolo, quando o usuário terminar de arrastar:Podemos usar uma animação de primavera e permitir a interação do usuário durante a animação para melhorar o fluxo do movimento:
fonte
UIViewPropertyAnimator
(que tem a capacidade de pausar) e use afractionComplete
propriedade para executar a limpeza.translateView(following:)
método, você calcula a altura com base na conversão, mas isso pode começar com um valor diferente de 0,0 (por exemplo, a exibição da tabela é rolada um pouco e a sobreposição é maximizada quando você começa a arrastar) . Isso resultaria no salto inicial. Você poderia resolver isso peloscrollViewWillBeginDragging
retorno de chamada, onde lembraria a inicialcontentOffset
da exibição da tabela e a usaria notranslateView(following:)
cálculo da.csrutil disable && reboot
. Você terá todos os poderes que o root normalmente fornecerá, incluindo a capacidade de se conectar a um processo da Apple.Tente Polia :
https://github.com/52inc/Pulley
fonte
Você pode tentar minha resposta https://github.com/SCENEE/FloatingPanel . Ele fornece um controlador de exibição de contêiner para exibir uma interface de "folha inferior".
É fácil de usar e você não se importa com o manuseio do reconhecedor de gestos! Além disso, você pode acompanhar a exibição de uma rolagem (ou a exibição de irmãos) em uma folha inferior, se necessário.
Este é um exemplo simples. Observe que você precisa preparar um controlador de exibição para exibir seu conteúdo em uma folha inferior.
Aqui está outro exemplo de código para exibir uma folha inferior e procurar um local como o Apple Maps.
fonte
Escrevi minha própria biblioteca para obter o comportamento pretendido no aplicativo ios Maps. É uma solução orientada a protocolo. Portanto, você não precisa herdar nenhuma classe base, em vez disso, crie um controlador de folha e configure como desejar. Ele também suporta navegação / apresentação interna com ou sem o UINavigationController.
Veja o link abaixo para mais detalhes.
https://github.com/OfTheWolf/UBottomSheet
fonte
Recentemente, criei um componente chamado
SwipeableView
como subclasse deUIView
, escrito no Swift 5.1. Ele suporta todas as quatro direções, possui várias opções de personalização e pode animar e interpolar diferentes atributos e itens (como restrições de layout, cor de fundo / tonalidade, transformação afim, canal alfa e centro de exibição, todos demonstrados com o respectivo caso de exibição). Ele também suporta a coordenação de deslizar com a visualização de rolagem interna, se configurada ou detectada automaticamente. Deve ser bastante fácil e direto de usar (espero 🙂)Link em https://github.com/LucaIaco/SwipeableView
prova de conceito:
Espero que ajude
fonte
Talvez você possa tentar minha resposta https://github.com/AnYuan/AYPannel , inspirada no Pulley. Transição suave de mover a gaveta para rolar a lista. Adicionei um gesto de panorama na exibição de rolagem do contêiner e defina shouldRecognizeSimultaneamenteWithGestureRecognizer para retornar YES. Mais detalhes no meu link do github acima. Deseja ajudar.
fonte