O React Native Reanimated é uma biblioteca poderosa e intuitiva que permite criar animações e interações suaves para aplicativos iOS e Android. Embora existam muitas bibliotecas de animação para React Native , incluindo a API animada integrada, examinaremos o Reanimado em profundidade para descobrir por que ele é a escolha superior em minha opinião.

Vamos começar!

Execução do código reanimado

O ponto forte do Reanimated reside na capacidade de melhorar o desempenho e a capacidade de resposta dos aplicativos React Native, dando às animações um acabamento suave que só pode ser obtido por meio da execução instantânea do código.

Para entender como Reanimado funciona, primeiro precisamos entender como React Native executa código.

React Native threads

O React Native tem três threads separados que permitem a execução de código JavaScript demorado sem afetar a capacidade de resposta da IU. O thread de IU é o thread nativo. Ele executa Swift ou Objective C para iOS e Java ou Kotlin para Android. A IU do aplicativo é manipulada exclusivamente no encadeamento de IU.

O encadeamento JavaScript é responsável pela lógica de renderização, como quais visualizações são exibidas e de que maneira. Ele executa JavaScript separadamente por meio de um mecanismo de JavaScript. Finalmente, a ponte permite a comunicação assíncrona entre a IU e o encadeamento JavaScript. Para evitar a redução do desempenho, ele deve ser usado apenas para transferir pequenas quantidades de dados.

Essas interações começam no thread JavaScript e devem ser refletidas no thread principal, podendo causar problemas ao lidar com eventos orientados interações.

Reanimada vs. API animada

Como a comunicação entre a IU e o thread de JavaScript é assíncrona, a API animada atrasa as atualizações em pelo menos um quadro, que dura aproximadamente 16,67 ms. O atraso pode durar ainda mais quando o thread JavaScript também está executando outros processos, como a execução de diffing React e processamento de solicitações de rede.

Conhecidos como perda de quadro, esses atrasos podem prejudicar sua UX e fazer as animações parecerem desajeitadas. Reanimated resolve esse problema removendo animação e lógica de manipulação de eventos do thread JavaScript e executando-o diretamente no thread de IU.

Além disso, Reanimated define worklets, que são pequenos pedaços de código JavaScript que podem ser movidos para um máquina virtual JavaScript separada e executada de forma síncrona no thread de interface do usuário. Worklets fazem com que as animações sejam executadas assim que são acionadas, criando uma UX mais satisfatória.

Valores compartilhados

Valores compartilhados, que são semelhantes aos dados com estado em um aplicativo React regular, armazenam dados dinâmicos que você pode animar no Reanimated. No entanto, em vez de compartilhar dados entre componentes como você faria com dados stateful, os valores compartilhados compartilham dados entre o thread da interface do usuário e o thread JavaScript.

Quando os dados dentro desses valores compartilhados são atualizados, a biblioteca Reanimated registra o altera e executa uma animação, semelhante a como o React renderiza novamente um componente quando o estado é atualizado.

Criar um valor compartilhado é muito semelhante a criar um pedaço de estado com o gancho useState; simplesmente use o gancho useSharedValue.

Digamos que queremos criar uma caixa que muda de altura quando um botão é pressionado. Definiremos uma variável boxHeight como um valor compartilhado para que possamos compartilhá-la entre o thread de IU e o thread de JavaScript durante a animação:

const boxHeight=useSharedValue (150);

No exemplo acima, criamos um valor compartilhado chamado boxHeight e definimos seu valor inicial como 150. Para acessar o valor boxHeight posteriormente em seu código, você deve fazer referência a boxHeight.value em vez de apenas boxHeight.

O gancho useSharedValue retorna um objeto e o valor inicial é salvo na propriedade.value do objeto. Para atualizar o valor compartilhado, o que normalmente é feito após alguma entrada predeterminada do usuário, simplesmente atualize a propriedade.value dentro de uma função. Reanimado registrará a alteração:

function toggleHeight () {boxHeight.value===450? boxHeight.value=150: boxHeight.value=450; }

Agora, vamos explorar como podemos usar esses valores compartilhados nos worklets Reanimados.

Worklets reanimados

Os worklets são funções simples que nos permitem executar código JavaScript de forma síncrona na IU fio. Normalmente, os worklets retornam uma propriedade de estilo do componente React. Um worklet é acionado por qualquer mudança no valor compartilhado ao qual faz referência.

Para declarar um worklet, podemos usar a diretiva de worklet no início da definição da função. No bloco de código abaixo, estamos declarando a função boxAnimation usando a diretiva worklet, indicando que a função é um worklet. Estamos retornando uma propriedade de altura atualizada usando o valor compartilhado boxHeight:

const boxAnimation=()=> {‘worklet’; return {height: withTiming (boxHeight.value, {duration: 750})}; };

Mais comumente, podemos usar o gancho useAnimatedStyle para declarar um worklet, o que nos permite passar uma função de retorno de chamada como um argumento. Agora, a função de retorno de chamada será tratada como um worklet:

const boxAnimation=useAnimatedStyle (()=> {return {height: withTiming (boxHeight.value, {duration: 750})};});

Dos dois métodos para declarar um worklet, recomendo usar o gancho useAnimatedStyle. Para usar o método de diretiva de worklet, devemos adicionar uma função secundária que chama o método runOnUI e passa a função boxAnimation como um parâmetro. Por outro lado, o gancho useAnimatedStyle abstrai essa função secundária, executando automaticamente o retorno de chamada passado para o gancho useAnimatedStyle no thread de IU.

Em ambos os exemplos, sempre que o valor de boxHeight.value é atualizado , o worklet irá disparar uma animação mostrando a caixa expandindo ou contraindo verticalmente.

Métodos utilitários

withTiming

Em nossos exemplos acima, usamos o utilitário withTiming , que nos permite criar uma animação simples que faz a transição gradualmente de seu ponto inicial ao ponto final, dando-nos a capacidade de controlar a duração e a aceleração da transição.

withTiming leva dois parâmetros. O primeiro, que é obrigatório, é o valor compartilhado que será atualizado. No nosso caso, é boxHeight.

O segundo parâmetro opcional é um objeto com duas propriedades. a duração controla a duração da animação e a atenuação controla a aceleração e desaceleração da animação. Os valores padrão são 300 ms para a duração e atenuação do quadrante de entrada e saída para atenuação.

withSpring

O método withSpring é semelhante a withTiming, no entanto, cria um efeito de animação diferente no qual o elemento passa seu ponto final antes de se estabelecer em sua posição final.

withSpring tem apenas um parâmetro obrigatório, que é o valor compartilhado a ser atualizado. Ele também tem seis parâmetros opcionais listados abaixo. No entanto, os valores padrão serão suficientes para a maioria dos casos de uso:

amortecimento: 10 massa: 1 rigidez: 100 overshootClamping: false restDisplacementThreshold: 0,01 restSpeedThreshold: 2

useAnimatedStyle Hook

Em nosso exemplo anterior , o gancho useAnimatedStyle cria um worklet que vincula o valor compartilhado boxHeight a um componente que usa boxHeight.value em suas propriedades de estilo. Ao fornecer as propriedades dos componentes do React, devemos usar a versão do componente que podemos animar.

Por exemplo, em vez de usar uma tag , devemos usar uma tag . Todos os filhos de estarão sujeitos à animação aplicada ao pai.

Ao definir estilos para o componente, certifique-se de passar os estilos como uma matriz. O primeiro elemento é um objeto que contém todos os estilos que você usaria normalmente, incluindo a altura. O segundo elemento é o worklet que foi definido anteriormente.

Agora, vamos combinar todas as ferramentas Reanimadas que abordamos para criar uma caixa cinza simples que se expande e contrai quando pressionamos um botão:

//instruções de importação onde adicionamos a funcionalidade para usar ganchos e métodos de Reanimated import React from’react’; import {View, Button} from’react-native’; import Animated, {useAnimatedStyle, useSharedValue, withTiming} de’react-native-reanimated’; função padrão de exportação ExpandingTextBox () {//criando valor compartilhado via useSharedValue const boxHeight=useSharedValue (150);//criando worklet por meio de useAnimatedStyle e incorporando o método withTiming const boxAnimation=useAnimatedStyle (()=> {return {height: withTiming (boxHeight.value, {duration: 750})}});//função que alterna o valor de boxHeight para que possa expandir e contrair a função toggleHeight () {boxHeight.value===450? boxHeight.value=150: boxHeight.value=450; };//estilos a serem usados ​​em nossa caixa cinza const styles={box: {width: 400, height: 150, backgroundColor:’gray’, borderRadius: 15, margin: 100, padding: 20, display:’flex’}}; return ( {/* componente Animated.View, com os estilos típicos contidos em styles.box, e o worklet”boxHeight”que atualiza a propriedade height ao lado dele */} {/* botão que dispara a função toggleHeight () sempre que é pressionado */} )};

A saída do código acima será semelhante à animação abaixo:

Vamos adicionar outro valor compartilhado e worklet para controlar a opacidade do texto. Também adicionaremos mais detalhes ao estilo.

Agora, temos uma lista suspensa de texto animado totalmente funcional!

Conclusão

Evento de descarregamentos reanimados-interações orientadas a partir do thread JavaScript e, em vez disso, as executa de forma síncrona no thread de IU. Com o Reanimated, você não precisa mais se preocupar em descartar quadros ou limitar a carga de trabalho do thread de JavaScript.

Para obter mais informações sobre os métodos, ganchos e animações do Reanimated, recomendo verificar o Documentação reanimada .