Bienvenido, les saluda Luis y para hoy les traigo este nuevo artículo.
Índice
Encabezado de animación suave
Hoy en día, el encabezado animado es el patrón de diseño más común en las aplicaciones actuales. Las animaciones son una parte importante de las aplicaciones móviles.
Por lo tanto, quería usar un encabezado animado increíble en mi aplicación React Native.
Decidí escribir este breve artículo para mostrar cómo crear un encabezado animado con ScrollView
y API animada. Hagámoslo juntos.
Encabezado animado final
Si desea verificar todo el código, aquí está el enlace a Github.
Configurar el proyecto
Creemos un nuevo proyecto de React Native llamado react_native_scrollable_animated_header
:
react-native init react_native_scrollable_animated_header cd react_native_scrollable_animated_header npm ejecutar ios
Ahora, hemos creado con éxito nuestro proyecto React Native. ¡Estamos listos para codificar!
Haciendo código mágico
Primero, necesitamos definir algunas constantes para el encabezado animado que se usarán para interpolar el valor de la posición de desplazamiento.
const HEADER_MAX_HEIGHT = 240; const HEADER_MIN_HEIGHT = 84; const HEADER_SCROLL_DISTANCE = HEADER_MAX_HEIGHT - HEADER_MIN_HEIGHT;
Voy a utilizar faker.js
para generar datos de usuario para ScrollView
. Faker.js
es una gran biblioteca para generar datos falsos. Debe instalarlo mediante la siguiente línea de comando:
npm install faker --save
A continuación, mostraré los datos del usuario con ScrollView component
. Entonces deberíamos cambiar el archivo App.js
de esta manera:
const HEADER_MAX_HEIGHT = 240; // altura máxima del encabezado const HEADER_MIN_HEIGHT = 84; // altura mínima del encabezado const HEADER_SCROLL_DISTANCE = HEADER_MAX_HEIGHT - HEADER_MIN_HEIGHT; // valor de desplazamiento del encabezado // crea una matriz con 10 datos de usuario falsos const DATA = Matriz (10) .fill (nulo) .map ((_, idx) => ({ id: idx, avatar: faker.image.avatar (), fullName: `$ {faker.name.firstName ()} $ {faker.name.lastName ()}`, })); función App () { const renderListItem = (elemento) => ( <Ver clave = {item.id} style = {styles.card}> <Image style = {styles.avatar} source = {{uri: item.avatar}} /> <Text style = {styles.fullNameText}> {item.fullName} </Text> </View> ); regreso ( <SafeAreaView style = {styles.saveArea}> <ScrollView contentContainerStyle = {{paddingTop: HEADER_MAX_HEIGHT - 32}}> // debe estar debajo del encabezado {DATA.map (renderListItem)} </ScrollView> </SafeAreaView> ); }
Después de eso, necesitamos crear el encabezado debajo del ScrollView
. Usaremos Animated.View
. Eventualmente, estará animado.
<Animated.View estilo = {[ styles.topBar, { transform: [{scale: titleScale}, {translateY: titleTranslateY}], }, ]}> <Text style = {styles.title}> Gestión </Text> </Animated.View>
Animación mágica
React Native proporciona API animada para animaciones. La API animada se centra en las relaciones declarativas entre las entradas y las salidas, con transformaciones configurables intermedias y métodos de inicio / parada para controlar la ejecución de la animación basada en el tiempo.
Vamos a usar Animated.ScrollView
para hacer la vista de desplazamiento y adjuntar una devolución de llamada para escuchar onScroll
evento cuando se cambia.
Luego, usando la interpolación para mapear el valor entre el eje y y la opacidad. The interpolation
mapea los rangos de entrada a los rangos de salida, normalmente utilizando una interpolación lineal, pero también admite funciones de aceleración.
Actualicemos nuestro archivo App.js
con las siguientes líneas de código:
const scrollY = useRef (nuevo Animated.Value (0)). current; // nuestro valor animado // nuestro eje y de encabezado animado de 0 a HEADER_SCROLL_DISTANCE, // movemos nuestro elemento para -HEADER_SCROLL_DISTANCE al mismo tiempo. const headerTranslateY = scrollY.interpolate ({ inputRange: [0, HEADER_SCROLL_DISTANCE], outputRange: [0, -HEADER_SCROLL_DISTANCE], extrapolar: 'abrazadera', }); // nuestra opacidad animada de 0 a 1 y nuestra opacidad será 0 const imageOpacity = scrollY.interpolate ({ inputRange: [0, HEADER_SCROLL_DISTANCE / 2, HEADER_SCROLL_DISTANCE], outputRange: [1, 1, 0], extrapolar: 'abrazadera', }); const imageTranslateY = scrollY.interpolate ({ inputRange: [0, HEADER_SCROLL_DISTANCE], outputRange: [0, 100], extrapolar: 'abrazadera', }); // cambia el tamaño del título del encabezado de 1 a 0,9 const titleScale = scrollY.interpolate ({ inputRange: [0, HEADER_SCROLL_DISTANCE / 2, HEADER_SCROLL_DISTANCE], outputRange: [1, 1, 0.9], extrapolar: 'abrazadera', }); // cambiar el título del encabezado en el eje y const titleTranslateY = scrollY.interpolate ({ inputRange: [0, HEADER_SCROLL_DISTANCE / 2, HEADER_SCROLL_DISTANCE], outputRange: [0, 0, -8], extrapolar: 'abrazadera', });
Arriba, usamos useRef
para conservar el valor animado. useRef
devuelve un objeto ref mutable cuyo .current
La propiedad se inicializa con el argumento pasado.
A continuación, necesitamos actualizar el valor animado cuando nos desplazamos ScrollView
. Atraparemos el evento por Animated.event
.
Se asigna directamente al valor animado scrollY
y actualizarlo cuando estemos desplazándonos o desplazándonos.
Podemos usar el controlador nativo especificando useNativeDriver: true
en nuestra configuración de animación.
Animamos nuestros componentes con los siguientes códigos:
<SafeAreaView style = {styles.saveArea}> <Animated.ScrollView contentContainerStyle = {{paddingTop: HEADER_MAX_HEIGHT - 32}} scrollEventThrottle = {16} // onScroll = {Animated.event ( [{nativeEvent: {contentOffset: {y: scrollY}}}], // event.nativeEvent.contentOffset.x a scrollX {useNativeDriver: true}, // usa el controlador nativo para la animación )}> {DATA.map (renderListItem)} </Animated.ScrollView> <Animated.View style = {[styles.header, {transform: [{translateY: headerTranslateY}]}]}> <Imagen animada estilo = {[ styles.headerBackground, { opacidad: imageOpacity, transformar: [{translateY: imageTranslateY}], }, ]} source = {require ('./ assets / management.jpg')} /> </Animated.View> <Animated.View estilo = {[ styles.topBar, { transform: [{scale: titleScale}, {translateY: titleTranslateY}], }, ]}> <Text style = {styles.title}> Gestión </Text> </Animated.View> </SafeAreaView>
Además, configuramos el scrollEventThrottle
prop
a 16
, por lo que los eventos se envían con la frecuencia suficiente para tener una animación fluida.
Finalmente, nuestro App.js
:
importar React, {useRef} de 'reaccionar'; importar { SafeAreaView, StyleSheet, Imagen, Vista, Texto, Animado, } de 'react-native'; importar faker de 'faker'; const HEADER_MAX_HEIGHT = 240; const HEADER_MIN_HEIGHT = 84; const HEADER_SCROLL_DISTANCE = HEADER_MAX_HEIGHT - HEADER_MIN_HEIGHT; const DATA = Matriz (10) .fill (nulo) .map ((_, idx) => ({ id: idx, avatar: faker.image.avatar (), fullName: `$ {faker.name.firstName ()} $ {faker.name.lastName ()}`, })); función App () { const scrollY = useRef (nuevo Animated.Value (0)). current; const headerTranslateY = scrollY.interpolate ({ inputRange: [0, HEADER_SCROLL_DISTANCE], outputRange: [0, -HEADER_SCROLL_DISTANCE], extrapolar: 'abrazadera', }); const imageOpacity = scrollY.interpolate ({ inputRange: [0, HEADER_SCROLL_DISTANCE / 2, HEADER_SCROLL_DISTANCE], outputRange: [1, 1, 0], extrapolar: 'abrazadera', }); const imageTranslateY = scrollY.interpolate ({ inputRange: [0, HEADER_SCROLL_DISTANCE], outputRange: [0, 100], extrapolar: 'abrazadera', }); const titleScale = scrollY.interpolate ({ inputRange: [0, HEADER_SCROLL_DISTANCE / 2, HEADER_SCROLL_DISTANCE], outputRange: [1, 1, 0.9], extrapolar: 'abrazadera', }); const titleTranslateY = scrollY.interpolate ({ inputRange: [0, HEADER_SCROLL_DISTANCE / 2, HEADER_SCROLL_DISTANCE], outputRange: [0, 0, -8], extrapolar: 'abrazadera', }); const renderListItem = (elemento) => ( <Ver clave = {item.id} style = {styles.card}> <Image style = {styles.avatar} source = {{uri: item.avatar}} /> <Text style = {styles.fullNameText}> {item.fullName} </Text> </View> ); regreso ( <SafeAreaView style = {styles.saveArea}> <Animated.ScrollView contentContainerStyle = {{paddingTop: HEADER_MAX_HEIGHT - 32}} scrollEventThrottle = {16} onScroll = {Animated.event ( [{ nativeEvent: { contentOffset: { y: scrollY } } }], {useNativeDriver: true}, )}> {DATA.map (renderListItem)} </Animated.ScrollView> <Animated.View style = {[styles.header, {transform: [{translateY: headerTranslateY}]}]}> <Imagen animada estilo = {[ styles.headerBackground, { opacidad: imageOpacity, transformar: [{translateY: imageTranslateY}], }, ]} source = {require ('./ assets / management.jpg')} /> </Animated.View> <Animated.View estilo = {[ styles.topBar, { transform: [{scale: titleScale}, {translateY: titleTranslateY}], }, ]}> <Text style = {styles.title}> Gestión </Text> </Animated.View> </SafeAreaView> ); } const styles = StyleSheet.create ({ saveArea: { flexión: 1, backgroundColor: '# eff3fb', }, tarjeta: { flexDirection: 'fila', alignItems: 'centro', shadowColor: '# 402583', backgroundColor: '#ffffff', shadowOffset: { ancho: 0, altura: 0, }, shadowOpacity: 0.1, shadowRadius: 6, elevación: 1, borderRadius: 10, marginHorizontal: 12, marginTop: 12, acolchado Horizontal: 16, acolchado Vertical: 12, }, encabezado: { posición: 'absoluta', arriba: 0, izquierda: 0, derecha: 0, backgroundColor: '# 62d1bc', desbordamiento: 'oculto', altura: HEADER_MAX_HEIGHT, }, fondo del encabezado: { posición: 'absoluta', arriba: 0, izquierda: 0, derecha: 0, ancho: nulo, altura: HEADER_MAX_HEIGHT, resizeMode: 'cubierta', }, barra superior: { marginTop: 40, altura: 50, alignItems: 'centro', justifyContent: 'centro', posición: 'absoluta', arriba: 0, izquierda: 0, derecha: 0, }, título: { color blanco', fontSize: 20, }, Avatar: { altura: 54, ancho: 54, resizeMode: 'contener', borderRadius: 54/2, }, fullNameText: { fontSize: 16, marginLeft: 24, }, }); exportar la aplicación predeterminada;
Gracias por leer, espero que este artículo te haya resultado útil.
Añadir comentario