Dominando Modais: O Padrão Bottom Sheet React Native
No desenvolvimento mobile moderno, a experiência do usuário (UX) é definida pelos detalhes. Se no artigo anterior exploramos as notificações de topo, hoje vamos dominar o Bottom Sheet React Native — aquele modal que desliza suavemente da base para cima. Este é, atualmente, um dos padrões de design mais fortes em apps como Instagram, Uber e Nubank.
📚 Baixar Código Base
1. Por que usar o Bottom Sheet?
Diferente dos alertas centrais que “saltam” e interrompem a visão, o Bottom Sheet é preferido porque mantém os elementos de interação próximos ao polegar do usuário. Isso facilita o uso do aparelho com apenas uma mão, algo essencial para a usabilidade no dia a dia.
2. Anatomia do Código Profissional
Para que o efeito seja fluido e pareça nativo, nossa implementação se baseia em três pilares:
A. O Overlay Inteligente
Usamos uma camada semitransparente para dar foco ao modal. Um detalhe crucial de UX: ao tocar no espaço vazio acima do modal, ele deve fechar.
<TouchableOpacity
style={estilos.fecharOverlay}
onPress={() => setModalVisivel(false)}
/>
B. O Indicador de Arraste (Handle)
Um detalhe sutil, mas poderoso, é criar uma pequena barra no topo do modal. Ela sinaliza visualmente ao usuário que aquele painel pode ser “puxado” ou descartado para baixo.
C. Estilização e Sombras
Para o visual de “aba”, aplicamos borderTopLeftRadius e borderTopRightRadius. Somado ao elevation (Android), criamos a profundidade necessária.
3. Implementação Prática (Laboratório)
import React, { useState } from 'react';
import { View, Text, StyleSheet, Modal, TouchableOpacity, StatusBar } from 'react-native';
export default function App() {
const [modalVisivel, setModalVisivel] = useState(false);
return (
<View style={estilos.container}>
<StatusBar barStyle="dark-content" />
<TouchableOpacity style={estilos.botao} onPress={() => setModalVisivel(true)}>
<Text style={estilos.textoBotao}>Abrir Opções</Text>
</TouchableOpacity>
<Modal
animationType="slide" // Efeito de deslizar de baixo para cima
transparent={true}
visible={modalVisivel}
onRequestClose={() => setModalVisivel(false)}
>
<View style={estilos.overlay}>
{/* Área clicável para fechar ao tocar fora */}
<TouchableOpacity
style={estilos.fecharOverlay}
onPress={() => setModalVisivel(false)}
/>
<View style={estilos.modalInferior}>
<View style={estilos.indicador} />
<Text style={estilos.titulo}>Configurações</Text>
<Text style={estilos.subtitulo}>Escolha uma das opções abaixo para prosseguir.</Text>
<TouchableOpacity style={estilos.opcaoBotao} onPress={() => setModalVisivel(false)}>
<Text style={estilos.textoOpcao}>Editar Perfil</Text>
</TouchableOpacity>
</View>
</View>
</Modal>
</View>
);
}
const estilos = StyleSheet.create({
container: { flex: 1, justifyContent: 'center', alignItems: 'center', backgroundColor: '#EDF2F7' },
botao: { backgroundColor: '#2D3748', padding: 15, borderRadius: 10 },
textoBotao: { color: '#FFF', fontWeight: 'bold' },
overlay: { flex: 1, backgroundColor: 'rgba(0,0,0,0.4)', justifyContent: 'flex-end' },
fecharOverlay: { flex: 1 }, // Ocupa o espaço acima do modal
modalInferior: {
backgroundColor: '#FFF',
borderTopLeftRadius: 30,
borderTopRightRadius: 30,
padding: 20,
alignItems: 'center',
elevation: 20,
},
indicador: { width: 40, height: 5, backgroundColor: '#CBD5E0', borderRadius: 10, marginBottom: 15 },
titulo: { fontSize: 20, fontWeight: 'bold', color: '#1A202C' },
subtitulo: { fontSize: 14, color: '#718096', textAlign: 'center', marginVertical: 10 },
opcaoBotao: { width: '100%', padding: 15, backgroundColor: '#F7FAFC', borderRadius: 12, marginTop: 10, alignItems: 'center' },
textoOpcao: { color: '#2D3748', fontWeight: '600' }
});
🧠 Desafio de Autonomia: Dark Mode
Agora que você tem a estrutura, tente aplicar o Pensamento Analítico: como você alteraria as cores do modalInferior e dos textos para criar um “Modo Noturno”? Mudar as cores de fundo para #1A202C e os textos para #FFF é um ótimo começo!
⬅️ Artigo Anterior: Criando Modais Modernos: O Top Alert
➡️ Próximo Passo: Trabalhando com Listas: O poder da FlatList
Compartilhe:





1 comentário