30. Creación de Banner

Introducción

¡Hola a todos! En este video vamos a crear el banner principal de nuestra aplicación de música. Este será el primer elemento visual que los usuarios verán al abrir la app, por lo que debe ser atractivo y funcional.

Paso 1: Preparación del Entorno

Primero, asegurémonos de que tenemos nuestra estructura base:

Estructura actual:

text

MusicApp/

├── src/

│   ├── data.js

│   └── images/

│       └── banner.png

├── App.js

└── package.json

Paso 2: Verificar data.js

Asegurémonos que nuestro archivo data.js esté correctamente configurado:

src/data.js

javascript

// Exportación por defecto de nuestra constante data

const data = {

  banner: {

    img: require('./images/banner.png'),

    title: "Descubre nueva música",

    subtitle: "Explora miles de canciones y álbumes"

  },

  // ... otras secciones

};


export default data;  // Export por defecto

Paso 3: Iniciar la Aplicación

Antes de comenzar, iniciamos nuestra aplicación:

bash

npm run android

O para iOS:

bash

npm run ios

Paso 4: Crear el Componente Banner en App.js

Vamos a modificar nuestro archivo principal App.js:

App.js completo:

javascript

import React from 'react';

import { 

  SafeAreaView, 

  ScrollView, 

  Image, 

  StyleSheet,

  View,

  Text,

  TouchableOpacity 

} from 'react-native';


// Importamos nuestros datos

import data from './src/data';


const App = () => {

  return (

    <SafeAreaView style={styles.safeArea}>

      {/* ScrollView para permitir desplazamiento */}

      <ScrollView style={styles.scrollView} showsVerticalScrollIndicator={false}>

        

        {/* BANNER PRINCIPAL */}

        <View style={styles.bannerContainer}>

          <Image 

            style={styles.banner} 

            source={data.banner.img} 

            resizeMode="cover"

          />

          

          {/* Overlay con texto sobre el banner */}

          <View style={styles.bannerOverlay}>

            <Text style={styles.bannerTitle}>{data.banner.title}</Text>

            <Text style={styles.bannerSubtitle}>{data.banner.subtitle}</Text>

            

            {/* Botón de acción */}

            <TouchableOpacity style={styles.bannerButton}>

              <Text style={styles.bannerButtonText}>Comenzar ahora</Text>

            </TouchableOpacity>

          </View>

        </View>

        

        {/* Espacio para contenido futuro */}

        <View style={styles.contentPlaceholder}>

          <Text style={styles.placeholderText}>

            ¡Contenido próximo! En el siguiente video agregaremos Mood Weekend

          </Text>

        </View>

        

      </ScrollView>

    </SafeAreaView>

  );

};


// Creación de estilos

const styles = StyleSheet.create({

  safeArea: {

    flex: 1,

    backgroundColor: '#121212',

  },

  scrollView: {

    flex: 1,

  },

  

  // Contenedor del banner

  bannerContainer: {

    marginHorizontal: 20,

    marginTop: 20,

    marginBottom: 30,

    borderRadius: 30,

    overflow: 'hidden',

    position: 'relative',

    elevation: 8, // Sombra para Android

    shadowColor: '#000', // Sombra para iOS

    shadowOffset: { width: 0, height: 4 },

    shadowOpacity: 0.3,

    shadowRadius: 5,

  },

  

  // Estilos para la imagen del banner

  banner: {

    width: '100%',

    height: 200,

    borderBottomLeftRadius: 50,

    borderTopRightRadius: 50,

  },

  

  // Overlay semitransparente sobre la imagen

  bannerOverlay: {

    position: 'absolute',

    bottom: 0,

    left: 0,

    right: 0,

    backgroundColor: 'rgba(0, 0, 0, 0.6)',

    padding: 25,

    paddingTop: 40, // Más espacio arriba

    borderTopLeftRadius: 30,

    borderBottomRightRadius: 50,

  },

  

  // Título del banner

  bannerTitle: {

    fontSize: 26,

    fontWeight: 'bold',

    color: '#FFFFFF',

    marginBottom: 8,

    textShadowColor: 'rgba(0, 0, 0, 0.75)',

    textShadowOffset: { width: 1, height: 1 },

    textShadowRadius: 3,

  },

  

  // Subtítulo del banner

  bannerSubtitle: {

    fontSize: 16,

    color: 'rgba(255, 255, 255, 0.9)',

    marginBottom: 20,

    lineHeight: 22,

  },

  

  // Botón del banner

  bannerButton: {

    backgroundColor: '#1DB954',

    paddingVertical: 12,

    paddingHorizontal: 25,

    borderRadius: 25,

    alignSelf: 'flex-start',

    marginTop: 10,

    elevation: 5,

    shadowColor: '#1DB954',

    shadowOffset: { width: 0, height: 2 },

    shadowOpacity: 0.3,

    shadowRadius: 3,

  },

  

  bannerButtonText: {

    color: '#FFFFFF',

    fontSize: 16,

    fontWeight: '600',

    textAlign: 'center',

  },

  

  // Placeholder para contenido futuro

  contentPlaceholder: {

    marginHorizontal: 20,

    padding: 25,

    backgroundColor: '#1E1E1E',

    borderRadius: 15,

    alignItems: 'center',

    marginBottom: 30,

  },

  

  placeholderText: {

    color: '#B3B3B3',

    fontSize: 16,

    textAlign: 'center',

    lineHeight: 24,

  },

});


export default App;

Paso 5: Versión Mejorada con Gradientes y Efectos

Si quieres un banner más avanzado, aquí tienes una versión con gradientes:

App.js con gradiente (requiere librería adicional):

javascript

import React from 'react';

import { 

  SafeAreaView, 

  ScrollView, 

  ImageBackground, 

  StyleSheet,

  View,

  Text,

  TouchableOpacity 

} from 'react-native';

import LinearGradient from 'react-native-linear-gradient'; // npm install react-native-linear-gradient


import data from './src/data';


const App = () => {

  return (

    <SafeAreaView style={styles.safeArea}>

      <ScrollView style={styles.scrollView} showsVerticalScrollIndicator={false}>

        

        {/* BANNER CON GRADIENTE */}

        <ImageBackground 

          source={data.banner.img} 

          style={styles.banner}

          imageStyle={styles.bannerImage}

        >

          <LinearGradient

            colors={['rgba(0,0,0,0.1)', 'rgba(0,0,0,0.8)']}

            style={styles.gradientOverlay}

            start={{ x: 0, y: 0 }}

            end={{ x: 0, y: 1 }}

          >

            <View style={styles.bannerContent}>

              <Text style={styles.bannerTitle}>{data.banner.title}</Text>

              <Text style={styles.bannerSubtitle}>{data.banner.subtitle}</Text>

              

              <TouchableOpacity style={styles.bannerButton}>

                <LinearGradient

                  colors={['#1DB954', '#1ED760']}

                  style={styles.buttonGradient}

                  start={{ x: 0, y: 0 }}

                  end={{ x: 1, y: 0 }}

                >

                  <Text style={styles.bannerButtonText}>🎵 Comenzar ahora</Text>

                </LinearGradient>

              </TouchableOpacity>

            </View>

          </LinearGradient>

        </ImageBackground>

        

      </ScrollView>

    </SafeAreaView>

  );

};


const styles = StyleSheet.create({

  safeArea: {

    flex: 1,

    backgroundColor: '#121212',

  },

  scrollView: {

    flex: 1,

  },

  banner: {

    height: 250,

    margin: 20,

    borderRadius: 30,

    overflow: 'hidden',

    elevation: 10,

    shadowColor: '#000',

    shadowOffset: { width: 0, height: 5 },

    shadowOpacity: 0.4,

    shadowRadius: 8,

  },

  bannerImage: {

    borderRadius: 30,

  },

  gradientOverlay: {

    flex: 1,

    justifyContent: 'flex-end',

    padding: 25,

  },

  bannerContent: {

    alignItems: 'flex-start',

  },

  bannerTitle: {

    fontSize: 28,

    fontWeight: '800',

    color: '#FFFFFF',

    marginBottom: 10,

    textShadowColor: 'rgba(0, 0, 0, 0.5)',

    textShadowOffset: { width: 1, height: 2 },

    textShadowRadius: 3,

  },

  bannerSubtitle: {

    fontSize: 16,

    color: 'rgba(255, 255, 255, 0.9)',

    marginBottom: 25,

    lineHeight: 22,

    maxWidth: '80%',

  },

  bannerButton: {

    borderRadius: 30,

    overflow: 'hidden',

    elevation: 5,

    shadowColor: '#1DB954',

    shadowOffset: { width: 0, height: 3 },

    shadowOpacity: 0.3,

    shadowRadius: 5,

  },

  buttonGradient: {

    paddingVertical: 14,

    paddingHorizontal: 30,

    borderRadius: 30,

  },

  bannerButtonText: {

    color: '#FFFFFF',

    fontSize: 16,

    fontWeight: '700',

    textAlign: 'center',

  },

});


export default App;

Paso 6: Versión Simple (Como en el ejemplo)

App.js versión simple:

javascript

import React from 'react';

import { 

  SafeAreaView, 

  ScrollView, 

  Image, 

  StyleSheet 

} 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 7: Explicación Detallada del Código

1. Importaciones necesarias:

javascript

import { 

  SafeAreaView,  // Evoca áreas seguras del dispositivo

  ScrollView,    // Permite desplazamiento vertical

  Image,         // Componente para mostrar imágenes

  StyleSheet     // Para crear estilos

} from 'react-native';

2. SafeAreaView:

  • Asegura que el contenido no se superponga con notch, barras de estado, etc.

  • Especialmente importante en dispositivos con pantallas con muescas

3. ScrollView:

  • Permite hacer scroll cuando el contenido excede la pantalla

  • showsVerticalScrollIndicator={false} oculta la barra de scroll

4. Image y source:

javascript

<Image 

  style={styles.banner} 

  source={data.banner.img} 

/>

  • source: Propiedad que define la fuente de la imagen

  • Usamos data.banner.img que importamos desde nuestro archivo de datos

5. StyleSheet.create:

javascript

const styles = StyleSheet.create({

  // Estilos aquí

});

  • Método optimizado para crear estilos en React Native

  • Mejor rendimiento que objetos de estilo inline

6. Estilos del banner:

javascript

banner: {

  width: '100%',          // Ocupa todo el ancho disponible

  height: 200,            // Altura fija de 200 unidades

  borderBottomLeftRadius: 50,   // Radio esquina inferior izquierda

  borderTopRightRadius: 50,     // Radio esquina superior derecha

}

Paso 8: Mejoras y Optimizaciones

1. Optimización de imágenes:

javascript

// Usar resizeMode para controlar cómo se ajusta la imagen

<Image 

  style={styles.banner} 

  source={data.banner.img}

  resizeMode="cover"  // "cover", "contain", "stretch", "repeat", "center"

/>

2. Añadir efecto de carga:

javascript

// Estado para controlar carga de imagen

const [imageLoaded, setImageLoaded] = React.useState(false);


<Image 

  style={styles.banner} 

  source={data.banner.img}

  onLoad={() => setImageLoaded(true)}

  onError={(error) => console.log('Error loading image:', error)}

/>

3. Banner responsivo:

javascript

import { Dimensions } from 'react-native';


const { width } = Dimensions.get('window');


const styles = StyleSheet.create({

  banner: {

    width: width - 40, // Ancho menos márgenes

    height: width * 0.5, // Altura proporcional al ancho

    marginHorizontal: 20,

    // ... otros estilos

  },

});

Paso 9: Solución de Problemas Comunes

Problema 1: Imagen no se muestra

javascript

// Verificar que la ruta sea correcta

console.log(data.banner.img); // Debería mostrar un número (el require)


// Verificar que la imagen exista en la ruta especificada

Problema 2: Bordes redondeados no funcionan

javascript

// Asegurar que el contenedor tenga overflow: 'hidden'

bannerContainer: {

  overflow: 'hidden',

  borderRadius: 30,

}

Problema 3: Imagen pixelada

javascript

// Usar imágenes con resolución adecuada

// Para @2x y @3x screens:

// banner.png (1x)

// banner@2x.png (2x)

// banner@3x.png (3x)


// O especificar dimensiones exactas

banner: {

  width: 375, // Ancho exacto

  height: 200,

}

Paso 10: Prueba y Verificación

  1. Guardar los cambios: Ctrl + S (Windows/Linux) o Cmd + S (Mac)

  2. Ver en el emulador/dispositivo: La imagen del banner debería aparecer

  3. Probar diferentes estilos: Modifica los valores de borderRadius y height

  4. Verificar en diferentes dispositivos: Asegura que se vea bien en todas las pantallas

Resumen del Proceso

Hemos creado un banner atractivo para nuestra aplicación de música:

  1. ✅ Importamos los componentes necesarios de React Native

  2. ✅ Creamos la estructura con SafeAreaView y ScrollView

  3. ✅ Importamos nuestros datos desde data.js

  4. ✅ Implementamos la imagen del banner con estilos personalizados

  5. ✅ Aplicamos bordes redondeados para un diseño moderno

  6. ✅ Probamos la aplicación y verificamos que todo funcione

Resultado Final

Tu aplicación debería mostrar:

  • Un banner con imagen atractiva

  • Bordes redondeados asimétricos (50 en esquinas opuestas)

  • Diseño que ocupa todo el ancho de la pantalla

  • Scroll vertical disponible

Próximos Pasos

En el próximo video agregaremos:

  • ✅ Sección Mood Weekend con scroll horizontal

  • ✅ Tarjetas de estados de ánimo

  • ✅ Iconos de navegación

  • ✅ Más estilos y funcionalidades

¡Guardamos los cambios y nos vemos en el próximo tutorial! 🎵

javascript

// Resumen del código esencial

import React from 'react';

import { SafeAreaView, ScrollView, Image, StyleSheet } from 'react-native';

import data from './src/data';


const App = () => {

  return (

    <SafeAreaView style={styles.safeArea}>

      <ScrollView>

        <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 

  },

});


export default App;


Comentarios

Entradas más populares de este blog

18. Visualizar nuestros componentes limpios con StyleSheet

15. Componente Image

Tema: 23. Justify Content en Flexbox para Column (Columna) en React Nativ