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.