自定义滚动吸顶位置
- 父组件中主要的工作使用的是动画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 stickyTopY = useRef(200).current; return ( <View> <Animated.ScrollView // 通过OnScroll结合 Animated.event保存顶部偏移量 onScroll={ Animated.event( [ { nativeEvent: { contentOffset: { y:scrollY } }, // 滑动距离 }, ], {useNativeDriver: true}, ) // 使用原生动画驱动 }> {/* 自定义吸顶组件 */} <StickyHeader stickyTopY={stickyTopY} // 头部高度,也就是吸顶位置 stickyScrollY={scrollY} // 把滑动距离传入 > <EveryDayRecommend source={require('@/assets/image/defaultRecommendGif.gif')} descBottom="默认的推荐风格" /> <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
中接受了父组件传递的,stickyTopY = null
吸顶位置stickyScrollY
偏移量children
传递内容-
style
样式 - 在组件中使用了
Animated.View
属性onLayout
初始化会返回当前元素的属性,这里使用的情况是防止未传递吸顶高度,所以默认将其偏移量量作为吸顶高度
import React from 'react'; import {StyleSheet, Animated} from 'react-native'; import {useRef} from 'react'; const StickyHeader = ({ stickyTopY = null, stickyScrollY, children, style, }) => { let stickyLayoutY = useRef(0).current; // 判断是否滚动是否存在吸顶高度,如果不存在将当前元素到高度设置为吸顶高度 let y = stickyHeaderY !== null ? stickyTopY : stickyLayoutY; // 初始化高度,没有传递吸顶位置时使用 const onLayout = event => { stickyLayoutY = event.nativeEvent.layout.y; }; return ( <Animated.View onLayout={onLayout} // 元素初始化时会返回当前元素的属性 style={[ style, styles.con, { // 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({ con: { zIndex: 10, }, });