31. Creación de MoodWeekend
Introducción
¡Bienvenidos al tutorial de creación de la sección Mood Weekend! En esta sección estaremos creando lo que es dentro de la aplicación de Music App, el Mood Weekend. Tendremos un contenedor que contendrá nuestro título de Mood Weekend y el icono que nos indica que podemos desplazarnos hacia la derecha. Eso estaremos creando en este video.
Paso 1: Estructura Actual de la Aplicación
Primero, veamos nuestro archivo App.js actual:
javascript
import React from 'react';
import {
SafeAreaView,
ScrollView,
Image,
StyleSheet,
View,
Text
} from 'react-native';
import data from './src/data';
const App = () => {
return (
<SafeAreaView style={styles.safeArea}>
<ScrollView>
{/* BANNER */}
<Image style={styles.banner} source={data.banner.img} />
</ScrollView>
</SafeAreaView>
);
};
const styles = StyleSheet.create({
safeArea: {
flex: 1,
backgroundColor: '#121212'
},
banner: {
width: '100%',
height: 200,
borderBottomLeftRadius: 50,
borderTopRightRadius: 50,
marginTop: 20
},
});
export default App;
Paso 2: Añadir la Sección Mood Weekend
Vamos a modificar nuestro App.js para incluir la sección Mood Weekend:
App.js completo actualizado:
javascript
import React from 'react';
import {
SafeAreaView,
ScrollView,
Image,
StyleSheet,
View,
Text
} from 'react-native';
import data from './src/data';
const App = () => {
return (
<SafeAreaView style={styles.safeArea}>
<ScrollView style={styles.mainScrollView}>
{/* BANNER */}
<Image style={styles.banner} source={data.banner.img} />
{/* MOOD WEEKEND SECTION */}
<View style={styles.sectionContainer}>
{/* Título e icono */}
<View style={styles.titleContainer}>
<Text style={styles.title}>{data.moodWeekend.title}</Text>
<Image
style={styles.icon}
source={data.moodWeekend.rightIcon}
/>
</View>
{/* Scroll horizontal de imágenes */}
<ScrollView
horizontal
showsHorizontalScrollIndicator={false}
style={styles.horizontalScroll}
>
{data.moodWeekend.images.map((image, index) => (
<Image
key={index}
style={styles.moodWeekendImg}
source={image.img}
/>
))}
</ScrollView>
</View>
</ScrollView>
</SafeAreaView>
);
};
const styles = StyleSheet.create({
safeArea: {
flex: 1,
backgroundColor: '#121212'
},
mainScrollView: {
flex: 1,
},
banner: {
width: '100%',
height: 200,
borderBottomLeftRadius: 50,
borderTopRightRadius: 50,
marginTop: 20
},
// Contenedor de la sección
sectionContainer: {
marginTop: 30,
marginBottom: 20,
},
// Contenedor del título (flex row con space-between)
titleContainer: {
flexDirection: 'row',
justifyContent: 'space-between',
alignItems: 'center',
marginHorizontal: 20,
marginBottom: 15,
},
// Estilo del título
title: {
fontSize: 25,
fontWeight: 'bold',
color: '#FFFFFF',
},
// Estilo del icono
icon: {
opacity: 0.5,
marginHorizontal: 5,
borderRadius: 20,
width: 30,
height: 30,
},
// Scroll horizontal
horizontalScroll: {
paddingLeft: 20,
},
// Imágenes del Mood Weekend
moodWeekendImg: {
marginHorizontal: 5,
borderRadius: 20,
width: 150,
height: 150,
marginRight: 15, // Espacio entre imágenes
},
});
export default App;
Paso 3: Explicación Detallada del Código
1. Contenedor de la Sección:
javascript
<View style={styles.sectionContainer}>
{/* Contenido Mood Weekend */}
</View>
Este View agrupa toda la sección Mood Weekend.
2. Contenedor del Título (Flex Direction Row):
javascript
<View style={styles.titleContainer}>
<Text style={styles.title}>{data.moodWeekend.title}</Text>
<Image style={styles.icon} source={data.moodWeekend.rightIcon} />
</View>
Estilos del titleContainer:
javascript
titleContainer: {
flexDirection: 'row', // Elementos en fila
justifyContent: 'space-between', // Espacio entre extremos
alignItems: 'center', // Centrado vertical
marginHorizontal: 20, // Margen horizontal
marginBottom: 15, // Margen inferior
},
3. ScrollView Horizontal:
javascript
<ScrollView
horizontal
showsHorizontalScrollIndicator={false}
style={styles.horizontalScroll}
>
{/* Contenido del scroll */}
</ScrollView>
horizontal={true}: Hace el scroll horizontal
showsHorizontalScrollIndicator={false}: Oculta la barra de scroll
4. Mapeo de Imágenes:
javascript
{data.moodWeekend.images.map((image, index) => (
<Image
key={index}
style={styles.moodWeekendImg}
source={image.img}
/>
))}
map(): Itera sobre el array de imágenes
key={index}: Identificador único requerido por React Native
source={image.img}: Fuente de la imagen desde nuestro data.js
Paso 4: Versión Mejorada con Más Funcionalidades
App.js versión mejorada:
javascript
import React from 'react';
import {
SafeAreaView,
ScrollView,
Image,
StyleSheet,
View,
Text,
TouchableOpacity,
Dimensions
} from 'react-native';
import data from './src/data';
const { width } = Dimensions.get('window');
const App = () => {
const handleMoodPress = (mood) => {
console.log('Mood seleccionado:', mood.title);
// Aquí podrías navegar a una pantalla de playlist
};
const handleViewAll = () => {
console.log('Ver todos los moods');
// Navegación a pantalla completa
};
return (
<SafeAreaView style={styles.safeArea}>
<ScrollView
style={styles.mainScrollView}
showsVerticalScrollIndicator={false}
>
{/* BANNER */}
<Image
style={styles.banner}
source={data.banner.img}
resizeMode="cover"
/>
{/* MOOD WEEKEND SECTION */}
<View style={styles.sectionContainer}>
{/* Encabezado con título e icono */}
<View style={styles.headerContainer}>
<Text style={styles.sectionTitle}>{data.moodWeekend.title}</Text>
<TouchableOpacity
style={styles.viewAllButton}
onPress={handleViewAll}
>
<Text style={styles.viewAllText}>Ver todo</Text>
<Image
style={styles.arrowIcon}
source={data.moodWeekend.rightIcon}
/>
</TouchableOpacity>
</View>
<Text style={styles.sectionDescription}>
Playlists para cada estado de ánimo
</Text>
{/* Scroll horizontal de moods */}
<ScrollView
horizontal
showsHorizontalScrollIndicator={false}
style={styles.horizontalScroll}
contentContainerStyle={styles.scrollContent}
>
{data.moodWeekend.images.map((mood, index) => (
<TouchableOpacity
key={index}
style={styles.moodCard}
onPress={() => handleMoodPress(mood)}
activeOpacity={0.7}
>
<Image
style={styles.moodImage}
source={mood.img}
resizeMode="cover"
/>
<View style={styles.moodOverlay}>
<Text style={styles.moodTitle}>{mood.title}</Text>
<Text style={styles.moodSubtitle}>50+ canciones</Text>
</View>
</TouchableOpacity>
))}
</ScrollView>
</View>
</ScrollView>
</SafeAreaView>
);
};
const styles = StyleSheet.create({
safeArea: {
flex: 1,
backgroundColor: '#121212'
},
mainScrollView: {
flex: 1,
},
banner: {
width: '100%',
height: 200,
borderBottomLeftRadius: 50,
borderTopRightRadius: 50,
marginTop: 20
},
// Contenedor de la sección
sectionContainer: {
marginTop: 30,
marginBottom: 30,
},
// Encabezado de la sección
headerContainer: {
flexDirection: 'row',
justifyContent: 'space-between',
alignItems: 'center',
marginHorizontal: 20,
marginBottom: 8,
},
sectionTitle: {
fontSize: 26,
fontWeight: '800',
color: '#FFFFFF',
letterSpacing: 0.5,
},
// Botón "Ver todo"
viewAllButton: {
flexDirection: 'row',
alignItems: 'center',
paddingVertical: 5,
paddingHorizontal: 10,
borderRadius: 15,
backgroundColor: 'rgba(255, 255, 255, 0.1)',
},
viewAllText: {
fontSize: 14,
color: '#B3B3B3',
marginRight: 5,
},
arrowIcon: {
width: 20,
height: 20,
tintColor: '#1DB954',
opacity: 0.8,
},
sectionDescription: {
fontSize: 14,
color: '#B3B3B3',
marginHorizontal: 20,
marginBottom: 20,
},
// Scroll horizontal
horizontalScroll: {
paddingLeft: 20,
},
scrollContent: {
paddingRight: 20,
},
// Tarjeta de mood
moodCard: {
width: 160,
marginRight: 15,
borderRadius: 20,
overflow: 'hidden',
backgroundColor: '#1E1E1E',
elevation: 5,
shadowColor: '#000',
shadowOffset: { width: 0, height: 2 },
shadowOpacity: 0.3,
shadowRadius: 4,
},
moodImage: {
width: '100%',
height: 160,
},
moodOverlay: {
position: 'absolute',
bottom: 0,
left: 0,
right: 0,
backgroundColor: 'rgba(0, 0, 0, 0.7)',
padding: 12,
borderBottomLeftRadius: 20,
borderBottomRightRadius: 20,
},
moodTitle: {
fontSize: 16,
fontWeight: '600',
color: '#FFFFFF',
marginBottom: 3,
},
moodSubtitle: {
fontSize: 12,
color: 'rgba(255, 255, 255, 0.7)',
},
});
export default App;
Paso 5: Versión con FlatList (Más Eficiente)
Para mejor rendimiento con muchas imágenes:
javascript
import React from 'react';
import {
SafeAreaView,
ScrollView,
FlatList,
Image,
StyleSheet,
View,
Text,
TouchableOpacity
} from 'react-native';
import data from './src/data';
const App = () => {
// Render item para FlatList
const renderMoodItem = ({ item, index }) => (
<TouchableOpacity
style={styles.moodItem}
activeOpacity={0.7}
>
<Image
style={styles.moodImage}
source={item.img}
resizeMode="cover"
/>
<View style={styles.moodLabel}>
<Text style={styles.moodText}>{item.title}</Text>
</View>
</TouchableOpacity>
);
return (
<SafeAreaView style={styles.safeArea}>
<ScrollView style={styles.mainScrollView}>
{/* BANNER */}
<Image style={styles.banner} source={data.banner.img} />
{/* MOOD WEEKEND CON FLATLIST */}
<View style={styles.sectionContainer}>
<View style={styles.titleContainer}>
<Text style={styles.title}>{data.moodWeekend.title}</Text>
<Image
style={styles.icon}
source={data.moodWeekend.rightIcon}
/>
</View>
<FlatList
data={data.moodWeekend.images}
renderItem={renderMoodItem}
keyExtractor={(item, index) => index.toString()}
horizontal
showsHorizontalScrollIndicator={false}
contentContainerStyle={styles.flatListContent}
/>
</View>
</ScrollView>
</SafeAreaView>
);
};
const styles = StyleSheet.create({
safeArea: {
flex: 1,
backgroundColor: '#121212'
},
mainScrollView: {
flex: 1,
},
banner: {
width: '100%',
height: 200,
borderBottomLeftRadius: 50,
borderTopRightRadius: 50,
marginTop: 20
},
sectionContainer: {
marginTop: 30,
marginBottom: 20,
},
titleContainer: {
flexDirection: 'row',
justifyContent: 'space-between',
alignItems: 'center',
marginHorizontal: 20,
marginBottom: 15,
},
title: {
fontSize: 25,
fontWeight: 'bold',
color: '#FFFFFF',
},
icon: {
opacity: 0.5,
marginHorizontal: 5,
borderRadius: 20,
width: 30,
height: 30,
},
flatListContent: {
paddingLeft: 20,
paddingRight: 10,
},
moodItem: {
marginRight: 15,
borderRadius: 20,
overflow: 'hidden',
},
moodImage: {
width: 150,
height: 150,
borderRadius: 20,
},
moodLabel: {
position: 'absolute',
bottom: 0,
left: 0,
right: 0,
backgroundColor: 'rgba(0, 0, 0, 0.5)',
padding: 10,
borderBottomLeftRadius: 20,
borderBottomRightRadius: 20,
},
moodText: {
color: '#FFFFFF',
fontSize: 14,
fontWeight: '600',
textAlign: 'center',
},
});
export default App;
Paso 6: Explicación de Estilos y Propiedades
flexDirection: 'row'
javascript
flexDirection: 'row'
Organiza los elementos hijos en una fila horizontal
Por defecto es 'column' (vertical)
justifyContent: 'space-between'
javascript
justifyContent: 'space-between'
Distribuye el espacio sobrante entre los elementos
El primer elemento al inicio, el último al final
Otros valores: 'flex-start', 'flex-end', 'center', 'space-around', 'space-evenly'
alignItems: 'center'
javascript
alignItems: 'center'
Alinea los elementos verticalmente al centro
Importante cuando los elementos tienen diferentes alturas
Margin y Padding
javascript
marginHorizontal: 20 // Margen izquierdo y derecho
marginVertical: 10 // Margen superior e inferior
padding: 15 // Padding en todos los lados
Paso 7: Data.js Actualizado para Mood Weekend
src/data.js (actualizado):
javascript
const data = {
banner: {
img: require('./images/banner.png'),
title: "Descubre nueva música",
subtitle: "Explora miles de canciones y álbumes"
},
moodWeekend: {
title: "Mood Weekend",
rightIcon: require('./images/right-arrow.png'),
images: [
{
id: 1,
img: require('./images/moodweekend/1.png'),
title: "Relax",
color: "#667eea",
songCount: 45
},
{
id: 2,
img: require('./images/moodweekend/2.png'),
title: "Energía",
color: "#f093fb",
songCount: 38
},
{
id: 3,
img: require('./images/moodweekend/3.png'),
title: "Nostalgia",
color: "#f5576c",
songCount: 52
},
{
id: 4,
img: require('./images/moodweekend/4.png'),
title: "Felicidad",
color: "#4facfe",
songCount: 41
},
{
id: 5,
img: require('./images/moodweekend/5.png'),
title: "Concentración",
color: "#43e97b",
songCount: 36
},
{
id: 6,
img: require('./images/moodweekend/6.png'),
title: "Fiesta",
color: "#fa709a",
songCount: 48
}
]
},
// ... otras secciones
};
export default data;
Paso 8: Solución de Problemas Comunes
Problema 1: Las imágenes no se muestran
javascript
// Verificar que las rutas sean correctas
console.log(data.moodWeekend.images[0].img);
// Verificar que las imágenes existan
// Las imágenes deben estar en:
// src/images/moodweekend/1.png
// src/images/moodweekend/2.png
// etc.
Problema 2: Error "Each child in a list should have a unique key"
javascript
// Siempre agregar key a elementos en map()
{data.moodWeekend.images.map((image, index) => (
<Image
key={index} // <-- Esto es necesario
style={styles.moodWeekendImg}
source={image.img}
/>
))}
Problema 3: Scroll horizontal no funciona
javascript
// Asegurar que el ScrollView tenga suficiente contenido
// Verificar que las imágenes tengan dimensiones adecuadas
// Probar con menos margen entre imágenes
Problema 4: Las imágenes se ven pixeladas
javascript
// Usar imágenes de alta resolución
// Especificar dimensiones exactas
moodWeekendImg: {
width: 150, // Ancho fijo
height: 150, // Alto fijo
// ...
}
Paso 9: Prueba y Verificación
Ejecutar la aplicación:
bash
npm run android
# o
npm run ios
Verificar que:
✅ El título "Mood Weekend" se muestra
✅ El icono de flecha aparece a la derecha
✅ Las imágenes se muestran en scroll horizontal
✅ Se puede deslizar hacia los lados
✅ Cada imagen tiene bordes redondeados
Probar diferentes configuraciones:
Cambiar el tamaño de las imágenes
Modificar los márgenes
Probar con más o menos imágenes
Resumen del Proceso
Hemos creado exitosamente la sección Mood Weekend:
✅ Contenedor del título con flexDirection: 'row' y justifyContent: 'space-between'
✅ Texto del título importado desde data.js
✅ Icono de flecha para indicar scroll horizontal
✅ ScrollView horizontal para las imágenes
✅ Mapeo de imágenes desde nuestro archivo de datos
✅ Estilos personalizados para cada elemento
✅ Bordes redondeados y márgenes adecuados
Resultado Final
Tu aplicación debería mostrar:
Un banner en la parte superior
La sección "Mood Weekend" con título e icono
Una fila horizontal de imágenes con estados de ánimo
Scroll horizontal funcional
Diseño atractivo con bordes redondeados
Próximos Pasos
En el próximo video crearemos:
✅ Sección "Top Albums" con diseño similar
✅ Mejoras en la interfaz de usuario
✅ Funcionalidad de reproducción básica
✅ Navegación entre secciones
¡Guardamos los cambios y nos vemos en el próximo tutorial! 🎵
javascript
// Resumen del código esencial para Mood Weekend
{/* Mood Weekend Section */}
<View style={styles.sectionContainer}>
{/* Title and Icon */}
<View style={styles.titleContainer}>
<Text style={styles.title}>{data.moodWeekend.title}</Text>
<Image style={styles.icon} source={data.moodWeekend.rightIcon} />
</View>
{/* Horizontal Images Scroll */}
<ScrollView horizontal showsHorizontalScrollIndicator={false}>
{data.moodWeekend.images.map((image, index) => (
<Image
key={index}
style={styles.moodWeekendImg}
source={image.img}
/>
))}
</ScrollView>
</View>
Comentarios
Publicar un comentario