Vistas, Texto y Componentes Principales
Primitivas de layout, reglas de anidación de texto y particularidades de renderizado específicas de la plataforma.
Busca en todas las páginas de la documentación
Primitivas de layout, reglas de anidación de texto y particularidades de renderizado específicas de la plataforma.
Tarjeta de referencia rápida - lista para copiar y pegar.
import { StyleSheet, Text, View, ScrollView, SafeAreaView } from "react-native";
export function ProfileCard({ name, bio }: { name: string; bio: string }) {
return (
<SafeAreaView style={styles.safe}>
<ScrollView contentContainerStyle={styles.scroll}>
<View style={styles.card}>
<Text style={styles.title}>{name}</Text>
<Text style={styles.body}>
{bio}
{"\n"}
<Text style={styles.link}>Leer más</Text>
</Text>
</View>
</ScrollView>
</SafeAreaView>
);
}
const styles = StyleSheet.create({
safe: { flex: 1, backgroundColor: "#f5f5f5" },
scroll: { padding: 16 },
card: {
backgroundColor: "#fff",
borderRadius: 12,
padding: 16,
gap: 8,
},
title: { fontSize: 20, fontWeight: "600" },
body: { fontSize: 16, lineHeight: 24, color: "#333" },
link: { color: "#2563eb", fontWeight: "500" },
});Cuándo usarlo: Estás construyendo cualquier layout de pantalla - tarjetas, listas, encabezados - y necesitas las primitivas fundamentales View/Text con desplazamiento seguro e insertos conscientes de las muescas.
import { useState } from "react";
import {
Platform,
Pressable,
ScrollView,
StyleSheet,
Text,
View,
} from "react-native";
import { SafeAreaView } from "react-native-safe-area-context";
type Tab = "posts" | "about";
interface Post {
id: string;
title: string;
excerpt: string;
}
const POSTS: Post[] = [
{ id: "1", title: "Hermes on device", excerpt: "Startup wins from a compact bytecode runtime." },
{ id: "2", title: "Fabric layout", excerpt: "Shadow nodes commit straight to the native tree." },
];
export default function FeedScreen() {
const [tab, setTab] = useState<Tab>("posts");
return (
<SafeAreaView style={styles.safe} edges={["top", "left", "right"]}>
<View style={styles.header}>
<Text style={styles.heading}>RN Fundamentals</Text>
<View style={styles.tabs}>
{(["posts", "about"] as const).map((key) => (
<Pressable
key={key}
onPress={() => setTab(key)}
style={[styles.tab, tab === key && styles.tabActive]}
>
<Text style={[styles.tabLabel, tab === key && styles.tabLabelActive]}>
{key === "posts" ? "Artículos" : "Acerca de"}
</Text>
</Pressable>
))}
</View>
</View>
<ScrollView
contentContainerStyle={styles.content}
keyboardShouldPersistTaps="handled"
>
{tab === "posts" ? (
POSTS.map((post) => (
<View key={post.id} style={styles.card}>
<Text style={styles.cardTitle}>{post.title}</Text>
<Text style={styles.cardBody} numberOfLines={2}>
{post.excerpt}
</Text>
</View>
))
) : (
<Text style={styles.cardBody}>
Built with Expo SDK 57, React Native 0.86, and React 19.2.3.
</Text>
)}
</ScrollView>
<View
style={[
styles.footer,
Platform.select({ ios: styles.footerIos, android: styles.footerAndroid }),
]}
>
<Text style={styles.footerText}>© 2026 Mobile Cookbook</Text>
</View>
</SafeAreaView>
);
}
const styles = StyleSheet.create({
safe: { flex: 1, backgroundColor: "#f8fafc" },
header: { paddingHorizontal: 16, paddingBottom: 8, gap: 12 },
heading: { fontSize: 28, fontWeight: "700", color: "#0f172a" },
tabs: { flexDirection: "row", gap: 8 },
tab: {
paddingHorizontal: 14,
paddingVertical: 8,
borderRadius: 999,
backgroundColor: "#e2e8f0",
},
tabActive: { backgroundColor: "#2563eb" },
tabLabel: { fontSize: 14, fontWeight: "600", color: "#334155" },
tabLabelActive: { color: "#fff" },
content: { padding: 16, gap: 12, paddingBottom: 32 },
card: {
backgroundColor: "#fff",
borderRadius: 12,
padding: 16,
gap: 6,
...Platform.select({
ios: {
shadowColor: "#000",
shadowOffset: { width: 0, height: 2 },
shadowOpacity: 0.08,
shadowRadius: 8,
},
android: { elevation: 3 },
}),
},
cardTitle: { fontSize: 17, fontWeight: "600", color: "#0f172a" },
cardBody: { fontSize: 15, lineHeight: 22, color: "#475569" },
footer: {
paddingHorizontal: 16,
paddingVertical: 12,
borderTopWidth: StyleSheet.hairlineWidth,
borderTopColor: "#cbd5e1",
},
footerIos: { paddingBottom: 4 },
footerAndroid: { paddingBottom: 8 },
footerText: { fontSize: 12, color: "#64748b", textAlign: "center" },
});Lo que esto demuestra:
View como contenedor de layout con flexbox (gap, flexDirection) y sombra/elevación específica de la plataformaText para tramos con estilos en línea dentro de un párrafoScrollView con contentContainerStyle para padding del contenido desplazableSafeAreaView de react-native-safe-area-context con edges explícitoPlatform.select para pequeñas diferencias de estilo entre iOS/Android en un archivonumberOfLines para truncamiento de texto en nodos de texto nativosView se convierte en UIView en iOS y android.view.ViewGroup en Android.flexDirection predeterminado es column, lo opuesto a los valores predeterminados web típicos.Text se mapea a UILabel / TextView. Las cadenas se renderizan mediante el motor de texto nativo, no como HTML.StyleSheet.create registra los estilos una vez; en tiempo de desarrollo valida los nombres de propiedades contra el esquema de estilo de RN.| Componente | Rol | Uso típico |
|---|---|---|
View | Caja de layout | Filas, tarjetas, envoltorios, objetivos de toque |
Text | Renderizado de texto | Etiquetas, párrafos, tramos en línea |
ScrollView | Desplazamiento acotado | Formularios cortos, configuración, páginas de detalle |
FlatList | Desplazamiento virtualizado | Listas largas (ver sección de rendimiento) |
Image | Mapas de bits e iconos | Avatares, imágenes destacadas (require o URI) |
TextInput | Texto editable | Formularios, barras de búsqueda |
Pressable | Retroalimentación de toque | Botones, filas de lista (ver artículo de manejo de eventos) |
SafeAreaView | Shell consciente de insertos | Pantallas bajo muescas e indicadores de inicio |
| Regla | iOS | Android |
|---|---|---|
Las cadenas sin formato deben estar dentro de <Text> | Aplicado (redbox) | Aplicado (redbox) |
<Text> anidado hereda estilos del padre | Sí | Sí |
numberOfLines trunca con puntos suspensivos | Sí | Sí |
onPress en Text anidado | Compatible | Compatible |
| Semántica HTML a nivel de bloque | N/A - sin <p>, <div> | N/A |
// Válido - enlace en línea dentro de texto del cuerpo
<Text style={styles.body}>
Toca aquí para {" "}
<Text style={styles.link} onPress={openDocs}>
abrir la documentación
</Text>
.
</Text>
// Inválido - cadena directamente bajo View
<View>
Hola {/* redbox: Text strings must be rendered within a <Text> component */}
</View>// Valores predeterminados de flex de RN (difiere del navegador)
// flexDirection: 'column'
// alignItems: 'stretch'
// flexShrink: 0 en hijos (web a menudo se reduce)
// position: 'relative' solo - se necesitan bibliotecas para 'fixed'/'sticky'
<View style={{ flex: 1 }}> {/* rellena el padre a lo largo del eje principal */}
<View style={{ flex: 1 }} /> {/* divide el espacio restante con hermanos */}
</View>import type { StyleProp, TextStyle, ViewStyle } from "react-native";
interface CardProps {
title: string;
children: React.ReactNode;
style?: StyleProp<ViewStyle>;
titleStyle?: StyleProp<TextStyle>;
}
// StyleProp<T> acepta un estilo único, array o entradas falsas
const merged: StyleProp<ViewStyle> = [styles.card, isActive && styles.cardActive, style];React de react; los tipos de prop de componentes viven junto al componente.StyleProp<ViewStyle> / StyleProp<TextStyle> para invalidaciones de estilo opcionales.const styles = StyleSheet.create({...}) para que las claves se verifiquen exhaustivamente.react-native-safe-area-context y escribe edges como Edge[].Cadenas fuera de Text - Colocar "Hola" directamente dentro de View genera una redbox de desarrollo. Solución: Envuelve todas las cadenas visibles para el usuario en <Text>.
Asumir layout de fila - Copiar fragmentos de flex web con dirección de fila implícita apila hijos verticalmente. Solución: Establece explícitamente flexDirection: "row" cuando desees layout horizontal.
Padding en ScrollView vs contenido - Poner padding en ScrollView mismo recorta indicadores de desplazamiento de manera extraña en iOS. Solución: Usa contentContainerStyle para padding interno.
Sombra en Android - Los props iOS shadowColor / shadowOffset se ignoran en Android. Solución: Empareja los props de sombra iOS con elevation vía Platform.select.
Doble padding de área segura - Anidar SafeAreaView dentro de otro envoltorio seguro agrega un inserto superior excesivo. Solución: Aplica el área segura una sola vez en la raíz de la pantalla; usa edges para controlar qué lados reciben inserto.
numberOfLines sin restricción de ancho - El truncamiento puede no aparecer si el nodo de texto se expande libremente. Solución: Limita el ancho con flex: 1, width o flexShrink del padre.
Árboles profundos de View para estilos de texto - Envolver cada palabra en View rompe el flujo en línea y perjudica la accesibilidad. Solución: Anida Text dentro de Text para tramos en línea.
| Alternativa | Usar cuando | No usar cuando |
|---|---|---|
Primitivas View + Text | Control total, aprendizaje de fundamentos, sistemas de diseño personalizados | Necesitas un kit de componentes completo listo para usar |
@rneui/themed / React Native Paper | Los componentes Material o temáticos consistentes se envían más rápido | El tamaño del bundle o la lucha por invalidaciones de estilo importa |
Layouts Stack de expo-router | Chrome de navegación, encabezados y shells de pantalla | Solo necesitas un layout de tarjeta estática |
FlatList en lugar de ScrollView | 50+ filas homogéneas, se requiere virtualización | Pantallas de contenido pequeño y mixto (formularios, dashboards) |
CSS vía react-native-unistyles / Tamagui | Theming basado en tokens en todas las plataformas | Una sola pantalla con un puñado de reglas StyleSheet |
UILabel / TextView.View es solo un contenedor de layout; no puede renderizar glifos.column - los hijos se apilan verticalmente de arriba a abajo.flexDirection: "row" para barras de herramientas horizontales y filas de chips.<Text style={styles.body}>
¿Ya tienes una cuenta?{" "}
<Text style={styles.link} onPress={goToLogin}>
Inicia sesión
</Text>
</Text>Text anidado hereda el tamaño y color de fuente del padre a menos que se anule.ScrollView renderiza todos los hijos de una sola vez - bien para contenido corto.FlatList virtualiza filas - requerido para feeds largos para evitar costo de memoria y layout.ScrollView es más simple y predecible.shadowColor, shadowOffset, shadowOpacity, shadowRadius.elevation en el fondo de la vista.Platform.select dentro de StyleSheet.create.style se aplica al viewport de desplazamiento (la ventana visible).contentContainerStyle se aplica al envoltorio interno que se mueve al desplazarse.gap y flexGrow: 1 en contentContainerStyle, no en style.SafeAreaView de react-native-safe-area-context (incluido en plantillas de Expo).edges={["top", "left", "right"]} para evitar padding inferior doble encima de barras de pestañas.Text acepta onPress, onLongPress y pressRetentionOffset.Pressable con un hijo Text para roles más claros y objetivos de toque más grandes.Text.gap, rowGap y columnGap se soportan en React Native 0.71+.contentContainerStyle de View y ScrollView.numberOfLines necesita un ancho acotado para medir el desbordamiento.flex: 1, un width fijo o flexShrink: 1 en Text o en la fila del padre.StyleSheet.create valida claves, permite reutilización y se lee más limpio en diffs.{ opacity: pressed ? 0.6 : 1 }).style={[styles.base, { backgroundColor: color }]}.Text, formas de estilo) se mantienen sin cambios desde la perspectiva del desarrollador.<View style={{ flex: 1, justifyContent: "center", alignItems: "center" }}>
<Text>Centrado</Text>
</View>justifyContent alinea en el eje principal (columna = vertical).alignItems alinea en el eje transversal (columna = horizontal).width: "100%" y height: "50%" se resuelven contra el padre.useWindowDimensions en el artículo de dimensiones.pointerEvents="none" permite que los toques pasen a través de las vistas inferiores - útil para superposiciones decorativas.box-none ignora los toques en el contenedor pero permite que los hijos los reciban.auto; cambia solo cuando depures objetivos de toque superpuestos.Pressable, gestos y hitSlopuseWindowDimensionsImage, buckets de densidad y carga de activos.ios / .androidVersiones de Stack: Esta página fue escrita para React 19.2.3, React Native 0.86.0 y Expo SDK 57 (
expo~57.0.4).
Revisado por Chris St. John·Última actualización: 19 jul 2026