Olá, eu sou a Nay! Boas-vindas ao curso de Angular: aprimore suas técnicas de animação!
Nayanne Batista é uma pessoa de pele morena. Tem olhos castanhos escuros e cabelos lisos também castanhos escuros. Usa óculos de grau com armação quadrada e está com uma camiseta laranja. Ao fundo, uma estante com livros e iluminação na cor verde.
Sabia que as pessoas usuárias formam uma primeira opinião sobre seu site em apenas 50 milissegundos?
É por isso que causar uma boa impressa é fundamental!
Quem contribui para isso são as animações. Além de deixarem o visual do site mais bonito, também melhoram a usabilidade por meio de feedbacks animados durante a navegação.
Esse curso é para você que já possui conhecimento sobre animação e também a biblioteca RxJS
Nas aulas, vamos explorar métodos mais avançados de animações, como group()
, query()
, stagger()
, keyframes()
e cubic-bezier()
. Assim descobriremos como criar animações mais complexas e personalizadas.
Durante o curso, você irá aprender:
Como criar animações e vinculá-las à validação dos campos de formulário;
Animar a entrada e saída de elementos;
Criar animações simultâneas e de forma sequencial.
Usaremos o RxJS para as animações funcionarem de forma eficiente.
Aceita o desafio? Te esperamos no próximo vídeo!
Que bom que você está de volta! Nesse curso, continuaremos animando o projeto Memorando.
A instrutora conta que está utilizando o projeto para cadastrar suas tarefas pessoais de trabalho e estudo, por isso o projeto está com uma lista maior.
O nível de complexidade dessas tarefas variam, as mais dfíceis, por exemplo, demandam mais tempo para serem realizadas.
Como a instrutora finalizou a tarefa chamada "Refatorar Código" ela a procura no projeto, utilizando o scroll, e a marca como cumprida, sinalizando com o "check".
Como a lista é grande, não é tão simples encontrar uma tarefa entre as demais cadastradas. Uma solução que simplificaria esse processo seria a implementação de um campo para filtrar as tarefas.
Essa é a missão dessa aula! Construiremos essa solução e deixaremos todo o processo animado.
Começamos abrindo o VS Code. Como a aplicação já está sendo executada, ao clicarmos na pasta "app > lista-tarefas" encontramos os arquivos lista-tarefas.component.html
e lista-tarefas.component.ts
, abrimos os dois.
lista-tarefas.component.html
Abaixo da imagem, img src
, vamos inserir um campo de busca. Para isso, criamos uma div.class="busca"
.
Nela, criamos um parágrafo <p></p>
com o atributo de classe"ff-prompt"
e o texto Procurando o que fazer?
.
<! -- código omitido -->
<div class="busca">
<p class="ff-prompt">Procurando o que fazer?</p>
Na linha abaixo, criamos um input
. Ele será type="search"
e terá o id "campo-busca"
. Na linha seguinte criamos o atributo placeholder="Busque por uma tarefa"
.
<! -- código omitido -->
<input
id="campo-busca" type="search"
placeholder="Busque por uma tarefa"
Feito isso, abrimos nossa aplicação. Repare que, no canto esquerdo da tela, encontramos a div
com o parágrafo e o input
. Eles estão simples, pois ainda não criamos os estilos. Faremos isso agora.
lista-tarefas.component.css
Clicamos no menu lateral e abrimos o arquivo lista-tarefas.component.css
. Nele, codamos todos os estilos necessários. Então, vamos descomentar da linha 1 até a 55, assim você poderá ter acesso a esses estilos também.
Não faremos um passo a passo, pois esse não é o foco do curso. Mas, caso você tenha interesse em aprender mais sobre esse tema, pode encontrar outros cursos na plataforma sobre css e responsividade.
Feito isso, fechamos o arquivo css. Ao voltar no Memorando, já temos a div
centralizada e com o estilo que definimos. Porém ainda não está funcionando.
lista-tarefas.component.html
Voltamos no VS Code. Abaixo de placeholder
, mais especificamente na linha 77, faremos uma vinculação bidirecional. Abrimos colchetes e parênteses e dentro escrevemos a diretiva ngModel
. Nela, passamos o atributo "campoBusca"
.
<! -- código omitido -->
[(ngModel)]="campoBusca"
lista-tarefas.component.ts
Feito isso, copiamos esse atributo, abrimos o arquivo lista-tarefas.component.ts
e colamos na linha 26, no fim de export class
. Definimos o tipo string inicializando vazia, string = ''
.
Embora essa tipagem seja opcional, optamos por defini-la pois fizemos isso nos demais atributos.
// código omitido
campoBusca: string = '';
lista-tarefas.component.html
Voltando ao template, criamos um keyup
atribuindo a expressão filtrarTarefasPorDescricao()
e passando como parâmetro campoBusca
.
lista-tarefas.component.ts
Agora, criaremos esse componente. Para isso, copiamos o nome desse método. Depois, no arquivo lista-tarefas.component.ts
, na linha 49, abaixo do ngOnInit()
, o colamos.
Nos parênteses, passamos como parâmetro descricao
e tipamos como string
. Em seguida, abrimos o bloco com as chaves.
//código omitido
filtrarTarefasPorDescricao(descricao: string) {
}
Na linha 27, criamos outro atributo chamado tarefasFiltradas
, que será o array resultante da busca. Ela será do tipo Tarefas[] = []
.
//código omitido
tarefasFiltradas: Tarefas[] = [];
Voltamos no método filtrarTarefasPorDescricao()
para fazer um tratamento para o campo de busca. Na linha abaixo escrevemos this.campoBusca = descricao.trim().toLowerCase()
, assim removeremos o espaço e deixaremos o termo em letra minúscula para não haver divergências quando formos fazer a comparação.
// código omitido
filtrarTarefasPorDescricao(descricao: string) {
this.campoBusca = descricao.trim().toLowerCase();
Na linha abaixo, vamos codar a lógica. Então, digitamos if(descricao)
, ou seja, se a pessoa digitou no campo de busca, vamos popular o array de tarefas filtradas, this.tarefasFiltradas = this.listaTarefas.filter()
.
Dentro dos parênteses passamos tarefas
, uma arrow function e escrevemos tarefa.descricao.ToLowerCase()
. Em seguida, passamos o método includes()
passando o this.campoBusca
.
Na linha 55, criamos o else{}
. Dentro das chaves, escrevemos this.tarefasFiltradas = this.listaTarefas
.
// código omitido
filtrarTarefasPorDescricao(descricao: string) {
this.campoBusca = descricao.trim().toLowerCase();
if (descricao) {
this.tarefasFiltradas = this.listaTarefas.filter(tarefa =>
tarefa.descricao.toLowerCase().includes(this.campoBusca));
} else {
this.tarefasFiltradas = this.listaTarefas;
}
}
Para funcionar, no trecho de código ngOnInit()
, deixamos o cursor parado no fim da linha this.listaTarefas
e apertamos as teclas "Alt + Shif + Seta para baixo". Nessa nova linha, atribuímos o array this.tarefasFiltradas
para que receba a lista de tarefas.
Na linha 48, ao invés de retornar a listaTarefas
, retornamos tarefasFiltradas
. Dessa forma:
// código omitido
ngOnInit(): Tarefa[] {
this.service.listar(this.categoria).subscribe((listaTarefas) => {
this.listaTarefas = listaTarefas;
this.tarefasFiltradas = listaTarefas;
});
return this.tarefasFiltradas;
}
Também precisamos fazer uma modificação no método listarAposCheck()
. Na linha 141, substituimos para this.tarefasFiltradas = listaTarefas
.
// código omitido
listarAposCheck() {
this.service.listar(this.categoria).subscribe((listaTarefas) => {
this.tarefasFiltradas = listaTarefas;
});
}
lista-tarefas.component.html
Por fim, no arquivo de template, faremos a mesma substituição nas linhas 80 e 83, apagando listaTarefas
e escrevendo tarefasFiltradas
.
<! -- código omitido -->
<div *ngIf="tarefasFiltradas.length > 0, else semTarefas">
<div
class="lista-tarefas card-{{ tarefa.categoria }}"
*ngFor="let tarefa of tarefasFiltradas; let i = index"
<! -- código omitido -->
Vamos testar. Acessamos o Memorando e no campo de busca escrevemos "reunião". Repare que assim que começamos as tarefas começam a ser filtradas. Deu certo!
Agora precisamos animar esse processo. É isso que faremos no próximo vídeo.
Até lá!
No vídeo anterior criamos um campo para filtrar as tarefas. Agora, tornaremos esse processo animado para que os cards apareçam e desapareçam gradualmente.
keyframes()
e offset
Para isso, abrimos o VS Code. Clicamos no menu lateral esquerdo, depois na pasta "service" e abrimos o arquivo animations.ts
.
No fim do código, criamos a nova constante export const
que se chamará filterTrigger
.
Adicionamos um sinal de igual e vamos associá-la a um novo trigger()
. Como parâmetro ele receberá 'filterAnimation'
e um array de metadados []
.
Como não queremos animar o estilo inicial e final dos cards, não utilizaremos state
nem style
e sim o transition()
.
Para animar a entrada e saída do card, nos parênteses passamos os parâmetros ':enter'
e []
.
// código omitido
export const filterTrigger = trigger('filterAnimation', [
transition(':enter', [
])
])
Na linha abaixo, passamos o style()
. Nos parênteses adicionamos chaves e dentro delas escrevemos opacity: 0, width: 0
.
Adicionamos vírgula e na próxima linha adicionamos o método animate()
. Nele, passamos como primeiro parâmetro a duração da animação '400ms'
seguido da time function ease-out
. O parâmetro seguinte será outra função style({})
.
Nas chaves passamos opacity: 1
e na próxima linha width: ''*
.
Para definir a largura o ideal seria saber a medida final do elemento. Porém, nesses casos podemos utilizar o curinga.
Sim! Além de utilizá-lo como estado também podemos passá-lo como valor para uma propriedade css.
// código omitido
export const filterTrigger = trigger('filterAnimation', [
transition(':enter', [
style({opacity: 0, width: 0}),
animate('400ms ease-out', style({
opacity:1,
width: '*'
}))
])
])
Na linha 52, após ])
, adicionamos uma vírgula. Damos espaço e na nova linha criaremos a transição de saída do elemento. Escrevemos transition()
. Dentro passamos os parâmetros ':leave'
e []
.
Em seguida, passamos a função animate()
com a mesma duração '400ms'
e a time function ease-out
. Adicionamos vírgula e a função style({opacity: 0, width:0})
. Assim, criamos a animação.
// código omitido
transition(':leave', [
animate('200ms cubic-bezier(.13,.9,.8,.1)', style({ opacity: 0, width: 0}))
])
])
lista-tarefas.components.ts
Agora, faremos as importações necessárias. Em animations
, após checkButtonTrigger
, adicionamos vírgula. Na linha abaixo escrevemos filterTrigger
. Feito isso ele também é importado na linha 7 do código.
// código omitido
import { checkButtonTrigger, filterTrigger, highlightedStateTrigger, shownStateTrigger } from '../animations';
@Component({
selector: 'app-lista-tarefas',
templateUrl: './lista-tarefas.component.html',
styleUrls: ['./lista-tarefas.component.css'],
animations: [
highlightedStateTrigger,
shownStateTrigger,
checkButtonTrigger,
filterTrigger
]
})
// código omitido
Para testar, acessamos o Memorando. Na barra de busca, escrevemos uma palavra. Notamos que a animação ainda não está funcionando. Para que isso aconteça, precismos a associação no template. Então, voltamos ao VS Code.
lista-tarefas-component.html
Na div
da linha 81 adicionamos @filterAnimation
, que é o nome do trigger.
<! -- código omitido -->
<div
@filterAnimation
class="lista-tarefas card-{{ tarefa.categoria }}"
*ngFor="let tarefa of tarefasFiltradas; let i = index"
(mouseover)="indexTarefa = i"
[@highlightedState]="indexTarefa === i ? 'highlighted' : 'default'">
Voltamos no Memorando para testar novamente. Ao digitar no campo de busca os cards vão aparecendo e desaparecendo gradualmente. Está funcionando!
animations.ts
Voltamos no arquivo animations.ts
. Será que durante os 400ms conseguimos fazer uma modificação em diferentes etapas desse tempo?
A resposta é sim! Podemos utilizar o keyframes()
para adicionar estilos intermediários na animação ao invés do style()
final.
Então, na linha 48, em animate
, apagamos o style()
e suas propriedades. No lugar, adicionamos o keyframes()
.
Como precisamos importá-lo da biblioteca, com o mouse em cima dele, clicamos em "Quick Fix" e depois em "Update import from "angular/animations".
Em keyframes()
passamos o array de estilos []
. Agora, podemos passar os estilos intermediários.
Dentro das chaves escrevemos style({opacity: 0, width:0})
. Com o cursor no fim dessa linha de código adicionamos vírgula e apertamos duas vezes as teclas "Alt + Shift + Seta para baixo". Assim, o trecho é replicado.
No segundo estilo, definimos a opacidade 0.5
e largura '*'
. No terceiro estilo opacidade 1
e largura '*'
.
// código omitido
animate('400ms ease-out', keyframes([
style({opacity:0, width:0}),
style({opacity:0.5, width:'*'}),
style({opacity:1, width:'*'})
Voltamos ao Memorando e no campo de busca, digitamos uma palavra. Conseguimos reparar uma pequena mudança.
Os keyframes()
animam vários estilos intermediários. Porém, em animações mais curtas como a nossa não ficam tão perceptíveis.
Por isso, adicionaremos outra propriedade css. No segundo style
passamos backgroundCollor: 'lightgreen'
. Copiamos esse trecho e colamos no estilo final, mudando a cor para lightblue
. Dessa forma:
// código omitido
animate('400ms ease-out', keyframes([
style({opacity:0, width:0}),
style({opacity:0.5, width:'*', backgroundCollor: 'lightgreen'}),
style({opacity:1, width:'*', backgroundCollor: 'lightblue'})
Ao testar no Memorando percebemos que quando os cards aparecem vão mudando de cor de verde para azul. Assim, animamos as etapas da animação.
Nesse momento, você pode estar se questionando se também é possível controlar o tempo em que essa etapa acontece. Sim! Podemos fazer isso utilizando o offset
.
offset
é uma propriedade que recebe um valor numérico entre 0 e 1. Assim, podemos controlar o momento exato em que a mudança da propriedade css acontece.
Na linha 49, no primeiro style()
adicionamos o offset:0
, no segundo offset: 0.8
e no último offset: 1
.
//código omitido
export const filterTrigger = trigger('filterAnimation', [
transition(':enter', [
style({opacity: 0, width: 0}),
animate('400ms ease-out', keyframes([
style({offset: 0, opacity:0, width:0}),
style({offset: 0.8, opacity:0.5, width:'*'}),
style({offset: 1, opacity:1, width:'*'})
]))
]),
transition(':leave', [
animate('200ms cubic-bezier(.13,.9,.8,.1)', style({ opacity: 0, width: 0}))
])
])
Voltamos na aplicação para testar. Ao realizar a busca, percebemos que deu certo!
Para visualizar melhor, mudamos o tempo de
animate
para2000ms
. Ao fazer isso, percebemos todos os detalhes da animação e a mudança da cor verde para a azul.
Os keyframes()
são recursos muito importantes para criarmos animações no Angular. A partir deles, podemos inserir estilos intermediários nas animações, além de controlar o tempo em que as mudanças de propriedades css acontecerão.
No próximo vídeo conheceremos mais uma ferramenta que irá adicionar mais personalização no seu projeto.
Até lá!
O curso Angular: aprimore suas técnicas de animação e crie interfaces ainda mais atraentes possui 102 minutos de vídeos, em um total de 42 atividades. Gostou? Conheça nossos outros cursos de Angular em Front-end, ou leia nossos artigos de Front-end.
Matricule-se e comece a estudar com a gente hoje! Conheça outros tópicos abordados durante o curso:
Impulsione a sua carreira com os melhores cursos e faça parte da maior comunidade tech.
1 ano de Alura
Assine o PLUS e garanta:
Formações com mais de 1500 cursos atualizados e novos lançamentos semanais, em Programação, Inteligência Artificial, Front-end, UX & Design, Data Science, Mobile, DevOps e Inovação & Gestão.
A cada curso ou formação concluído, um novo certificado para turbinar seu currículo e LinkedIn.
No Discord, você tem acesso a eventos exclusivos, grupos de estudos e mentorias com especialistas de diferentes áreas.
Faça parte da maior comunidade Dev do país e crie conexões com mais de 120 mil pessoas no Discord.
Acesso ilimitado ao catálogo de Imersões da Alura para praticar conhecimentos em diferentes áreas.
Explore um universo de possibilidades na palma da sua mão. Baixe as aulas para assistir offline, onde e quando quiser.
Acelere o seu aprendizado com a IA da Alura e prepare-se para o mercado internacional.
1 ano de Alura
Todos os benefícios do PLUS e mais vantagens exclusivas:
Luri é nossa inteligência artificial que tira dúvidas, dá exemplos práticos, corrige exercícios e ajuda a mergulhar ainda mais durante as aulas. Você pode conversar com a Luri até 100 mensagens por semana.
Aprenda um novo idioma e expanda seus horizontes profissionais. Cursos de Inglês, Espanhol e Inglês para Devs, 100% focado em tecnologia.
Transforme a sua jornada com benefícios exclusivos e evolua ainda mais na sua carreira.
1 ano de Alura
Todos os benefícios do PRO e mais vantagens exclusivas:
Mensagens ilimitadas para estudar com a Luri, a IA da Alura, disponível 24hs para tirar suas dúvidas, dar exemplos práticos, corrigir exercícios e impulsionar seus estudos.
Envie imagens para a Luri e ela te ajuda a solucionar problemas, identificar erros, esclarecer gráficos, analisar design e muito mais.
Escolha os ebooks da Casa do Código, a editora da Alura, que apoiarão a sua jornada de aprendizado para sempre.