React Native con Expo - App móvil de inventario
"Una app móvil completa no vive en una sola pantalla: necesita moverse entre secciones."
En la guía anterior creamos la base visual de nuestra aplicación de inventario. Ahora agregaremos navegación entre pantallas.
La aplicación comenzará a parecerse más a una app real, ya que tendrá menú lateral, menú inferior y pantallas de detalle.
Es el menú lateral de la app. Se abre desde un botón o deslizando desde el borde.
Menú lateralEs el menú inferior que permite cambiar rápidamente entre secciones principales.
Menú inferiorPermite avanzar de una pantalla a otra, por ejemplo de una lista al detalle.
Pantalla de detalleAl finalizar esta guía, la aplicación tendrá varias pantallas conectadas entre sí.
NavigationContainer.Primero instalaremos las librerías necesarias para que la app pueda navegar entre pantallas.
Abre la terminal dentro de la carpeta del proyecto:
cd inventario-app
Ahora instala el paquete principal de React Navigation:
npm install @react-navigation/native
Estas dependencias ayudan a que la navegación funcione correctamente en dispositivos móviles.
npx expo install react-native-screens react-native-safe-area-context
Ahora instalaremos los tres tipos de navegación que usaremos en la aplicación.
npm install @react-navigation/native-stack @react-navigation/bottom-tabs @react-navigation/drawer
El menú lateral necesita algunas librerías adicionales para gestos y animaciones.
npx expo install react-native-gesture-handler react-native-reanimated react-native-worklets
Cuando se instalan librerías de navegación o animación, es recomendable reiniciar Expo limpiando la caché.
npx expo start -c
En la guía anterior ya teníamos carpetas para pantallas y componentes. Ahora agregaremos una carpeta para la navegación.
mkdir src/navigation
También crea los archivos que usaremos para organizar la navegación:
src/navigation/RootDrawer.js
src/navigation/MainTabs.js
src/navigation/ProductsStack.js
El archivo App.js será el encargado de cargar la navegación general de la aplicación.
Para que el Drawer funcione correctamente, agregaremos esta línea al inicio del archivo:
import 'react-native-gesture-handler';
Esta línea debe estar arriba de las demás importaciones.
El componente NavigationContainer envolverá toda la navegación de la app.
import { NavigationContainer } from '@react-navigation/native';
Más adelante crearemos el archivo RootDrawer.js. Por ahora lo importaremos en App.js.
import RootDrawer from './src/navigation/RootDrawer';
Vamos a reemplazar el contenido de App.js, pero lo haremos paso a paso.
Paso 4.1: Agregar las importaciones básicas
import 'react-native-gesture-handler';
import { StatusBar } from 'expo-status-bar';
import { NavigationContainer } from '@react-navigation/native';
import { SafeAreaProvider } from 'react-native-safe-area-context';
import RootDrawer from './src/navigation/RootDrawer';
Estas importaciones traen:
gesture-handler: Para que los gestos del Drawer funcionen.NavigationContainer: El contenedor de toda la navegación.SafeAreaProvider: Protege el contenido de zonas peligrosas del dispositivo.RootDrawer: El navegador principal (lo crearemos después).Paso 4.2: Crear el componente App
export default function App() {
return (
<SafeAreaProvider>
<NavigationContainer>
<RootDrawer />
</NavigationContainer>
</SafeAreaProvider>
);
}
La estructura es: SafeAreaProvider envuelve NavigationContainer, que a su vez envuelve RootDrawer.
Paso 4.3: Agregar la barra de estado
import 'react-native-gesture-handler';
import { StatusBar } from 'expo-status-bar';
import { NavigationContainer } from '@react-navigation/native';
import { SafeAreaProvider } from 'react-native-safe-area-context';
import RootDrawer from './src/navigation/RootDrawer';
export default function App() {
return (
<SafeAreaProvider>
<NavigationContainer>
<RootDrawer />
</NavigationContainer>
<StatusBar style="light" />
</SafeAreaProvider>
);
}
Ayuda a que el contenido respete las zonas seguras del dispositivo, como notches, barras superiores o navegación inferior.
El Drawer será el menú lateral principal de la app. Desde aquí podremos acceder a la sección principal y a configuración.
Abre el archivo:
import { createDrawerNavigator } from '@react-navigation/drawer';
El Drawer no cargará directamente todas las pantallas.
Cargará un navegador de tabs llamado MainTabs y una pantalla de configuración.
import MainTabs from './MainTabs';
import SettingsScreen from '../screens/SettingsScreen';
const Drawer = createDrawerNavigator();
Paso 4.1: Estructura básica
export default function RootDrawer() {
return (
<Drawer.Navigator>
<Drawer.Screen
name="MainTabs"
component={MainTabs}
/>
<Drawer.Screen
name="Settings"
component={SettingsScreen}
/>
</Drawer.Navigator>
);
}
Esto crea un menú lateral con dos opciones: Principal (MainTabs) y Configuración (Settings).
Paso 4.2: Personalizar los colores del Drawer
Ahora agregaremos opciones visuales al Drawer.Navigator:
<Drawer.Navigator
screenOptions={{
headerShown: false,
drawerActiveTintColor: '#1a5276',
drawerInactiveTintColor: '#64748b',
drawerLabelStyle: {
fontWeight: '800',
},
}}
>
Estos atributos controlan:
headerShown: false: Oculta el encabezado superior.drawerActiveTintColor: Color del texto cuando está seleccionado.drawerInactiveTintColor: Color del texto cuando NO está seleccionado.drawerLabelStyle: Estilos del texto (hacerlo más grueso).Paso 4.3: Agregar opciones individuales a cada pantalla
Para que el menú lateral muestre nombres bonitos, agregamos options
a cada Drawer.Screen:
<Drawer.Screen
name="MainTabs"
component={MainTabs}
options={{
title: 'Principal',
drawerLabel: 'Principal',
}}
/>
<Drawer.Screen
name="Settings"
component={SettingsScreen}
options={{
title: 'Configuración',
drawerLabel: 'Configuración',
}}
/>
import { createDrawerNavigator } from '@react-navigation/drawer';
import MainTabs from './MainTabs';
import SettingsScreen from '../screens/SettingsScreen';
const Drawer = createDrawerNavigator();
export default function RootDrawer() {
return (
<Drawer.Navigator
screenOptions={{
headerShown: false,
drawerActiveTintColor: '#1a5276',
drawerInactiveTintColor: '#64748b',
drawerLabelStyle: {
fontWeight: '800',
},
}}
>
<Drawer.Screen
name="MainTabs"
component={MainTabs}
options={{
title: 'Principal',
drawerLabel: 'Principal',
}}
/>
<Drawer.Screen
name="Settings"
component={SettingsScreen}
options={{
title: 'Configuración',
drawerLabel: 'Configuración',
}}
/>
</Drawer.Navigator>
);
}
El menú lateral (Drawer) se vería de la siguiente manera cuando lo abres:
El contenido se oscurece cuando abre el Drawer
El Bottom Tabs Navigator será el menú inferior de la aplicación. Este menú permitirá moverse rápidamente entre las secciones principales.
Abre el archivo:
import { createBottomTabNavigator } from '@react-navigation/bottom-tabs';
Usaremos Text para mostrar pequeños íconos usando emojis
y Pressable para crear el botón del menú lateral.
import { Text, Pressable } from 'react-native';
import HomeScreen from '../screens/HomeScreen';
import CategoriesScreen from '../screens/CategoriesScreen';
import ProfileScreen from '../screens/ProfileScreen';
import ProductsStack from './ProductsStack';
const Tab = createBottomTabNavigator();
Como ocultamos el encabezado del Drawer, crearemos nuestro propio botón.
function MenuButton({ navigation }) {
return (
<Pressable
onPress={() => navigation.getParent()?.openDrawer()}
style={{ marginLeft: 16 }}
>
<Text style={{ color: '#ffffff', fontSize: 24 }}>☰</Text>
</Pressable>
);
}
La pantalla actual está dentro de los tabs, y los tabs están dentro del drawer.
Por eso usamos getParent() para acceder al navegador padre
y abrir el menú lateral.
Paso 6.1: Estructura básica
export default function MainTabs() {
return (
<Tab.Navigator>
<Tab.Screen name="Inicio" component={HomeScreen} />
<Tab.Screen name="Productos" component={ProductsStack} />
<Tab.Screen name="Categorias" component={CategoriesScreen} />
<Tab.Screen name="Perfil" component={ProfileScreen} />
</Tab.Navigator>
);
}
Aquí registramos las 4 pantallas principales que aparecerán en el menú inferior.
Paso 6.2: Personalizar el encabezado
Agregamos estilos para que el encabezado (que viene de los tabs) sea azul oscuro:
screenOptions={({ navigation }) => ({
headerStyle: {
backgroundColor: '#1a5276',
},
headerTintColor: '#ffffff',
headerTitleStyle: {
fontWeight: '900',
},
headerLeft: () => <MenuButton navigation={navigation} />,
Esto controla el color del encabezado, el color del texto, y coloca un botón de menú en la esquina izquierda.
Paso 6.3: Personalizar la barra inferior de tabs
tabBarActiveTintColor: '#1a5276',
tabBarInactiveTintColor: '#64748b',
tabBarLabelStyle: {
fontWeight: '800',
},
tabBarStyle: {
height: 64,
paddingBottom: 8,
paddingTop: 8,
},
})}
Esto hace que la barra inferior sea más alta, con texto más grueso, y con colores azul (activo) y gris (inactivo).
Paso 6.4: Agregar íconos y nombres a cada tab
Para cada pantalla, agregamos un emoji como ícono y un nombre:
<Tab.Screen
name="Inicio"
component={HomeScreen}
options={{
title: 'Inicio',
tabBarIcon: () => <Text>🏠</Text>,
}}
/>
Usamos emojis para los íconos en lugar de una librería adicional.
import { Text, Pressable } from 'react-native';
import { createBottomTabNavigator } from '@react-navigation/bottom-tabs';
import HomeScreen from '../screens/HomeScreen';
import CategoriesScreen from '../screens/CategoriesScreen';
import ProfileScreen from '../screens/ProfileScreen';
import ProductsStack from './ProductsStack';
const Tab = createBottomTabNavigator();
function MenuButton({ navigation }) {
return (
<Pressable
onPress={() => navigation.getParent()?.openDrawer()}
style={{ marginLeft: 16 }}
>
<Text style={{ color: '#ffffff', fontSize: 24 }}>☰</Text>
</Pressable>
);
}
export default function MainTabs() {
return (
<Tab.Navigator
screenOptions={({ navigation }) => ({
headerStyle: {
backgroundColor: '#1a5276',
},
headerTintColor: '#ffffff',
headerTitleStyle: {
fontWeight: '900',
},
headerLeft: () => <MenuButton navigation={navigation} />,
tabBarActiveTintColor: '#1a5276',
tabBarInactiveTintColor: '#64748b',
tabBarLabelStyle: {
fontWeight: '800',
},
tabBarStyle: {
height: 64,
paddingBottom: 8,
paddingTop: 8,
},
})}
>
<Tab.Screen
name="Inicio"
component={HomeScreen}
options={{
title: 'Inicio',
tabBarIcon: () => <Text>🏠</Text>,
}}
/>
<Tab.Screen
name="Productos"
component={ProductsStack}
options={{
title: 'Productos',
tabBarIcon: () => <Text>📦</Text>,
}}
/>
<Tab.Screen
name="Categorias"
component={CategoriesScreen}
options={{
title: 'Categorías',
tabBarIcon: () => <Text>🏷️</Text>,
}}
/>
<Tab.Screen
name="Perfil"
component={ProfileScreen}
options={{
title: 'Perfil',
tabBarIcon: () => <Text>👤</Text>,
}}
/>
</Tab.Navigator>
);
}
La barra de tabs se verá de la siguiente manera cuando hagas tap en cada pestaña:
Contenido de la pantalla activa
Ahora crearemos una navegación de tipo Stack para productos. Esto permitirá pasar de la lista de productos a una pantalla de detalle.
Abre el archivo:
import { createNativeStackNavigator } from '@react-navigation/native-stack';
import ProductsScreen from '../screens/ProductsScreen';
import ProductDetailScreen from '../screens/ProductDetailScreen';
const Stack = createNativeStackNavigator();
Paso 4.1: Estructura básica
El Stack Navigator maneja dos pantallas:
export default function ProductsStack() {
return (
<Stack.Navigator>
<Stack.Screen
name="ProductosLista"
component={ProductsScreen}
/>
<Stack.Screen
name="DetalleProducto"
component={ProductDetailScreen}
/>
</Stack.Navigator>
);
}
Paso 4.2: Ocultar el encabezado del Stack
Aunque los tabs ya tienen un encabezado superior, el Stack Navigator crearía otro encabezado. Para evitar duplicarlo, lo ocultamos:
<Stack.Navigator
screenOptions={{
headerShown: false,
}}
>
Ahora solo habrá un encabezado (el de los tabs), y el Stack Navigator simplemente administra la navegación en segundo plano.
import { createNativeStackNavigator } from '@react-navigation/native-stack';
import ProductsScreen from '../screens/ProductsScreen';
import ProductDetailScreen from '../screens/ProductDetailScreen';
const Stack = createNativeStackNavigator();
export default function ProductsStack() {
return (
<Stack.Navigator
screenOptions={{
headerShown: false,
}}
>
<Stack.Screen
name="ProductosLista"
component={ProductsScreen}
/>
<Stack.Screen
name="DetalleProducto"
component={ProductDetailScreen}
/>
</Stack.Navigator>
);
}
La pantalla de productos (ProductsScreen) mostrará una lista de productos como esta:
$850.00 - Stock: 8
Tecnología$18.50 - Stock: 25
Accesorios$95.00 - Stock: 4
OficinaAhora crearemos las pantallas que se usarán en la navegación.
Crea el archivo:
Paso 1: Importar y crear datos
Primero importamos lo necesario:
import { useState } from 'react';
import { ScrollView, View, Text, StyleSheet } from 'react-native';
import ProductCard from '../components/ProductCard';
Luego creamos datos temporales dentro de la función:
export default function ProductsScreen({ navigation }) {
const [categorias] = useState([
{ id: 1, nombre: 'Tecnología' },
{ id: 2, nombre: 'Accesorios' },
{ id: 3, nombre: 'Oficina' },
]);
const [productos] = useState([
{
id: 1,
nombre: 'Laptop Dell',
precio: 850,
stock: 8,
categoriaId: 1,
},
{
id: 2,
nombre: 'Mouse inalámbrico',
precio: 18.5,
stock: 25,
categoriaId: 2,
},
{
id: 3,
nombre: 'Silla ejecutiva',
precio: 95,
stock: 4,
categoriaId: 3,
},
]);
Nota que la función recibe { navigation } como parámetro.
Esto nos permite navegar hacia otras pantallas.
Paso 2: Crear función auxiliar para categorías
function obtenerNombreCategoria(categoriaId) {
const categoriaEncontrada = categorias.find(
categoria => categoria.id === categoriaId
);
return categoriaEncontrada ? categoriaEncontrada.nombre : 'Sin categoría';
}
Paso 3: Crear el UI de la pantalla
Primero, un encabezado simple:
return (
<ScrollView style={styles.container} contentContainerStyle={styles.content}>
<View style={styles.headerBlock}>
<Text style={styles.title}>Productos</Text>
<Text style={styles.subtitle}>
Consulta los productos registrados en el inventario.
</Text>
</View>
Paso 4: Mostrar los productos con navegación
Finalmente, listamos los productos. Cada uno es clickeable y abre el detalle:
{productos.map(producto => (
<ProductCard
key={producto.id}
producto={producto}
categoria={obtenerNombreCategoria(producto.categoriaId)}
onPress={() =>
navigation.navigate('DetalleProducto', {
producto: producto,
categoria: obtenerNombreCategoria(producto.categoriaId),
})
}
/>
))}
</ScrollView>
);
}
La parte importante es navigation.navigate('DetalleProducto', {...}).
Esto navega a la pantalla de detalle y le pasa el producto como parámetro.
import { useState } from 'react';
import { ScrollView, View, Text, StyleSheet } from 'react-native';
import ProductCard from '../components/ProductCard';
export default function ProductsScreen({ navigation }) {
const [categorias] = useState([
{ id: 1, nombre: 'Tecnología' },
{ id: 2, nombre: 'Accesorios' },
{ id: 3, nombre: 'Oficina' },
]);
const [productos] = useState([
{
id: 1,
nombre: 'Laptop Dell',
precio: 850,
stock: 8,
categoriaId: 1,
},
{
id: 2,
nombre: 'Mouse inalámbrico',
precio: 18.5,
stock: 25,
categoriaId: 2,
},
{
id: 3,
nombre: 'Silla ejecutiva',
precio: 95,
stock: 4,
categoriaId: 3,
},
]);
function obtenerNombreCategoria(categoriaId) {
const categoriaEncontrada = categorias.find(
categoria => categoria.id === categoriaId
);
return categoriaEncontrada ? categoriaEncontrada.nombre : 'Sin categoría';
}
return (
<ScrollView style={styles.container} contentContainerStyle={styles.content}>
<View style={styles.headerBlock}>
<Text style={styles.title}>Productos</Text>
<Text style={styles.subtitle}>
Consulta los productos registrados en el inventario.
</Text>
</View>
{productos.map(producto => (
<ProductCard
key={producto.id}
producto={producto}
categoria={obtenerNombreCategoria(producto.categoriaId)}
onPress={() =>
navigation.navigate('DetalleProducto', {
producto: producto,
categoria: obtenerNombreCategoria(producto.categoriaId),
})
}
/>
))}
</ScrollView>
);
}
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: '#f8fafc',
},
content: {
padding: 20,
paddingBottom: 40,
},
headerBlock: {
marginBottom: 18,
},
title: {
fontSize: 28,
fontWeight: '900',
color: '#0f172a',
},
subtitle: {
color: '#64748b',
marginTop: 6,
fontSize: 15,
},
});
Crea el archivo:
Paso 1: Recibir parámetros y crear la estructura
Esta pantalla recibirá el producto y la categoría a través de route.params.
import { View, Text, StyleSheet, Pressable } from 'react-native';
export default function ProductDetailScreen({ route, navigation }) {
const { producto, categoria } = route.params;
Paso 2: Crear la tarjeta con el encabezado
Ahora mostramos la información del producto en una tarjeta:
return (
<View style={styles.container}>
<View style={styles.card}>
<Text style={styles.kicker}>Detalle del producto</Text>
<Text style={styles.title}>{producto.nombre}</Text>
Paso 3: Agregar los campos de información
Luego agregamos recuadros para mostrar cada detalle:
<View style={styles.infoBox}>
<Text style={styles.label}>Categoría</Text>
<Text style={styles.value}>{categoria}</Text>
</View>
<View style={styles.infoBox}>
<Text style={styles.label}>Precio</Text>
<Text style={styles.value}>${producto.precio.toFixed(2)}</Text>
</View>
<View style={styles.infoBox}>
<Text style={styles.label}>Stock disponible</Text>
<Text style={styles.value}>{producto.stock} unidades</Text>
</View>
Paso 4: Agregar botón de navegación
Finalmente, un botón que regresa a la lista de productos:
<Pressable style={styles.button} onPress={() => navigation.goBack()}>
<Text style={styles.buttonText}>Volver a productos</Text>
</Pressable>
</View>
</View>
);
}
import { View, Text, StyleSheet, Pressable } from 'react-native';
export default function ProductDetailScreen({ route, navigation }) {
const { producto, categoria } = route.params;
return (
<View style={styles.container}>
<View style={styles.card}>
<Text style={styles.kicker}>Detalle del producto</Text>
<Text style={styles.title}>{producto.nombre}</Text>
<View style={styles.infoBox}>
<Text style={styles.label}>Categoría</Text>
<Text style={styles.value}>{categoria}</Text>
</View>
<View style={styles.infoBox}>
<Text style={styles.label}>Precio</Text>
<Text style={styles.value}>${producto.precio.toFixed(2)}</Text>
</View>
<View style={styles.infoBox}>
<Text style={styles.label}>Stock disponible</Text>
<Text style={styles.value}>{producto.stock} unidades</Text>
</View>
<Pressable style={styles.button} onPress={() => navigation.goBack()}>
<Text style={styles.buttonText}>Volver a productos</Text>
</Pressable>
</View>
</View>
);
}
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: '#f8fafc',
padding: 20,
},
card: {
backgroundColor: '#ffffff',
borderRadius: 22,
padding: 22,
borderWidth: 1,
borderColor: '#e2e8f0',
},
kicker: {
color: '#1a5276',
fontWeight: '900',
textTransform: 'uppercase',
fontSize: 12,
marginBottom: 8,
},
title: {
fontSize: 28,
fontWeight: '900',
color: '#0f172a',
marginBottom: 18,
},
infoBox: {
backgroundColor: '#f8fafc',
padding: 14,
borderRadius: 16,
marginBottom: 12,
},
label: {
color: '#64748b',
fontWeight: '800',
fontSize: 13,
},
value: {
color: '#0f172a',
fontSize: 18,
fontWeight: '900',
marginTop: 4,
},
button: {
backgroundColor: '#1a5276',
padding: 14,
borderRadius: 14,
marginTop: 10,
},
buttonText: {
color: '#ffffff',
textAlign: 'center',
fontWeight: '900',
},
});
Crea el archivo:
import { useState } from 'react';
import { ScrollView, View, Text, StyleSheet } from 'react-native';
export default function CategoriesScreen() {
const [categorias] = useState([
{
id: 1,
nombre: 'Tecnología',
descripcion: 'Equipos electrónicos y computadoras',
},
{
id: 2,
nombre: 'Accesorios',
descripcion: 'Complementos para computadoras y oficina',
},
{
id: 3,
nombre: 'Oficina',
descripcion: 'Mobiliario y herramientas de trabajo',
},
]);
return (
<ScrollView style={styles.container} contentContainerStyle={styles.content}>
<Text style={styles.title}>Categorías</Text>
<Text style={styles.subtitle}>
Clasifica los productos del inventario.
</Text>
{categorias.map(categoria => (
<View key={categoria.id} style={styles.card}>
<Text style={styles.categoryName}>{categoria.nombre}</Text>
<Text style={styles.description}>{categoria.descripcion}</Text>
</View>
))}
</ScrollView>
);
}
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: '#f8fafc',
},
content: {
padding: 20,
paddingBottom: 40,
},
title: {
fontSize: 28,
fontWeight: '900',
color: '#0f172a',
},
subtitle: {
color: '#64748b',
marginTop: 6,
marginBottom: 18,
fontSize: 15,
},
card: {
backgroundColor: '#ffffff',
padding: 18,
borderRadius: 18,
marginBottom: 12,
borderWidth: 1,
borderColor: '#e2e8f0',
},
categoryName: {
fontSize: 18,
fontWeight: '900',
color: '#1a5276',
},
description: {
color: '#64748b',
marginTop: 5,
},
});
Crea el archivo:
import { View, Text, StyleSheet } from 'react-native';
export default function ProfileScreen() {
return (
<View style={styles.container}>
<View style={styles.card}>
<View style={styles.avatar}>
<Text style={styles.avatarText}>AD</Text>
</View>
<Text style={styles.title}>Administrador</Text>
<Text style={styles.subtitle}>
Usuario encargado de gestionar el inventario.
</Text>
<View style={styles.infoBox}>
<Text style={styles.label}>Rol</Text>
<Text style={styles.value}>Encargado de inventario</Text>
</View>
<View style={styles.infoBox}>
<Text style={styles.label}>Módulo actual</Text>
<Text style={styles.value}>Productos y categorías</Text>
</View>
</View>
</View>
);
}
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: '#f8fafc',
padding: 20,
},
card: {
backgroundColor: '#ffffff',
borderRadius: 22,
padding: 22,
borderWidth: 1,
borderColor: '#e2e8f0',
alignItems: 'center',
},
avatar: {
width: 84,
height: 84,
borderRadius: 42,
backgroundColor: '#1a5276',
justifyContent: 'center',
alignItems: 'center',
marginBottom: 14,
},
avatarText: {
color: '#ffffff',
fontSize: 26,
fontWeight: '900',
},
title: {
fontSize: 24,
fontWeight: '900',
color: '#0f172a',
},
subtitle: {
textAlign: 'center',
color: '#64748b',
marginTop: 6,
marginBottom: 18,
},
infoBox: {
width: '100%',
backgroundColor: '#f8fafc',
padding: 14,
borderRadius: 16,
marginBottom: 10,
},
label: {
color: '#64748b',
fontWeight: '800',
fontSize: 13,
},
value: {
color: '#0f172a',
fontWeight: '900',
marginTop: 4,
},
});
Crea el archivo:
import { View, Text, StyleSheet, Pressable } from 'react-native';
export default function SettingsScreen({ navigation }) {
return (
<View style={styles.container}>
<View style={styles.topbar}>
<Pressable onPress={() => navigation.openDrawer()}>
<Text style={styles.menuButton}>☰</Text>
</Pressable>
<Text style={styles.topbarTitle}>Configuración</Text>
</View>
<View style={styles.card}>
<Text style={styles.title}>Ajustes de la aplicación</Text>
<Text style={styles.subtitle}>
Esta sección servirá más adelante para configurar opciones generales
del sistema de inventario.
</Text>
<View style={styles.option}>
<Text style={styles.optionTitle}>Nombre de la empresa</Text>
<Text style={styles.optionText}>Inventario App</Text>
</View>
<View style={styles.option}>
<Text style={styles.optionTitle}>Moneda</Text>
<Text style={styles.optionText}>Dólares estadounidenses</Text>
</View>
</View>
</View>
);
}
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: '#f8fafc',
},
topbar: {
backgroundColor: '#1a5276',
paddingTop: 48,
paddingHorizontal: 20,
paddingBottom: 16,
flexDirection: 'row',
alignItems: 'center',
gap: 14,
},
menuButton: {
color: '#ffffff',
fontSize: 26,
},
topbarTitle: {
color: '#ffffff',
fontSize: 20,
fontWeight: '900',
},
card: {
backgroundColor: '#ffffff',
margin: 20,
padding: 22,
borderRadius: 22,
borderWidth: 1,
borderColor: '#e2e8f0',
},
title: {
fontSize: 24,
fontWeight: '900',
color: '#0f172a',
},
subtitle: {
color: '#64748b',
marginTop: 8,
marginBottom: 18,
},
option: {
backgroundColor: '#f8fafc',
padding: 14,
borderRadius: 16,
marginBottom: 10,
},
optionTitle: {
color: '#0f172a',
fontWeight: '900',
},
optionText: {
color: '#64748b',
marginTop: 4,
},
});
En la guía anterior, ProductCard solo mostraba información.
Ahora necesitamos que sea clickeable para abrir el detalle del producto.
Abre el archivo:
Antes importábamos:
import { View, Text, StyleSheet } from 'react-native';
Ahora necesitamos importar Pressable:
import { Pressable, View, Text, StyleSheet } from 'react-native';
Antes la función era:
export default function ProductCard({ producto, categoria }) {
Ahora recibiremos una prop onPress que ejecutará cuando se presione:
export default function ProductCard({ producto, categoria, onPress }) {
El contenedor principal (que antes era View) ahora será Pressable:
<Pressable style={styles.card} onPress={onPress}>
// ... resto del contenido ...
</Pressable>
El onPress={onPress} hace que cuando se toque la tarjeta,
se ejecute la función que pasó el componente padre (ProductsScreen).
import { Pressable, View, Text, StyleSheet } from 'react-native';
import CategoryPill from './CategoryPill';
export default function ProductCard({ producto, categoria, onPress }) {
return (
<Pressable style={styles.card} onPress={onPress}>
<View style={styles.row}>
<View style={styles.info}>
<Text style={styles.nombre}>{producto.nombre}</Text>
<Text style={styles.detalle}>
Precio: ${producto.precio.toFixed(2)}
</Text>
<Text style={styles.detalle}>
Stock: {producto.stock} unidades
</Text>
<CategoryPill nombre={categoria} />
</View>
<View style={styles.badge}>
<Text style={styles.badgeText}>
{producto.stock <= 5 ? 'Bajo' : 'OK'}
</Text>
</View>
</View>
</Pressable>
);
}
const styles = StyleSheet.create({
card: {
backgroundColor: '#ffffff',
padding: 16,
borderRadius: 18,
marginBottom: 12,
borderWidth: 1,
borderColor: '#e2e8f0',
},
row: {
flexDirection: 'row',
justifyContent: 'space-between',
gap: 12,
},
info: {
flex: 1,
},
nombre: {
fontSize: 17,
fontWeight: '900',
color: '#0f172a',
},
detalle: {
color: '#64748b',
marginTop: 3,
},
badge: {
backgroundColor: '#e0f2fe',
borderRadius: 12,
paddingHorizontal: 10,
paddingVertical: 6,
alignSelf: 'flex-start',
},
badgeText: {
color: '#0369a1',
fontWeight: '900',
fontSize: 12,
},
});
En la Guía 1, HomeScreen mostraba un inicio visual.
Ahora agregaremos botones para navegar a productos y categorías.
Para poder navegar, la función debe recibir navigation:
export default function HomeScreen() {
export default function HomeScreen({ navigation }) {
En las importaciones de React Native, necesitamos Pressable:
import { ScrollView, View, Text, StyleSheet } from 'react-native';
import { ScrollView, View, Text, StyleSheet, Pressable } from 'react-native';
Debajo del bloque del encabezado, agrega un View para los botones:
<View style={styles.actionsRow}>
El primer botón navega a la pantalla de productos:
<Pressable
style={styles.primaryButton}
onPress={() => navigation.navigate('Productos')}
>
<Text style={styles.primaryButtonText}>Ver productos</Text>
</Pressable>
El segundo botón navega a la pantalla de categorías:
<Pressable
style={styles.secondaryButton}
onPress={() => navigation.navigate('Categorias')}
>
<Text style={styles.secondaryButtonText}>Ver categorías</Text>
</Pressable>
</View>
En la sección de estilos, agrega estos nuevos estilos:
actionsRow: {
flexDirection: 'row',
gap: 10,
marginBottom: 18,
},
primaryButton: {
flex: 1,
backgroundColor: '#1a5276',
padding: 14,
borderRadius: 14,
},
primaryButtonText: {
color: '#ffffff',
textAlign: 'center',
fontWeight: '900',
},
secondaryButton: {
flex: 1,
backgroundColor: '#e0f2fe',
padding: 14,
borderRadius: 14,
},
secondaryButtonText: {
color: '#1a5276',
textAlign: 'center',
fontWeight: '900',
},
{ navigation } a la función.Pressable.Ahora es tu turno. Realiza las siguientes modificaciones.
Cambia los nombres de las opciones del Drawer. Por ejemplo: Principal por Inicio del sistema.
Cambia los emojis usados como íconos de los tabs.
Agrega una nueva pantalla llamada AboutScreen.js y colócala dentro del Drawer.
Agrega un cuarto producto temporal y verifica que también pueda abrirse en la pantalla de detalle.