Olá! Meu nome é Giovanna Moeller, eu sou instrutora na Alura, e quero te dar boas-vindas ao curso de iOS com SwiftUI voltado para animações!
Giovanna é uma mulher branca de cabelo loiro, liso e comprido, e olhos castanho-escuro. Ela veste uma blusa azul-escuro e está nos estúdios da Alura, sentada em uma cadeira preta em frente a uma parede cinza iluminada em roxo, com uma estante preta com plantas e enfeites à direita.
Nosso projeto será o aplicativo Chef Delivery e vamos implementar a ele novas funcionalidades, como uma tela de boas-vindas focada em animar os componentes, que são:
Além disso, vamos implementar um carrossel na página inicial de forma totalmente automática.
Nesse curso, entenderemos como o SwiftUI consegue tornar determinadas coisas muito mais simples e fáceis para nós, em relação à questão das animações. Uma tela com esse tipo de animação torna a experiência da pessoa usuária muito mais agradável, além de ser mais agradável também visualmente.
Como pré-requisito desse curso, é importante que você já tenha certo conhecimento sobre a construção de layouts simples com Swift UI, e também sobre gerenciamento de estados com Swift UI.
Mas não se preocupe! Temos todos esses conteúdos disponíveis na plataforma, basta acessar a página da nossa escola de Mobile.
Em caso de dúvida, lembre-se de nos chamar no fórum e também no Discord, onde você vai encontrar outras pessoas que estão fazendo esse curso ou já finalizaram!
Espero que você tenha se animado para começar a implementar de fato as animações do projeto e deixar seu aplicativo muito mais bonito.
Te espero para a primeira aula!
Nossa tarefa para esse curso será criar a tela de boas-vindas exibida abaixo, que consiste em bastante animação dos componentes!
Animações são técnicas visuais que adicionam movimento à interface da pessoa usuária. Elas trazem dinamismo e interatividade, então são elementos incríveis para a experiência da pessoa usuária.
Eu, particularmente, acho incríveis os aplicativos que contêm animações, por isso reservamos um curso específico para animações com o SwiftUI.
Retornando ao projeto, nosso primeiro passo será criar a tela de boas-vindas. Para isso, criaremos uma nova pasta dentro de "ChefDelivery", chamada "HomeView".
Dentro dela, vamos criar um novo arquivo do tipo "SwiftUI View" chamado HomeView.swift
.
import SwiftUI
struct HomeView: View {
var body: some View {
Text("Hello, World!")
}
}
struct HomeView_Previews: PreviewProvider {
static var previews: some View {
HomeView()
}
}
Como essa será a primeira tela do nosso aplicativo, precisamos fazer uma modificação no arquivo ChefDeliveryApp.swift
, que por enquanto tem como primeira tela a ContentView()
. Vamos substituí-la por HomeView()
.
import SwiftUI
@main
struct ChefDeliveryApp: App {
var body: some Scene {
WindowGroup {
HomeView()
}
}
}
Feito isso, podemos retornar ao arquivo HomeView.swift
para começar a construir o layout. Primeiramente, vamos remover o elemento Text()
e adicionar uma VStack
.
import SwiftUI
struct HomeView: View {
var body: some View {
VStack {
}
}
}
struct HomeView_Previews: PreviewProvider {
static var previews: some View {
HomeView()
}
}
Entre as chaves dessa VStack
, vamos usar o Text()
para adicionar um texto, que será "Chef Delivery". Em seguida, colocaremos alguns modificadores de propriedade para esse componente.
O primeiro deles será relacionado à fonte (.font()
). Queremos que ela seja bem grande, então vamos usar um tamanho fixo nesse caso. Para isso, passamos .system()
para o modificador e adicionamos a ele a propriedade size
com o valor 40.
Também vamos usar o modificador .fontWeight()
, passando o .heavy
como parâmetro.
Por fim, vamos utilizar um modificador de cor, o .foregroundColor()
. Passaremos para ele a cor "ColorRed", que está dentro de "Assets".
Para finalizar, vamos adicionar o componente Spacer()
, para que seja ocupado todo o espaço disponível e o texto seja posicionado na extremidade superior da tela.
import SwiftUI
struct HomeView: View {
var body: some View {
VStack {
Text("Chef Delivery")
.font(.system(size: 48))
.fontWeight(.heavy)
.foregroundColor(Color("ColorRed"))
Spacer()
}
}
}
struct HomeView_Previews: PreviewProvider {
static var previews: some View {
HomeView()
}
}
Agora nosso objetivo é criar um efeito de opacidade, de modo que, quando a tela aparecer, o texto vá de totalmente transparente até o opaco. Para fazer isso, começamos criando uma propriedade de estado (@State
) logo abaixo da view HomeView
. Ela será do tipo private var
e a chamaremos de isAnimating
.
Essa propriedade de estado será um booleano, ou seja, só possuirá valores de true
(verdadeiro) ou false
(falso). Iremos iniciar como false
, pois o momento em que a tela aparece é quando mudamos para verdadeiro.
import SwiftUI
struct HomeView: View {
@State private var isAnimating = false
var body: some View {
VStack {
Text("Chef Delivery")
.font(.system(size: 48))
.fontWeight(.heavy)
.foregroundColor(Color("ColorRed"))
Spacer()
}
}
}
struct HomeView_Previews: PreviewProvider {
static var previews: some View {
HomeView()
}
}
Como saber quando a tela estiver aparecendo? Para isso, existe um modificador de propriedade chamado .onAppear()
. Vamos aplicá-lo ao VStack
, mas em vez de parênteses após o modificador, abriremos chaves.
Dentro do .onAppear {}
, passaremos que a propriedade isAnimating
é igual a true
.
import SwiftUI
struct HomeView: View {
@State private var isAnimating = false
var body: some View {
VStack {
Text("Chef Delivery")
.font(.system(size: 48))
.fontWeight(.heavy)
.foregroundColor(Color("ColorRed"))
Spacer()
}
.onAppear {
isAnimating = true
}
}
}
struct HomeView_Previews: PreviewProvider {
static var previews: some View {
HomeView()
}
}
Agora podemos adicionar os modificadores de propriedade com base nessa propriedade de estado. Por exemplo: no Text()
, vamos incluir o modificador .opacity()
e, entre parênteses, adicionaremos um operador if
ternário.
Relembrando: o
if
ternário é composto por ponto de interrogação (?
) e dois-pontos (:
).
Entre os parênteses do modificador, vamos digitar isAnimating
seguido de ?
. Com isso, queremos dizer que se isAnimating
for igual a true
, o texto ficará totalmente opaco, então adicionamos o valor 1 após a interrogação. Se a propriedade isAnimating
for igual a false
, ou seja, :
, o valor será 0, sem opacidade.
import SwiftUI
struct HomeView: View {
@State private var isAnimating = false
var body: some View {
VStack {
Text("Chef Delivery")
.font(.system(size: 48))
.fontWeight(.heavy)
.foregroundColor(Color("ColorRed"))
.opacity(isAnimating ? 1 : 0)
Spacer()
}
.onAppear {
isAnimating = true
}
}
}
struct HomeView_Previews: PreviewProvider {
static var previews: some View {
HomeView()
}
}
Ao executar esse código, o resultado no simulador estará igual ao anterior, praticamente sem acontecer nada, pois o texto já vem diretamente opaco. Isso acontece porque não existe nenhuma transição suave entre o estado do isAnimating
.
Ou seja, quando o isAnimating
vai de false
para true
assim que a tela aparece, não existe nenhuma animação suave. Precisamos implementar isso!
withAnimation()
Existe um bloco de código em SwiftUI chamado withAnimation()
, que nos permite adicionar animação às alterações de propriedade. Interessante, não é?
Dentro do modificador .onAppear {}
, vamos começar escrevendo withAnimation()
.
Se digitarmos um ponto (.
) entre os parênteses, serão sugeridas várias opções de animação. A minha animação favorita é a easeInOut()
, pois ela começa devagar, se torna mais rápida, e depois volta a ser devagar.
Vamos selecionar a opção easeInOut(duration:)
, para adicionar também a duração da animação. Por padrão, ela dura 0.25 segundos. Nesse caso, vamos definir a duração como 3 segundos, para visualizar melhor a animação acontecer.
/* Código suprimido */
.onAppear {
withAnimation(.easyInOut(duration: 3))
isAnimating = true
}
/* Código suprimido */
Em seguida, vamos adicionar chaves ao final do withAnimation()
e deslocar a propriedade isAnimating
da linha de código 28 para dentro desse bloco de código.
.onAppear {
withAnimation(.easeInOut(duration: 3)) {
isAnimating = true
}
}
Executando o código com essas modificações, teremos o efeito de opacidade acontecendo com uma animação, que no caso é uma transição suave. Com o bloco de código withAnimation()
, podemos animar as variáveis quando elas mudam de estado.
Vamos adicionar também um modificador de offset (.offset()
). Esse modificador basicamente causa um deslocamento no eixo vertical (y) e no eixo horizontal (x).
Começaremos trabalhando com o eixo vertical, então vamos digitar y
e, após dois-pontos, adicionar a propriedade isAnimating
seguida de uma interrogação.
Queremos dizer que se a propriedade for verdadeira (valor true
), o deslocamento será nulo, então digitamos 0. Se for falsa (valor false
), teremos o deslocamento de -40, para criar um efeito do texto se deslocando de cima para baixo.
.offset(y: isAnimating ? 0 : -40)
Executando o código com essa alteração, teremos o efeito desejado do texto descendo, além da transição suave de 3 segundos, conforme definido anteriormente.
Nesse caso, 3 segundos é um tempo longo, que adicionamos apenas para visualizar a animação acontecer. Podemos alterar para 1.5, um tempo interessante para rodar a animação.
.onAppear { withAnimation(.easeInOut(duration: 1.5)) { isAnimating = true } }
Agora vamos adicionar o subtítulo da tela. Após o componente Text()
referente ao título, colocaremos um novo Text()
, contendo o texto "Peça as suas comidas favoritas no conforto da sua casa".
Incluiremos também alguns modificadores, como:
.font()
: definido como title2
;.padding()
;.multilineTextAlignment()
: definido como .center
para centralizar o texto;.foregroundColor()
: definido como .black
com opacidade (.opacity()
) de 0.7;.opacity()
: definiremos o mesmo que utilizamos para o primeiro Text()
, então isAnimating ? 1 : 0
;.offset()
: também seguiremos o mesmo padrão utilizado para o primeiro Text()
, ou seja, y: isAnimating ? 0 : -40
.É importante mencionar que, às vezes, as animações não funcionam tão bem no simulador, então se acontecer algum bug, não se preocupe, pois o XCode é assim mesmo!
Abaixo, o resultado do código de HomeView.swift
até o momento:
import SwiftUI
struct HomeView: View {
@State private var isAnimating = false
var body: some View {
VStack {
Text("Chef Delivery")
.font(.system(size: 48))
.fontWeight(.heavy)
.foregroundColor(Color("ColorRed"))
.opacity(isAnimating ? 1 : 0)
.offset(y: isAnimating ? 0 : -40)
Text("Peça as suas comidas favoritas no conforto da sua casa.")
.font(.title2)
.padding()
.multilineTextAlignment(.center)
.foregroundColor(.black.opacity(0.7))
.opacity(isAnimating ? 1 : 0)
.offset(y: isAnimating ? 0 : -40)
Spacer()
}
.onAppear {
withAnimation(.easeInOut(duration: 1.5)) {
isAnimating = true
}
}
}
}
struct HomeView_Previews: PreviewProvider {
static var previews: some View {
HomeView()
}
}
Feito isso, teremos dois efeitos de animação aplicados a ambos os textos adicionados: o primeiro de opacidade, e o segundo de offset.
Você já entendeu um pouco mais sobre animações, como podemos utilizar o bloco withAnimation()
para animar quando uma variável tem seu valor alterado, e também como utilizamos o operador ternário para criar modificadores de propriedade com a visualização de animação.
Agora precisamos criar o efeito de desfoque no fundo da tela. Para fazer isso, espero você no próximo vídeo!
Já temos os textos criados na nossa tela. Agora precisamos criar o fundo!
O fundo é composto por dois círculos vermelhos que estão com o efeito de desfoque, nos cantos superior esquerdo e inferior direito da tela. Para criar esse fundo, precisamos aprender sobre um container chamado ZStack
, pois os círculos estão atrás dos textos, da imagem e do botão.
O ZStack
faz referência ao eixo z, que é o eixo de profundidade.
Retornando ao código do arquivo HomeView.swift
, vamos pressionar a tecla "Command" e clicar sobre a view VStack
. Feito isso, selecionaremos a opção "Embed in ZStack".
Teremos o seguinte resultado no código:
import SwiftUI
struct HomeView: View {
@State private var isAnimating = false
var body: some View {
ZStack {
VStack {
Text("Chef Delivery")
.font(.system(size: 48))
.fontWeight(.heavy)
.foregroundColor(Color("ColorRed"))
.opacity(isAnimating ? 1 : 0)
.offset(y: isAnimating ? 0 : -40)
Text("Peça as suas comidas favoritas no conforto da sua casa.")
.font(.title2)
.padding()
.multilineTextAlignment(.center)
.foregroundColor(.black.opacity(0.7))
.opacity(isAnimating ? 1 : 0)
.offset(y: isAnimating ? 0 : -40)
Spacer()
}
}
.onAppear {
withAnimation(.easeInOut(duration: 1.5)) {
isAnimating = true
}
}
}
}
struct HomeView_Previews: PreviewProvider {
static var previews: some View {
HomeView()
}
}
O primeiro componente do ZStack
será um círculo, então vamos escrever Circle()
. Definiremos uma cor de fundo para ele, utilizando o modificador .foregroundColor()
. A cor será "ColorRed", salva em "Assets" e utilizada também no título.
Além desse modificador, vamos utilizar o .frame()
para diminuir o tamanho desse círculo. Para isso, o parâmetro width
será definido como 200.
Agora precisamos adicionar um modificador chamado .position()
. Esse modificador irá definir onde o círculo fica na tela. Para isso, ele recebe dois parâmetros: o x
e o y
, definindo os eixos horizontal e vertical, respectivamente.
Para o x
, vamos passar o valor de 50, para que o círculo fique posicionado um pouco mais à esquerda. Lembrando que os eixos x
e y
iguais a 0, seria correspondente ao canto superior esquerdo da tela. Em seguida, vamos definir o y
com o valor de 100, para movê-lo um pouco para baixo em relação à extremidade do topo.
Para criar o efeito de desfoque, podemos utilizar o modificador .blur()
contendo o parâmetro radius
, que irá receber o valor 60.
Vamos finalizar reduzindo um pouco do vermelho do círculo. Para isso, adicionamos o modificador de propriedade .opacity()
e passaremos o valor 0.5.
import SwiftUI
struct HomeView: View {
@State private var isAnimating = false
var body: some View {
ZStack {
Circle()
.foregroundColor(Color("ColorRed"))
.frame(width: 200)
.position(x: 50, y: 100)
.blur(radius: 60)
.opacity(0.5)
/* Código suprimido */
No momento, temos o seguinte resultado no simulador:
Como o círculo é o primeiro componente do ZStack
, então ele fica atrás dos outros elementos. Caso o VStack
viesse antes do círculo, o VStack
ficaria atrás do círculo, então a ordem no código importa bastante nesse caso.
Vamos copiar o bloco Circle()
que acabamos de criar e colar logo abaixo, pois será adicionado um novo elemento de círculo.
Você deve estar pensando que poderia ser criado um componente para o círculo, já que serão modificadas poucas coisas nesse processo. É verdade, você poderia criar esse componente, mas como não é esse o escopo do nosso curso, vamos manter dessa forma.
Para o segundo círculo, vamos alterar a cor no modificador .foregroundColor
de "ColorRed" para "ColorRedDark", para trazer uma diferença entre os componentes.
Até o momento, temos o seguinte:
import SwiftUI
struct HomeView: View {
@State private var isAnimating = false
var body: some View {
ZStack {
Circle()
.foregroundColor(Color("ColorRed"))
.frame(width: 200)
.position(x: 50, y: 100)
.blur(radius: 60)
.opacity(0.5)
Circle()
.foregroundColor(Color("ColorRedDark"))
.frame(width: 200)
.position(x: 50, y: 100)
.blur(radius: 60)
.opacity(0.5)
/* Código suprimido */
Agora temos um problema: gostaríamos de posicionar o segundo círculo no canto inferior direito da tela. Qual será a .position()
do x
e do y
nesse caso? Será que precisamos testar valores até encontrar o resultado desejado? O que aconteceria se estivéssemos utilizando um iPad, por exemplo, cuja dimensão é bem maior?
Existe uma maneira de saber quais são os valores das extremidades de uma tela. Para fazer isso, podemos utilizar um container oferecido pelo SwiftUI chamado GeometryReader
, que consegue pegar os valores das dimensões do nosso dispositivo.
Vamos pressionar a tecla "Command" e clicar sobre o ZStack
na linha de código 16, para então selecionar a opção "Embed…". Será criado acima do ZStack
um elemento Container {}
, que vamos renomear para GeometryReader
.
Para utilizar o GeometryReader
, precisamos ter acesso a uma variável para dar os valores das dimensões, então logo após a abertura de chaves do GeometryReader
, vamos adicionar geometry in
.
import SwiftUI
struct HomeView: View {
@State private var isAnimating = false
var body: some View {
GeometryReader { geometry in
ZStack {
Circle()
.foregroundColor(Color("ColorRed"))
.frame(width: 200)
.position(x: 50, y: 100)
.blur(radius: 60)
.opacity(0.5)
Circle()
.foregroundColor(Color("ColorRedDark"))
.frame(width: 200)
.position(x: 50, y: 100)
.blur(radius: 60)
.opacity(0.5)
VStack {
Text("Chef Delivery")
.font(.system(size: 48))
.fontWeight(.heavy)
.foregroundColor(Color("ColorRed"))
.opacity(isAnimating ? 1 : 0)
.offset(y: isAnimating ? 0 : -40)
Text("Peça as suas comidas favoritas no conforto da sua casa.")
.font(.title2)
.padding()
.multilineTextAlignment(.center)
.foregroundColor(.black.opacity(0.7))
.opacity(isAnimating ? 1 : 0)
.offset(y: isAnimating ? 0 : -40)
Spacer()
}
}
}
.onAppear {
withAnimation(.easeInOut(duration: 1.5)) {
isAnimating = true
}
}
}
}
struct HomeView_Previews: PreviewProvider {
static var previews: some View {
HomeView()
}
}
Feito isso, a variável geometry
dará todas as informações referentes às extremidades e às posições do nosso dispositivo.
Vamos retornar ao bloco do segundo círculo, e em vez de passar o valor 200 para o parâmetro x
, vamos digitar geometry.size.width
. Dessa forma, será retornada a largura do dispositivo.
Em seguida, faremos uma conta básica de menos 50, adicionando - 50
após o geometry.size.width
, para que o círculo fique posicionado um pouco mais à esquerda na tela.
No caso do y
, vamos digitar geometry.size.height
, correspondente à altura do dispositivo. Da mesma forma, vamos adicionar - 50
para mover o círculo um pouco para cima.
Circle()
.foregroundColor(Color("ColorRedDark"))
.frame(width: 200)
.position(x: geometry.size.width - 50, y: geometry.size.height - 50)
.blur(radius: 60)
.opacity(0.5)
Teremos o seguinte resultado no simulador:
Já temos nosso fundo de desfoque criado, mas ainda precisamos adicionar alguma animação a eles, pois até o momento, quando executamos o código, os textos são animados e os círculos são estáticos.
Vamos trazer um pouco de vida para eles? Te espero para o próximo vídeo!
O curso iOS com SwiftUI: trabalhando com animações e DragGesture possui 74 minutos de vídeos, em um total de 39 atividades. Gostou? Conheça nossos outros cursos de iOS em Mobile, ou leia nossos artigos de Mobile.
Matricule-se e comece a estudar com a gente hoje! Conheça outros tópicos abordados durante o curso:
Mais de 1500 cursos completamente atualizados, com novos lançamentos todas as semanas, emProgramação, Front-end, UX & Design, Data Science, Mobile, DevOps e Inovação & Gestão.
Desafios temáticos para você turbinar seu portfólio. Você aprende na prática, com exercícios e projetos que simulam o dia a dia profissional.
Webséries exclusivas com discussões avançadas sobre arquitetura de sistemas com profissionais de grandes corporações e startups.
Emitimos certificados para atestar que você finalizou nossos cursos e formações.
Mais de 1500 cursos completamente atualizados, com novos lançamentos todas as semanas, emProgramação, Front-end, UX & Design, Data Science, Mobile, DevOps e Inovação & Gestão.
Desafios temáticos para você turbinar seu portfólio. Você aprende na prática, com exercícios e projetos que simulam o dia a dia profissional.
Webséries exclusivas com discussões avançadas sobre arquitetura de sistemas com profissionais de grandes corporações e startups.
Emitimos certificados para atestar que você finalizou nossos cursos e formações.
Luri é nossa inteligência artificial que tira dúvidas, dá exemplos práticos e ajuda a mergulhar ainda mais durante as aulas. Você pode conversar com Luri até 100 mensagens por semana.
Estude a língua inglesa com um curso 100% focado em tecnologia e expanda seus horizontes profissionais.
Acesso completo
durante 1 ano
Estude 24h/dia
onde e quando quiser
Novos cursos
todas as semanas