Buscar

aula6 (1)

Prévia do material em texto

6ºAula
Implementação I
Objetivos de aprendizagem
Ao término desta aula, vocês serão capazes de:
• criar uma aplicação que tem várias telas que podem ser navegadas através de abas;
• criar uma aplicação que os dados são armazenados em um banco de dados local.
Olá, 
Na aula anterior foi demonstrada a utilização dos estados 
e como acontece a renderização quando um estado é alterado 
durante a execução, também foi exemplificado através de uma 
aplicação prática como criar uma lista com nomes aleatórios 
obtidos de uma API.
Nesta aula será desenvolvida uma aplicação que possui 
várias telas que podem ser navegadas e também permite o 
armazenamento de informações em um banco de dados local.
Leia atentamente esta aula e se tiver alguma dúvida, use os 
recursos que estão na sua área do aluno.
Bons estudos!
32Programação para Dispositivos Móveis
Seções de estudo
 
1– Navegação entre abas
2– Armazenamento Local
1- Navegação entre abas
Em muitas aplicações é necessário a exibição de mais 
de uma tela com controle de navegação. Um dos templates 
que pode ser escolhido quando é feita a instalação do Expo 
permite a navegação com abas, Figura 1, ele baixa com o 
template todas as dependências para utilizar a navegação. 
Figura 1 – Escolha do template. Fonte: Acervo pessoal.
Na Figura 2 é possível ver a interface que é criada quando 
esse template é escolhido. A aplicação possui dois botões na 
base da tela que intercalam entre as telas, tanto o conteúdo 
quanto o título é alterado quando os botões são pressionados.
Figura 2 – Navegação com abas. Fonte: Acervo pessoal.
A utilização desse template faz com que o processo de 
desenvolvimento seja encurtado, porém abaixo será explicado 
como criar essa navegação em uma aplicação em branco. 
Para isso crie através no comando expo init nome-do-
projeto e selecione a opção blank. O primeiro passo após 
isso é instalar o pacote que vai garantir o suporte a navegação 
por abas.
npm install @react-navigation/native
Em seguida, algumas dependências devem ser instaladas 
via Expo, que são responsáveis pela manipulação da 
navegação.
expo install react-native-gesture-
handler react-native-reanimated react-
native-screens react-native-safe-
area-context @react-native-community/
masked-view
E para fi nalizar, deve ser adicionado o último pacote, que 
é responsável pelos botões das abas.
npm install @react-navigation/
bottom-tabs
A ideia do nosso projeto é criar uma tela que exibirá 
uma lista com nomes (seguindo o mesmo princípio da aula 
anterior) e uma outra tela que terá um formulário, que será 
preenchido para incluir os nomes na lista.
 Portanto, se faz necessária a criação de 2 arquivos 
JavaScript, um para cada tela que será exibida. Eles terão a 
mesma base do arquivo principal App.js, chamaremos de 
AppList.js e AppForm.js.
 AppList.js
import { StatusBar } from ‘expo-
status-bar’;
import React from ‘react’;
import { StyleSheet, Text, View } 
from ‘react-native’;
export default function AppList() {
 return (
 <View style={styles.container}>
 <Text>List!</Text>
 <StatusBar style=”light” />
 </View>
 );
}
const styles = StyleSheet.create({
 container: {
 fl ex: 1,
 backgroundColor: ‘#D93600’,
 alignItems: ‘center’,
 justifyContent: ‘center’,
 },
});
 AppForm.js
33
import { StatusBar } from ‘expo-
status-bar’;
import React from ‘react’;
import { StyleSheet, Text, View } 
from ‘react-native’;
 
export default function AppForm() {
 return (
 <View style={styles.container}>
 <Text>Form!</Text>
 <StatusBar style=”light” />
 </View>
 );
}
 
const styles = StyleSheet.create({
 container: {
 flex: 1,
 backgroundColor: ‘#D93600’,
 alignItems: ‘center’,
 justifyContent: ‘center’,
 },
});
Para organizar melhor os códigos, esses dois arquivos 
foram criados dentro da pasta screen no projeto. Após as telas 
já estarem criadas, precisamos criar o arquivo que irá gerenciar 
a navegação entre as telas, e que também exibirá os botões 
para que a navegação seja possível. 
Criaremos então o arquivo AppTab.js, que importará o 
módulo de navegação e dos botões, e também as telas que 
foram criadas. Dentro do return é criado o container da 
navegação que contém as telas que serão navegadas.
Dentro do navigator são definidas as propriedades, tais 
como estilo dentro da tabBarOptions. Além disso, o nome 
que será exibido nos botões da navegação podem ser alterados 
modificando a opção tabBarLabel na criação da tela.
import {NavigationContainer} from ‘@
react-navigation/native’;
import {createBottomTabNavigator} 
from ‘@react-navigation/bottom-tabs’;
import React from ‘react’;
 
import AppList from ‘./AppList’;
import AppForm from ‘./AppForm’;
 
const {Navigator, Screen} = 
createBottomTabNavigator();
 
 
export default function AppTab(){
 return (
 <NavigationContainer>
 <Navigator
 tabBarOptions={{
 style: {
 elevation: 0,
 shadowOpacity: 
0,
 height: 64,
 },
 tabStyle: {
 flexDirection: 
‘row’,
 alignItems: 
‘center’,
 justifyContent: ‘center’
 },
 labelStyle: {
 fontSize: 13,
 marginLeft: 16
 },
 inactiveBackgroundColor: 
‘#fafafc’,
 activeBackgroundColor: 
‘#ebebf5’,
 inactiveTintColor: 
‘#c1bccc’,
 activeTintColor: 
‘#32264d’
 }}
 >
 <Screen name=”AppList” 
component={AppList} options={{ 
tabBarLabel: “Nomes” }} />
 <Screen name=”AppForm” 
component={AppForm} options={{ 
tabBarLabel: “Adicionar” }} />
 </Navigator>
 </NavigationContainer>
 );
}
Com as telas desenvolvidas e a navegação configurada e 
definida basta fazer a chamada a AppTab.js dentro do arquivo 
principal App.js. 
import { StatusBar } from ‘expo-
status-bar’;
import React from ‘react’;
import AppTab from ‘./screen/AppTab’;
export default function App() {
 return (
 <>
 <AppTab />
 <StatusBar style=”light” />
 </>
 );
}
Nesse momento, temos basicamente a mesma estrutura 
e funcionamento que o template que já vem com a navegação 
do Expo. Já é possível percorrer entre as telas.
34Programação para Dispositivos Móveis
2- Armazenamento Local
Quando uma aplicação é criada é necessário que as 
manipulações sejam de alguma maneira armazenadas, para 
que em uma próxima utilização seja possível continuar com o 
mesmo conteúdo que vinha sendo trabalhado.
Nesta seção será apresentada uma maneira de utilizar 
o armazenamento local através da biblioteca Expo Async 
Storage. O primeiro passo para utilizar ela é instalar o seu 
pacote na pasta do projeto.
expo install @react-native-community/
async-storage
Essa biblioteca trabalha com o armazenamento de 
dados locais baseado em chave-valor. Um objeto JSON é 
criado e convertido para texto (JSON.stringify) que pode 
ser armazenado e depois pode ser recuperado e convertido 
novamente para JSON (JSON.parse).
Para começar a armazenar os valores precisamos criar o 
formulário em que os dados serão inseridos e o botão para 
armazená-los.
A tela AppForm.js vai ser alterada para receber esse 
formulário, um elemento novo que será introduzido agora é o 
TouchableOpacity, ele funciona como um botão que pode 
ser estilizado.
Além disso, dois estados foram criados para o nome e 
sobrenome, e funções que armazenam o conteúdo no estado 
sempre que o texto inserido nos TextInput foram alterados 
e uma função que é chamada sempre que o botão de salvar é 
chamado.
Quando o botão salvar é pressionado, ele vai exibir 
no console as informações que posteriormente serão 
armazenadas no banco de dados local, e também após essa 
exibição com console.log uma chamada a outra tela é feitaatravés da função navigate do objeto navigation que recebe 
como parâmetro o nome da tela que deve ser exibido.
 AppForm.js
import React, {useState} from 
‘react’;
import { StatusBar } from ‘expo-
status-bar’;
import { StyleSheet, Text, View, 
TextInput, TouchableOpacity } from 
‘react-native’;
export default function AppForm({ 
navigation }) {
 //Estados para o nome e sobrenome
 const [nome, setNome] = useState(‘’); 
 const [sobrenome, setSobrenome] = 
useState(‘’);
 
 //Funções chamadas sempre que o 
TextInput for alterado
 function handleNomeChange(nome){ 
setNome(nome); } 
 function 
handleSobrenomeChange(sobrenome){ 
setSobrenome(sobrenome); }
 function handleButtonPress(){ 
 console.log({id: new Date().
getTime(), nome, sobrenome});
 //A chamada a navigation muda 
a tela sempre que o botão salvar é 
pressionado
 navigation.navigate(“AppList”);
 }
 return (
 <View style={styles.container}>
 <Text style={styles.
title}>Adicionar Pessoa</Text>
 <View style={styles.
inputContainer}> 
 <TextInput 
 style={styles.input} 
 onChangeText={handleNomeChange} 
 placeholder=”Nome”
 clearButtonMode=”always” /> 
 <TextInput 
 style={styles.input} 
 
onChangeText={handleSobrenomeChange} 
 placeholder=”Sobrenome” 
 clearButtonMode=”always” /> 
 <TouchableOpacity style={styles.
button} onPress={handleButtonPress}> 
 <Text style={styles.
buttonText}>Salvar</Text> 
 </TouchableOpacity> 
 </View>
 <StatusBar style=”light” />
 </View>
 );
}
const styles = StyleSheet.create({
 container: {
 fl ex: 1,
 backgroundColor: ‘#036FFC’,
 alignItems: ‘center’,
 },
 title: {
 color: ‘#fff’,
 fontSize: 20,
 fontWeight: ‘bold’,
 marginTop: 50,
 },
 inputContainer: {
 fl ex: 1,
 marginTop: 30,
 width: ‘90%’,
 padding: 20,
 borderTopLeftRadius: 10,
 borderTopRightRadius: 10,
 alignItems: ‘stretch’,
35
 backgroundColor: ‘#fff’
 },
 input: {
 marginTop: 10,
 height: 60,
 backgroundColor: ‘#fff’,
 borderRadius: 10,
 paddingHorizontal: 24,
 fontSize: 16,
 alignItems: ‘stretch’
 },
 button: {
 marginTop: 10,
 height: 60,
 backgroundColor: ‘#036FFC’,
 borderRadius: 10,
 paddingHorizontal: 24,
 fontSize: 16,
 alignItems: ‘center’,
 justifyContent: ‘center’,
 elevation: 20,
 shadowOpacity: 20,
 shadowColor: ‘#ccc’,
 },
 buttonText: {
 color: ‘#fff’,
 fontWeight: ‘bold’,
 }
});
Figura 2 – AppForm.js. Fonte: Acervo pessoal.
Para então salvar no arquivo precisamos alterar a função 
handleButtonPress que só imprime os valores no console
Primeiro deve-se importar a biblioteca do Expo Async 
Storage para o objeto AsyncStorage.
import AsyncStorage from ‘@react-
native-community/async-storage’;
Em seguida, na função handleButtonPress, uma 
variável item é criada contendo as informações que foram 
inseridas no formulário. Um array é então preenchido com 
os nomes que já estão salvos, então o novo item é incluido 
(push) no array, e todo array é salvo novamente.
As funções do objeto AsyncStorage para salvar e 
recuperar os itens são setItem e getItem respectivamente.
async function handleButtonPress(){ 
 //Cria o objeto com os dados do 
formulario
 const listItem = {id: 
new Date().getTime(), nome:nome, 
sobrenome:sobrenome};
 //Criar um array vazio;
 let savedItems = [];
 //Recupera os nomes que já estão 
no banco de dados
 const response = await AsyncStorage.
getItem(‘nomes’);
 
 //Armazena os nomes do banco na 
variavel savedItems
 if(response) savedItems = JSON.
parse(response);
 //Inclui o novo nome
 savedItems.push(listItem);
 
 //Salva no banco de dados
 await AsyncStorage.setItem(‘nomes’, 
JSON.stringify(savedItems));
 //A chamada a navigation muda 
a tela sempre que o botão salvar é 
pressionado
 navigation.navigate(“AppList”, 
listItem);
 }
Nesse ponto os nomes já estão sendo inseridos no 
banco de dados, precisamos então criar a listagem dos nomes 
no arquivo AppList.js, mas antes é importante criar um 
componente que irá conter a estrutura de exibição do nome, 
colocaremos também um botão para que os nomes também 
possam ser excluídos.
O arquivo AppItem.js foi criado então na pasta 
components. Para deixar o componente mais agradável 
visualmente utilizaremos um módulo do Expo que permite 
utilizar icones nos botões, para isso basta importar o módulo 
nativo vector-icons.
import { Feather as Icon } from ‘@
expo/vector-icons’
O icone será utilizado dentro do TouchableOpacity, 
as propriedades do icone que utilizaremos serão name, 
color e size, o primeiro é o nome do icone que será exibido, 
36Programação para Dispositivos Móveis
o segundo é a cor do icone e o terceiro é o tamanho. No 
exemplo abaixo o símbolo é uma lixeira que terá cor branca 
e tamanho 18.
<Icon name=”trash” color=”white” 
size={18} />
Voltando para o componente que utilizará as propriedades 
para receber nome e sobrenome do item que será construído. 
AppItem.js
import React from ‘react’;
import { StyleSheet, Text, View, 
TouchableOpacity } from ‘react-native’;
import { Feather as Icon } from ‘@
expo/vector-icons’
export default function AppItem(props) 
{
 return (
 <View style={styles.container}>
 <Text style={styles.
textItem}>{props.nome + “ “ + props.
sobrenome}</Text>
 <View style={styles.
buttonsContainer}>
 <TouchableOpacity 
style={styles.deleteButton} >
 <Icon name=”trash” 
color=”white” size={18} />
 </TouchableOpacity>
 </View>
 </View>
 );
}
const styles = StyleSheet.create({
 container: {
 backgroundColor: ‘#fff’,
 marginTop: 20,
 width: ‘100%’
 },
 buttonsContainer: {
 fl exDirection: ‘row-reverse’,
 alignItems: ‘fl ex-end’,
 borderBottomWidth: 1,
 borderBottomColor: ‘#CCC’,
 paddingBottom: 10,
 marginTop: 10,
 },
 editButton: {
 marginLeft: 10,
 height: 40,
 backgroundColor: ‘blue’,
 borderRadius: 10,
 padding: 10,
 fontSize: 12,
 elevation: 10,
 shadowOpacity: 10,
 shadowColor: ‘#ccc’,
 alignItems: ‘center’
 },
 deleteButton: {
 marginLeft: 10,
 height: 40,
 width: 40,
 backgroundColor: ‘red’,
 borderRadius: 10,
 padding: 10,
 fontSize: 12,
 elevation: 10,
 shadowOpacity: 10,
 shadowColor: ‘#ccc’,
 alignItems: ‘center’
 },
 textItem: {
 fontSize: 20,
 }
});
Figura 3 – AppItem.js. Fonte: Acervo pessoal.
Com o componente devidamente criado basta mapear 
o conteúdo do banco de dados dentro do AppList.js para 
exibir todos os nomes que já estão no banco de dados. Uma 
alteração deve ser feita na construção da função AppList, que 
deve os parâmetros route e navigation, o primeiro contém 
os parâmetros de navegação que foram passados até chegar 
nessa tela, enquanto o navigation pode ser utilizado quando 
é necessário fazer a navegação para outra tela, este último 
deverá ser passado como uma propriedade para o item.
export default function AppList({ route, navigation }) {
Outra função importante que tem que ser apresentada 
é a função useEffect, que é disparada toda a vez que uma 
variável determinada é alterada. Essa função vai ser usada para 
preencher a lista com os nomes cada vez que a tela AppList 
for chamada.
useEffect(() => {
 //função chamada quando a 
variável route é alterada
 }, [route]);
Para conseguir utilizar o useEffect é necessário importar 
ele no começo do arquivo.
import React, { useState, useEffect 
} from ‘react’;
Feitas as alterações o código do AppList.js já está pronto 
para ser testado. Toda vez que acessar a aplicação ou adicionar 
um novo nome a lista será atualizada automaticamente.
 AppList.jsimport { StatusBar } from ‘expo-
status-bar’;
import React, { useState, useEffect 
} from ‘react’;
import { StyleSheet, Text, View, 
ScrollView } from ‘react-native’;
import AppItem from ‘../components/
AppItem’;
37
import AsyncStorage from ‘@react-
native-community/async-storage’;
export default function AppList({ 
route, navigation }) {
 const [nomes, setNomes] = 
useState([]);
 async function fetchData() {
 //Recupera os nomes que já 
estão no banco de dados
 const response = await 
AsyncStorage.getItem(‘nomes’);
 //Armazena os nomes do banco 
na variavel savedItems
 if (response) return JSON.
parse(response);
 return [];
 }
 useEffect(() => {
 fetchData().
then(items=>setNomes(items));
 }, [route]);
 return (
 <View style={styles.container}>
 <StatusBar style=”light” 
/>
 <Text style={styles.
title}>Lista de Convidados</Text>
 <ScrollView
 style={styles.
scrollContainer}
 contentContainerStyle={styles.
itemsContainer}>
 {nomes.map(item => {
 return <AppItem 
key={item.id} id={item.id} nome={item.
nome} sobrenome={item.sobrenome} 
navigation={navigation} />
 })}
 </ScrollView>
 </View>
 );
}
const styles = StyleSheet.create({
 container: {
 fl ex: 1,
 backgroundColor: ‘#036FFC’,
 alignItems: ‘center’,
 justifyContent: ‘center’
 },
 title: {
 color: ‘#fff’,
 fontSize: 20,
 fontWeight: ‘bold’,
 marginTop: 50,
 marginBottom: 20
 },
 scrollContainer: {
 fl ex: 1,
 width: ‘90%’
 },
 itemsContainer: {
 marginTop: 10,
 padding: 20,
 borderRadius: 10,
 alignItems: ‘stretch’,
 backgroundColor: ‘#fff’
 },
});
Figura 4 – AppList.js. Fonte: Acervo pessoal.
Para fi nalizar esta aula, faremos com que o botão 
excluir possua a funcionalidade de remover um nome da 
lista. Essas alterações serão realizadas diretamente dentro do 
componente criado no AppItem.js. Uma função é defi nida 
para gerenciar quando o botão de deletar for selecionado 
(handleDeletePress).
A interação com o usuário é muito importante, mesmo 
que seja de um simples banco de dados local, precisa de uma 
confi rmação, para isso pode ser usado o componente Alert 
do React Native. Comum na programação Web ele funciona 
como um alerta, o usuário pode confi rmar se quer efetuar a 
exclusão. A importação desse componente deve ser feita no 
começo do arquivo.
import { StyleSheet, Text, View, 
TouchableOpacity, Alert } from ‘react-
native’;
Caso o usuário confi rme no Alert pressionando o 
botão sim, a exclusão do item é realizada e após isso com 
o navigation que foi passado como propriedade será 
realizada uma chamada a tela AppList.js, passando também 
por parâmetro o id que foi removido, para que ela renderize 
novamente os nomes, removendo o excluído.
function handleDeletePress() {
Alert.alert(
 “Atenção”,
 “Você tem certeza que 
38Programação para Dispositivos Móveis
DUARTE, L. In: Tutorial CRUD em app Android e 
iOS com React Native, 2020. Disponível em: https://www.
luiztools.com.br/post/tutorial-crud-em-app-android-e-ios-
com-react-native/. Acesso em: 25 jun. 2020.
Vale a pena acessar
PINHO, D. M.; ESCUDELARIO, B. React Native 
Desenvolvimento de aplicativos mobile com React. Editora Casa do 
Código, São Paulo, 2020.
EISENMAN, B. Learning React Native: Building Native 
Mobile Apps with JavaScript. O’Reilly Media, 2015.
BODUCH, A. React and React Native. Packt Publishing, 
2017.
LEBENSOLD, J. React Native Cookbook: Bringing the 
Web to Native Platforms. O’Reilly Media, 2018.
Vale a pena ler
Vale a pena
deseja excluir este nome?”,
 [
 {
 text: “Não”,
 onPress: ( ) => 
console.log(“Cancel Pressed”),
 style: “cancel”
 },
 {
 text: “Sim”, 
onPress: async () => {
 let savedItems 
= [ ];
 const response = 
await AsyncStorage.getItem(‘nomes1’);
 if (response) 
savedItems = JSON.parse(response);
 const index = 
await savedItems.fi ndIndex(item => item.
id === props.id);
 savedItems.
splice(index, 1);
AsyncStorage.setItem(‘nomes1’, JSON.
stringify(savedItems));
p r o p s . n a v i g a t i o n .
navigate(“AppList”, {id: props.id});
 }
 }
 ],
 { cancelable: false }
 );
 }
Com a função criada basta atribuir no botão na 
propriedade de onPress.
< T o u c h a b l e O p a c i t y 
o n P r e s s = { h a n d l e D e l e t e P r e s s } 
style={styles.deleteButton} >
 <Icon name=”trash” color=”white” 
size={18} />
</TouchableOpacity>
Figura 5 – AppItem.js. Fonte: Acervo pessoal.
Chegamos ao fi nal da sexta aula. Vamos recordar?
Retomando a aula
1– Navegação entre abas
Na seção 1 foi exemplifi cada a navegação entre abas, 
e como criar do zero instalando os métodos ou através do 
template padrão do Expo, que já cria um projeto base com 
navegação.
2– Armazenamento Local
Na última seção foi demonstrado como persistir os 
dados em um banco de dados local, as funções de adicionar, 
ler e remover elementos foram criadas em um projeto de lista 
de convidados.

Continue navegando