O React Native é uma estrutura de desenvolvimento de aplicativos móveis multiplataforma com uma curva de aprendizado suave e muitos componentes integrados. Por ter uma comunidade de desenvolvedores muito ativa, também existem centenas de bibliotecas de componentes de terceiros de código aberto disponíveis para ele, permitindo que você crie aplicativos para Android e iOS com foco apenas na lógica principal dos aplicativos. No entanto, ser capaz de criar rapidamente seus próprios componentes personalizados e reutilizáveis do zero ainda é uma habilidade importante para se ter.
Neste tutorial, mostrarei como criar um componente React Native Calendar personalizado usando apenas o ES6 e alguns componentes básicos oferecidos pelo próprio framework.
1. Criando um novo projeto
Para evitar a instalação do React Native CLI e todas as suas dependências no seu computador, por enquanto, sugiro que você use o Expo’s Snack, um IDE gratuito baseado em navegador para desenvolvimento de aplicativos React Native. Se você ainda não tem uma conta Expo, crie uma agora.
Depois de fazer login na Expo, crie um novo projeto Snack alternando para o Lanches guia e clicando no Crie um lanche link.
O IDE levará apenas alguns segundos para criar seu projeto e preparar um dispositivo de visualização para ele. Depois de pronto, deve ficar assim:
Para manter as coisas simples, todo o nosso código irá para dentro do App.js Arquivo. Antes de continuar, certifique-se de excluir todo o código de amostra presente no App.js, incluindo as importações.
2. Criando um novo componente
Para poder usar a estrutura React e os componentes React Native em seu projeto, adicione o seguinte import
declarações no início do App.js Arquivo:
import * as React from 'react'; import * as RN from 'react-native';
Você cria um componente React personalizado criando uma classe que estende o Component
classe. Dentro da classe, você deve adicionar um método chamado render()
, que retorna o código JSX. O código a seguir cria um componente chamado MyCalendar
:
import * as React from 'react'; import * as RN from 'react-native'; class MyCalendar extends React.Component { render() { return (); } } // Export for now to get rid of error and see preview: export default MyCalendar
No render()
método, no momento estamos retornando um vazio View
componente. Ele servirá como um contêiner para todos os outros componentes do nosso calendário.
3. Criando Constantes
O componente calendar precisa de dois arrays de strings: um para armazenar os nomes dos meses e outro para armazenar os nomes dos dias da semana. Inclua o seguinte código no MyCalendar
componente de classe, pouco antes de ser render()
método.
months = ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"]; weekDays = [ "Sun","Mon","Tue","Wed","Thu","Fri","Sat" ];
Em seguida, precisaremos de um array que armazene o número de dias que cada mês tem. Para fevereiro, deixe o número ser 28. Vamos escrever o código para lidar com anos bissextos mais tarde. Adicione o seguinte logo abaixo do months
e weekDays
variedade.
nDays = [31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31];
4. Inicializar um estado
Para tornar nosso componente de calendário interativo, devemos associar um estado a ele. Por enquanto, vamos armazenar nada além de um Date
objeto dentro do estado, inicializado para a data de hoje. Para fazer isso, adicione o seguinte código ao MyCalendar
classe, logo abaixo nDays
variedade.
state = { activeDate: new Date() }
O estado, é claro, é mutável. Quando um usuário clicar em uma data diferente no calendário, mudaremos o estado para usar a nova data.
5. Gerando uma Matriz
Uma matriz com sete linhas e sete colunas é grande o suficiente para representar qualquer mês do ano. Usaremos a primeira linha apenas como cabeçalho, armazenando os nomes dos dias da semana nela. Para criar e inicializar esta matriz, inclua o seguinte generateMatrix()
método entre state
e render()
dentro MyCalendar
classe.
generateMatrix() { var matrix = []; // The following code creates the header matrix[0] = this.weekDays; // The remaining code will go here }
Antes de começarmos a adicionar dias à matriz, precisamos determinar o dia em que o mês atual começa. Para fazer isso, primeiro obtenha o ano e o mês da Date
objeto armazenado no estado. Em seguida, crie um novo Date
objeto usando esses valores e 1
, o primeiro dia do mês. Ao chamar o getDay()
método deste novo objeto, você obtém o primeiro dia do mês. Adicione o seguinte código ao generateMatrix
função:
var year = this.state.activeDate.getFullYear(); var month = this.state.activeDate.getMonth(); var firstDay = new Date(year, month, 1).getDay();
Não podemos usar diretamente o nDays
array para determinar o número de dias que o mês atual tem. Se o mês for fevereiro, precisamos adicionar manualmente um dia extra ao lidar com anos bissextos. O bloco de código a seguir mostra como fazer isso; por favor adicione o código ao generateMatrix
função:
var maxDays = this.nDays[month]; if (month == 1) { // February if ((year % 4 == 0 && year % 100 != 0) || year % 400 == 0) { maxDays += 1; } }
Neste ponto, temos todos os dados necessários para preencher o restante da matriz. O código a seguir mostra como fazer isso usando um contador, dois for
laços, e dois simples if
condições – adicione-o a generateMatrix
para completar o corpo da função:
var counter = 1; for (var row = 1; row < 7; row++) { matrix[row] = []; for (var col = 0; col < 7; col++) { matrix[row][col] = -1; if (row == 1 && col >= firstDay) { // Fill in rows only after the first day of the month matrix[row][col] = counter++; } else if (row > 1 && counter <= maxDays) { // Fill in rows only if the counter's not greater than // the number of days in the month matrix[row][col] = counter++; } } } return matrix;
Observe que você precisa inicializar explicitamente cada elemento da matriz 7 x 7. Se você esquecer de fazer isso, a primeira ou a última linha pode ter menos de sete elementos. Isso pode causar problemas durante o uso do map()
método para percorrer a matriz.
6. Renderizando um mês
De volta para dentro do render()
método do MyCalendar
componente de classe, agora devemos renderizar a matriz que criamos. Então chame o generateMatrix()
método dentro dele, logo acima do return()
declaração.
var matrix = this.generateMatrix();
Em seguida, vamos exibir o ano e o nome do mês atual adicionando um Text
componente para o atualmente vazio View
componente. Opcionalmente, você pode usar o style
prop para adicionar estilos ao texto. O seguinte código JSX deve ir dentro do vazio
elemento no return
declaração de MyCalendar
classe render()
método.
{this.months[this.state.activeDate.getMonth()]} {this.state.activeDate.getFullYear()}
Na seção de visualização do aplicativo, o calendário renderizado agora deve mostrar o mês e o ano atuais.
Estaremos usando um flexbox para renderizar o conteúdo de cada linha da matriz. Mais precisamente, para cada linha, usaremos um View
componente com sua flex
e flexDirection
parâmetros definidos para 1
e row
respectivamente. Além disso, para garantir que todos os itens da linha tenham a mesma largura, definiremos o flexbox justifyContent
parâmetro para space-around
.
Além disso, para exibir os elementos individuais da matriz, usaremos Text
componentes novamente. Ao modificar o backgroundColor
propriedade do Text
componentes responsáveis pelos elementos da primeira linha, podemos destacar o cabeçalho. Da mesma forma, se você quiser destacar os domingos, use o color
propriedade do Text
componentes responsáveis pelos elementos da primeira coluna.
Nosso calendário deve ser capaz de destacar a data de hoje ou uma data selecionada pelo usuário. Portanto, vamos associar um fontWeight
propriedade com cada Text
componente. Vamos configurá-lo para bold
sempre que seu conteúdo coincidir com a data em nosso estado activeDate
variável.
O código a seguir mostra como usar o map()
método como alternativa for
loops enquanto gera uma hierarquia de componentes para o conteúdo da matriz. Adicione o código no render
método de MyCalendar
class, logo antes da instrução return:
var rows = []; rows = matrix.map((row, rowIndex) => { var rowItems = row.map((item, colIndex) => { return (this._onPress(item)}> {item != -1 ? item : ''} ); }); return ({rowItems} ); });
Para realmente renderizar a matriz, agora você deve incluir rows
no JSX retornado pelo render()
método. Então adicione o seguinte código abaixo do
componente responsável por exibir o ano e o nome do mês:
{ rows }
Você deve ter notado que associamos um onPress
manipulador de eventos com cada
componente exibindo uma data. Vamos usá-lo para atualizar o activeDate
variável sempre que os usuários clicam em uma data. Claro, lembre-se de ignorar
componentes vazios ou responsáveis pelos nomes dos dias da semana.
Assim, adicione o seguinte método em qualquer lugar no corpo do seu MyCalendar
classe:
_onPress = (item) => { this.setState(() => { if (!item.match && item != -1) { this.state.activeDate.setDate(item); return this.state; } }); };
7. Mudando os meses
Nosso componente de calendário terá dois botões rotulados Próximo e Anterior. Esses botões, quando pressionados, devem permitir que os usuários passem de um mês para outro. Como você deve ter adivinhado, dentro de seus manipuladores de eventos, tudo o que precisamos fazer é obter o activeDate
objeto e aumentar ou diminuir seu mês por 1
.
Assim, adicione o seguinte código no final do JSX retornado pelo render()
método de MyCalendar
(mantenha-o dentro de
):
this.changeMonth(-1)}/> this.changeMonth(+1)}/>
A seguir, crie o changeMonth()
método em qualquer lugar no corpo do MyCalendar
classe. Dentro dele, você deve primeiro chamar o setState()
método e, em seguida, chamar o setMonth()
método para atualizar o activeDate
objeto.
changeMonth = (n) => { this.setState(() => { this.state.activeDate.setMonth( this.state.activeDate.getMonth() + n ) return this.state; }); }
8. Usando o componente
Se você executar seu projeto agora, deverá ver um calendário parecido com este:
Como você pode ver, nosso componente de calendário React Native está pronto.
Se você quiser usar o componente de calendário dentro de um componente pai, digamos App
basta adicioná-lo ao render()
método do seu App
classe assim:
export default class App extends React.Component { render() { return; } } export default App;
Sinta-se à vontade para pegar o código completo para o calendário React Native do snack.
Conclusão
Agora você sabe como criar e usar um componente de calendário React Native personalizado sem depender de nenhum pacote de terceiros. O componente que criamos hoje é interativo, extensível e pode ser usado em qualquer aplicativo com alterações mínimas. Sinta-se à vontade para adicionar mais estilos e funcionalidades a ele.
Para saber mais sobre os componentes do React Native, consulte a documentação oficial. E confira alguns de nossos outros posts sobre o desenvolvimento de aplicativos React Native!