Cartões animados no SwiftUI

Vamos SwiftUI cartões animados com suporte a gestos no SwiftUI :



Eu queria adicionar uma visualização detalhada, mas o tamanho do gif não é ortodoxo. Uma visualização grande pode ser visualizada no link ou no tutorial em vídeo .


Será necessário


SwiftUI agora na versão beta e é instalado com o novo Xcode, que também está na versão beta. A boa notícia é que o novo Xcode pode ser colocado próximo ao antigo e você quase não sente dor.



Você pode baixá-lo no link na seção Applications .


Você pode ter visto visualizações em tempo real enquanto trabalhava com o SwiftUI . Para ativá-lo, bem como alguns menus de contexto, você precisa instalar o beta macOS Catalina . Não vai ficar sem dor. Eu não apostei, então vou rodar o simulador à moda antiga.


Novo projeto


Crie um Single View Application com uma marca de seleção adicional - SwiftUI :



Vá para o arquivo ContentView.swift . O herdeiro de PreviewProvider é responsável pela visualização. Como não o usaremos, deixaremos o código mínimo necessário:


 import SwiftUI struct ContentView: View { var body: some View { } } 

Espero que já exista um entendimento comum sobre o SwiftUI , não vamos nos debruçar sobre pontos triviais.


Postais


Os cartões são organizados um após o outro, portanto, usaremos o ZStack . Deixe-me lembrá-lo de que existem mais duas opções para agrupar elementos: HStack - horizontalmente e VStack - verticalmente. Para maior clareza:



Adicione o primeiro cartão:


 struct ContentView: View { var body: some View { return ZStack { Rectangle() .fill(Color.black) .frame(height: 230) .cornerRadius(10) .padding(16) } } } 

Aqui, adicionamos um retângulo, pintado de preto, com 230pt altura, arredondando as bordas em 10pt e definindo as margens de todos os lados para 16pt .


O texto no cartão é adicionado ao bloco ZStack após o retângulo:


 Text("Main Card") .color(.white) .font(.title) .bold() 

Execute o projeto para ver o resultado intermediário:



Mas há três deles!



Por conveniência, MainCard código MainCard :


 struct MainCard: View { var title: String var body: some View { ZStack { Rectangle() .fill(Color.black) .frame(height: 230) .cornerRadius(10) .padding(16) Text(title) .color(.white) .font(.largeTitle) .bold() } } } 

O title aparecerá no inicializador. Este texto estará no cartão. Adicione um cartão ao ContentView , ao mesmo tempo, veremos um novo parâmetro no inicializador:


 struct ContentView: View { var body: some View { return MainCard(title: "Main Card") } } 

Já sabemos como criar o código, então defina imediatamente uma classe para cartões de plano de fundo:


 struct Card: View { var title: String var body: some View { ZStack { Rectangle() .fill(Color(red: 68 / 255, green: 41 / 255, blue: 182 / 255)) .frame(height: 230) .cornerRadius(10) .padding(16) Text(title) .color(.white) .font(.title) .bold() } } } 

Defina uma cor e estilo diferentes para o texto. O restante do código repete o MainCard preto principal. Adicione dois cartões de plano de fundo ao ContentView . Os cartões são organizados um após o outro, então os ZStack no ZStack . Código ContentView :


 struct ContentView: View { var body: some View { return ZStack { Card(title: "Third card") Card(title: "Second Card") MainCard(title: "Main Card") } } } 

Os cartões de plano de fundo estão localizados sob o preto e até agora não são visíveis. Adicione deslocamento para cima e preenchimento a partir das bordas:


 Card(title: "Third card") .blendMode(.hardLight) .padding(64) .padding(.bottom, 64) Card(title: "Second Card") .blendMode(.hardLight) .padding(32) .padding(.bottom, 32) MainCard(title: "Main Card") 

Agora, o resultado se assemelha ao anúncio no início do tutorial:



Vamos seguir para gestos e, junto com isso, para animações.


Gestos


A maneira como os gestos são implementados me forçará a menos karma e a deixar uma revisão tóxica.



Antes de ver o código, observe: ele está listado em developer.apple.com como um exemplo. A primeira impressão é enganosa, na prática eu gostei.


Declare enum no ContentView :


 enum DragState { case inactive case dragging(translation: CGSize) var translation: CGSize { switch self { case .inactive: return .zero case .dragging(let translation): return translation } } var isActive: Bool { switch self { case .inactive: return false case .dragging: return true } } } 

DragState tornará o trabalho com um gesto mais confortável. Adicione dragState dragState ao ContentView:


 @GestureState var dragState = DragState.inactive 

Haverá mágica.



Onde quer que dragState seja usado, os novos valores serão aplicados automaticamente. Declare um gesto:


 let dragGester = DragGesture() .updating($dragState) { (value, state, transaction) in state = .dragging(translation: value.translation) } 

Adicione um gesto ao cartão principal e defina o offset :


 MainCard(title: "Main Card") .offset( x: dragState.translation.width, y: dragState.translation.height ) .gesture(dragGester) 

O deslocamento será igual ao valor do parâmetro quando for acessado? Não, sempre será igual . Isso é mágico.


O cartão seguirá com um dedo com um mouse, mas sem animações:



Os cartões de segundo plano também devem mudar de posição ( pelo menos o que desejávamos ). Adicione um código para eles associado ao estado do gesto. rotation3DEffect girará o cartão até que o gesto se torne ativo:


 Card(title: "Third card") .rotation3DEffect(Angle(degrees: dragState.isActive ? 0 : 60), axis: (x: 10.0, y: 10.0, z: 10.0)) .blendMode(.hardLight) .padding(dragState.isActive ? 32 : 64) .padding(.bottom, dragState.isActive ? 32 : 64) Card(title: "Second Card") .rotation3DEffect(Angle(degrees: dragState.isActive ? 0 : 30), axis: (x: 10.0, y: 10.0, z: 10.0)) .blendMode(.hardLight) .padding(dragState.isActive ? 16 : 32) .padding(.bottom, dragState.isActive ? 0 : 32) 

De que outra forma você pode usar 3D, você pode olhar aqui . Eu também adicionei blendMode . Os modos são semelhantes às ferramentas no Photoshop e Sketch.


Enquanto as alterações são aplicadas sem animação, vamos corrigi-lo.


Animação


Você ficará surpreso com o quão simples é. Basta adicionar uma linha:


 .animation(.spring()) 

Adicione para cada cartão. Agora, quaisquer alterações serão aplicadas animadamente, no nosso caso, são tamanhos de recuo, rotação 3D e offset . Se você precisar de animação com curvas, use basic modo basic .


Decorações


Adicione a sombra e a rotação da vista principal, ligadas ao deslocamento:


 .rotationEffect(Angle(degrees: Double(dragState.translation.width / 10))) .shadow(radius: dragState.isActive ? 8 : 0) 

Se você executar o projeto, verá a referência desde o início do tutorial. Ligue a visualização não está visível, puxe o cartão para o lado para ver o efeito.



Para quem procura


→ O código do projeto pode ser encontrado no repositório


Basta copiar o arquivo para o projeto, não são necessárias configurações adicionais. Não tenha medo de que tão pouco código seja um dos SwiftUI da SwiftUI .


Se for mais conveniente para você assistir ao vídeo, dê uma olhada no tutorial. A propósito, no vídeo eu uso visualizações em tempo real.


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


All Articles