
Dimensiones, breakpoints y estilos responsivos en apps móviles.
Dimensiones y Estilos Responsivos
Uso de Dimensions, useWindowDimensions y breakpoints para adaptar el diseño.
typescript1import { View, Text, StyleSheet, Dimensions, useWindowDimensions } from 'react-native' 2 3// Dimensions estático 4const { width: SCREEN_WIDTH, height: SCREEN_HEIGHT } = Dimensions.get('window') 5 6function DimensionsExample() { 7 return ( 8 <View style={dimensionStyles.container}> 9 <Text>Ancho de pantalla: {SCREEN_WIDTH}px</Text> 10 <Text>Alto de pantalla: {SCREEN_HEIGHT}px</Text> 11 <View style={dimensionStyles.box} /> 12 </View> 13 ) 14} 15 16const dimensionStyles = StyleSheet.create({ 17 container: { 18 padding: 16 19 }, 20 box: { 21 width: SCREEN_WIDTH * 0.8, 22 height: 200, 23 backgroundColor: '#007AFF', 24 marginTop: 16, 25 borderRadius: 8 26 } 27}) 28 29// useWindowDimensions Hook (se actualiza con rotación) 30function ResponsiveComponent() { 31 const { width, height } = useWindowDimensions() 32 const isLandscape = width > height 33 34 return ( 35 <View style={{ padding: 16 }}> 36 <Text style={{ fontSize: 18, marginBottom: 8 }}> 37 Ancho: {width.toFixed(0)}px 38 </Text> 39 <Text style={{ fontSize: 18, marginBottom: 8 }}> 40 Alto: {height.toFixed(0)}px 41 </Text> 42 <Text style={{ fontSize: 18, fontWeight: 'bold' }}> 43 Orientación: {isLandscape ? 'Horizontal' : 'Vertical'} 44 </Text> 45 <View 46 style={{ 47 width: width * 0.9, 48 height: 150, 49 backgroundColor: isLandscape ? '#4ECDC4' : '#FF6B6B', 50 marginTop: 16, 51 borderRadius: 8, 52 justifyContent: 'center', 53 alignItems: 'center' 54 }} 55 > 56 <Text style={{ color: 'white', fontSize: 16 }}> 57 {isLandscape ? 'Modo Horizontal' : 'Modo Vertical'} 58 </Text> 59 </View> 60 </View> 61 ) 62} 63 64// Estilos con Breakpoints 65function createStyles() { 66 const { width } = Dimensions.get('window') 67 68 // Definir breakpoints 69 const isSmallDevice = width < 375 70 const isMediumDevice = width >= 375 && width < 768 71 const isLargeDevice = width >= 768 72 73 return StyleSheet.create({ 74 container: { 75 padding: isSmallDevice ? 12 : isMediumDevice ? 16 : 24, 76 backgroundColor: '#f5f5f5' 77 }, 78 title: { 79 fontSize: isSmallDevice ? 20 : isMediumDevice ? 24 : 32, 80 fontWeight: 'bold', 81 marginBottom: 16 82 }, 83 grid: { 84 flexDirection: 'row', 85 flexWrap: 'wrap', 86 gap: isSmallDevice ? 8 : 12 87 }, 88 gridItem: { 89 width: isLargeDevice ? '23%' : isMediumDevice ? '31%' : '48%', 90 aspectRatio: 1, 91 backgroundColor: '#007AFF', 92 borderRadius: 8, 93 justifyContent: 'center', 94 alignItems: 'center' 95 }, 96 columns: { 97 flexDirection: isLargeDevice ? 'row' : 'column', 98 gap: 16 99 }, 100 column: { 101 flex: isLargeDevice ? 1 : undefined, 102 padding: 16, 103 backgroundColor: 'white', 104 borderRadius: 8 105 } 106 }) 107} 108 109// Componente usando estilos responsivos 110function ResponsiveGrid() { 111 const styles = createStyles() 112 const items = Array.from({ length: 8 }, (_, i) => i + 1) 113 114 return ( 115 <View style={styles.container}> 116 <Text style={styles.title}>Grid Responsivo</Text> 117 <View style={styles.grid}> 118 {items.map((item) => ( 119 <View key={item} style={styles.gridItem}> 120 <Text style={{ color: 'white', fontSize: 20, fontWeight: 'bold' }}> 121 {item} 122 </Text> 123 </View> 124 ))} 125 </View> 126 </View> 127 ) 128}
Ejemplos de Código
4 ejemplos
Card Component
typescript
1import { View, StyleSheet } from "react-native";
2function Card() {
3 return (
4 <View style={styles.card}>
5 <View style={styles.header}>{/* Header content */}</View>
6 <View style={styles.body}>{/* Body content */}</View>
7 </View>
8 );
9}Typography
typescript
1import { Text, StyleSheet } from "react-native";
2function Typography() {
3 return (
4 <View>
5 <Text style={styles.h1}>Título Principal</Text>
6 <Text style={styles.h2}>Subtítulo</Text>
7 <Text style={styles.body}>
8 Texto normal del párrafo con <Text style={styles.bold}>negrita</Text> y <Text style={styles.link}>enlaces</Text>.
9 </Text>
10 <Text numberOfLines={2} ellipsizeMode="tail">Texto muy largo que se truncará después de dos líneas...</Text>
11 </View>
12 );
13}ResponsiveComponent
javascript
1import { Dimensions, useWindowDimensions, View, Text } from "react-native";
2function ResponsiveComponent() {
3 const { width, height } = useWindowDimensions();
4 return (
5 <View style={{ width: width * 0.9 }}>
6 <Text>Ancho: {width}px</Text>
7 <Text>Alto: {height}px</Text>
8 </View>
9 );
10}NewsApp
typescript
1import { useState } from 'react'
2import {
3 View,
4 Text,
5 Image,
6 ScrollView,
7 TouchableOpacity,
8 StyleSheet,
9 SafeAreaView,
10 useWindowDimensions
11} from 'react-native'
12
13interface Article {
14 id: number
15 title: string
16 description: string
17 imageUrl: string
18 category: string
19 date: string
20}
21
22const ARTICLES: Article[] = [
23 {
24 id: 1,
25 title: 'React Native 0.73 Lanzado',
26 description: 'Nuevas características y mejoras de rendimiento',
27 imageUrl: 'https://picsum.photos/400/200',
28 category: 'Tecnología',
29 date: '2025-12-01'
30 },
31 {
32 id: 2,
33 title: 'Guía de TypeScript para Móvil',
34 description: 'Aprende TypeScript para desarrollo móvil',
35 imageUrl: 'https://picsum.photos/400/201',
36 category: 'Desarrollo',
37 date: '2025-12-02'
38 },
39 {
40 id: 3,
41 title: 'Mejores Prácticas de UI/UX',
42 description: 'Diseña interfaces móviles intuitivas',
43 imageUrl: 'https://picsum.photos/400/202',
44 category: 'Diseño',
45 date: '2025-12-03'
46 }
47]
48
49export default function NewsApp() {
50 const [selectedCategory, setSelectedCategory] = useState('Todos')
51 const { width } = useWindowDimensions()
52 const isLargeScreen = width > 768
53
54 const categories = ['Todos', 'Tecnología', 'Desarrollo', 'Diseño']
55
56 const filteredArticles = selectedCategory === 'Todos'
57 ? ARTICLES
58 : ARTICLES.filter(article => article.category === selectedCategory)
59
60 return (
61 <SafeAreaView style={styles.container}>
62 <View style={styles.header}>
63 <Text style={styles.headerTitle}>Noticias</Text>
64 </View>
65
66 <ScrollView
67 horizontal
68 showsHorizontalScrollIndicator={false}
69 style={styles.categoriesContainer}
70 >
71 {categories.map((category) => (
72 <TouchableOpacity
73 key={category}
74 style={[
75 styles.categoryButton,
76 selectedCategory === category && styles.categoryButtonActive
77 ]}
78 onPress={() => setSelectedCategory(category)}
79 >
80 <Text
81 style={[
82 styles.categoryText,
83 selectedCategory === category && styles.categoryTextActive
84 ]}
85 >
86 {category}
87 </Text>
88 </TouchableOpacity>
89 ))}
90 </ScrollView>
91
92 <ScrollView
93 style={styles.articlesContainer}
94 contentContainerStyle={styles.articlesContent}
95 >
96 {filteredArticles.map((article) => (
97 <TouchableOpacity
98 key={article.id}
99 style={[
100 styles.articleCard,
101 isLargeScreen && styles.articleCardLarge
102 ]}
103 >
104 <Image
105 source={{ uri: article.imageUrl }}
106 style={styles.articleImage}
107 />
108 <View style={styles.articleContent}>
109 <View style={styles.articleMeta}>
110 <Text style={styles.category}>{article.category}</Text>
111 <Text style={styles.date}>{article.date}</Text>
112 </View>
113 <Text style={styles.articleTitle}>{article.title}</Text>
114 <Text style={styles.articleDescription} numberOfLines={2}>
115 {article.description}
116 </Text>
117 </View>
118 </TouchableOpacity>
119 ))}
120 </ScrollView>
121 </SafeAreaView>
122 )
123}
124
125const styles = StyleSheet.create({
126 container: {
127 flex: 1,
128 backgroundColor: '#f5f5f5'
129 },
130 header: {
131 backgroundColor: 'white',
132 padding: 20,
133 borderBottomWidth: 1,
134 borderBottomColor: '#eee'
135 },
136 headerTitle: {
137 fontSize: 32,
138 fontWeight: 'bold'
139 },
140 categoriesContainer: {
141 backgroundColor: 'white',
142 paddingVertical: 12,
143 borderBottomWidth: 1,
144 borderBottomColor: '#eee'
145 },
146 categoryButton: {
147 paddingHorizontal: 16,
148 paddingVertical: 8,
149 marginHorizontal: 8,
150 borderRadius: 20,
151 backgroundColor: '#f0f0f0'
152 },
153 categoryButtonActive: {
154 backgroundColor: '#007AFF'
155 },
156 categoryText: {
157 fontSize: 14,
158 fontWeight: '600',
159 color: '#666'
160 },
161 categoryTextActive: {
162 color: 'white'
163 },
164 articlesContainer: {
165 flex: 1
166 },
167 articlesContent: {
168 padding: 16
169 },
170 articleCard: {
171 backgroundColor: 'white',
172 borderRadius: 12,
173 marginBottom: 16,
174 shadowColor: '#000',
175 shadowOffset: { width: 0, height: 2 },
176 shadowOpacity: 0.1,
177 shadowRadius: 4,
178 elevation: 3,
179 overflow: 'hidden'
180 },
181 articleCardLarge: {
182 flexDirection: 'row'
183 },
184 articleImage: {
185 width: '100%',
186 height: 200
187 },
188 articleContent: {
189 padding: 16
190 },
191 articleMeta: {
192 flexDirection: 'row',
193 justifyContent: 'space-between',
194 marginBottom: 8
195 },
196 category: {
197 fontSize: 12,
198 color: '#007AFF',
199 fontWeight: '600'
200 },
201 date: {
202 fontSize: 12,
203 color: '#999'
204 },
205 articleTitle: {
206 fontSize: 18,
207 fontWeight: 'bold',
208 marginBottom: 8,
209 color: '#333'
210 },
211 articleDescription: {
212 fontSize: 14,
213 color: '#666',
214 lineHeight: 20
215 }
216})Recursos
1 recurso disponible
Taller Práctico
TallerPrincipiante60 min
App de Noticias Responsive
Proyecto de la Semana
Crea una app de noticias con categorías, cards y diseño responsive usando Flexbox y Dimensions.