Baixe o app para aproveitar ainda mais
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.
Compartilhar