react native自定义滚动吸顶位置
【代码】react native自定义滚动吸顶位置。
·
自定义滚动吸顶位置
- 父组件中主要的工作使用的是动画Animated,对
Animated.ScrollView组件的onScroll监听滚动位置,使用Animated.event将偏移量保存import React, {useRef} from 'react'; import { Text, View, ScrollView, Animated, } from 'react-native'; // 这是我自定义的顶部图片 import EveryDayRecommend from '@/view/DailyRecommendation/components/EveryDayRecommend/EveryDayRecommend'; // 这个组件使用的是吸顶的组件,抽出来方便其他页面组件使用 import StickyHeader from '@/view/DailyRecommendation/components/StickyHeader/StickyHeader'; const DefaultRecommend = () => { // 初始化动画 let scrollY = useRef(new Animated.Value(0)).current; // 指定到定位哪个位置停止滚动 let headHeight = useRef(200).current; return ( <View> <Animated.ScrollView // 通过OnScroll结合 Animated.event保存顶部偏移量 onScroll={ Animated.event( [ { nativeEvent: {contentOffset: {y: scrollY}}, // 滑动距离 }, ], {useNativeDriver: true}, ) // 使用原生动画驱动 }> {/* 自定义吸顶组件 */} <StickyHeader stickyHeaderY={headHeight} // 吸顶位置 stickyScrollY={scrollY} // 滚动距离传入 > <EveryDayRecommend source={require('@/assets/image/defaultRecommendGif.gif')} descBottom="默认的推荐风格" stickyHeaderY={headHeight} // 把头部高度传入 stickyScrollY={scrollY} // 把滑动距离传入 /> <Text>全部播放</Text> </StickyHeader> <ScrollView> <View> {[...Array.from({length: 100}).keys()].map(item => { return <Text key={item}>{item}</Text>; })} </View> </ScrollView> </Animated.ScrollView> </View> ); }; export default DefaultRecommend; - 子组件
StickyHeader中接受了父组件传递的,stickyHeaderY = null吸顶位置stickyScrollY偏移量children传递内容style样式- 在组件中使用了
Animated.View属性onLayout初始化会返回当前元素的属性,这里使用的情况是防止未传递吸顶高度,所以默认将其偏移量量作为吸顶高度
import React from 'react'; import {StyleSheet, Animated} from 'react-native'; import {useRef} from 'react'; const StickyHeader = ({ stickyHeaderY = null, stickyScrollY, children, style, }) => { let stickyLayoutY = useRef(0).current; // 判断是否滚动是否存在吸顶高度,如果不存在将当前元素到高度设置为吸顶高度 let y = stickyHeaderY !== null ? stickyHeaderY : stickyLayoutY; // 防止没有传头部高度 const _onLayout = event => { stickyLayoutY = event.nativeEvent.layout.y; }; return ( <Animated.View onLayout={_onLayout} // 元素初始化时会返回当前元素的属性 style={[ style, styles.container, { // interpolate函数用于创建一个动画, // 将输入范围映射到输出范围 stickyScrollY是一个Animated.Value,正在被插值以创建一个新的Animated.Value。 // inputRange数组指定了stickyScrollY值可以取的范围,outputRange数组指定了新的Animated.Value将取的值的范围。 // outputRange数组是[0, 0, 0, 1]。这意味着当stickyScrollY小于-1时,新的Animated.Value将为0。 // 当stickyScrollY在-1和0之间时,新的Animated.Value将为0。当stickyScrollY在y和y + 1之间时, // 新的Animated.Value将为0。当stickyScrollY大于y + 1时,新的Animated.Value将为1。 transform: [ { translateY: stickyScrollY.interpolate({ inputRange: [-1, 0, y, y + 1], outputRange: [0, 0, 0, 1], }), }, ], }, ]}> {children} </Animated.View> ); }; export default React.memo(StickyHeader); const styles = StyleSheet.create({ container: { zIndex: 100, }, }); - 并且使其组件中的图片会跟随,滚动逐渐隐藏,在父组件中有一个
EveryDayRecommend这里面是一个图片和日期- 主要部分就是通过最后一个
Animated.View进行定位和整个元素重合,设置其透明度,透明度结束位置,就是触顶位置
import React, {useRef, useState} from 'react'; import { Dimensions, Image, StyleSheet, Text, View, Animated, } from 'react-native'; import {useTheme} from '@react-navigation/native'; const widthWindow = Dimensions.get('window').width; const EveryDayRecommend = props => { const {otherColor, fontSize} = useTheme(); // 这个是获取当前日期 const [currentDate] = useState(new Date()); return ( <View style={styles.everyDayRecommend}> <Image style={[{width: widthWindow, height: 300}]} source={props.source} /> <View style={styles.desc}> <Text style={[styles.dateCurrent, {color: otherColor.bgFontColor}]}> <Text style={{fontSize: fontSize.superBig}}> {currentDate.getDate() >= 10 ? currentDate.getDate() : '0' + currentDate.getDate()} </Text> <Text style={{fontSize: fontSize.small}}> / {currentDate.getMonth() >= 10 ? currentDate.getMonth() + 1 : '0' + (currentDate.getDay() + 1)} </Text> </Text> <Text style={{color: otherColor.bgFontColor}}>{props.descBottom}</Text> </View> { /* 相当于遮罩层 */ } <Animated.View style={[ styles.shelter, { // 使用外部传递的stickyScrollY,使用插值opacity opacity: props.stickyScrollY?.interpolate({ inputRange: [0, props.stickyHeaderY], outputRange: [0, 1], }), }, ]} /> </View> ); }; export default EveryDayRecommend; const styles = StyleSheet.create({ everyDayRecommend: { position: 'relative', }, desc: { position: 'absolute', bottom: 20, paddingHorizontal: 10, }, dateCurrent: { flexDirection: 'row', fontWeight: 'bold', }, shelter: { width: widthWindow, height: 300, zIndex: 100, position: 'absolute', top: 0, left: 0, backgroundColor: '#fff', }, }); - 主要部分就是通过最后一个
更多推荐
所有评论(0)