React Native 锚点 ScrollView 实现
引用:
<Anchor anchorList={anchorContentCultureList} initCurIndex='shiming' />
anchorContentCultureList config.tsx
import React from 'react'; import { ImageSourcePropType } from 'react-native'; import { Image } from 'react-native-ui-lib'; import shimingImg from '../images/shiming.png'; import yuanjingImg from '../images/yuanjing.png'; import jiazhiguanImg from '../images/jiazhiguan.png'; import linianImg from '../images/linian.png'; import sanwenImg from '../images/sanwen.png'; import jilv1Img from '../images/jilv1.png'; import tielvImg from '../images/tielv.png'; import jilv2Img from '../images/jilv2.png'; import { AnimatableView } from '../../../components'; import { deviceWidth } from '../../../utils'; const imgConfig = { shiming: shimingImg, yuanjing: yuanjingImg, jiazhiguan: jiazhiguanImg, linian: linianImg, sanwen: sanwenImg, }; const reactNode = (id: string) => { if (id === 'jilv') { return ( <AnimatableView key={id} style={{ marginLeft: 15 }}> <Image style={{ width: deviceWidth - 30 }} source={jilv1Img as ImageSourcePropType} /> <Image style={{ width: deviceWidth - 30 }} source={tielvImg as ImageSourcePropType} /> <Image style={{ width: deviceWidth - 30 }} source={jilv2Img as ImageSourcePropType} /> </AnimatableView> ); } return ( <AnimatableView key={id} style={{ marginLeft: 15 }}> <Image style={{ width: deviceWidth - 30 }} source={imgConfig[id] as ImageSourcePropType} /> </AnimatableView> ); }; export const anchorContentCultureList = [{ id: 'shiming', name: '使命', reactNode: reactNode('shiming'), }, { id: 'yuanjing', name: '愿景', reactNode: reactNode('yuanjing'), }, { id: 'jiazhiguan', name: '价值观', reactNode: reactNode('jiazhiguan'), }, { id: 'linian', name: '理念', reactNode: reactNode('linian'), }, { id: 'sanwen', name: '三问', reactNode: reactNode('sanwen'), }, { id: 'jilv', name: '纪律', reactNode: reactNode('jilv'), }];
Anchor.tsx 代码
// 社区Tab下 文化Tab页 锚点 import React, { ReactNode, useState, useRef } from 'react'; import { ScrollView } from 'react-native'; import { Text, View, Colors } from 'react-native-ui-lib'; import { LineSpace, Touchable } from '../../components'; type Iarr = { y: number, height: number, id: string }; type IAnchorItem = { id: string, name: string, reactNode: ReactNode, }; type IAnchorProps = { otherChildren: ReactNode, // 锚点所在滚动区的其他组件 anchorList: IAnchorItem[], // 锚点list initCurIndex: string, // 初始化时选中的锚点,一般是第一个 }; const Anchor = (props: IAnchorProps) => { const anchorScrollViewRef: any = useRef(null); //锚点内容滚动容器 const { otherChildren, anchorList, initCurIndex = 'shiming' } = props; const [curIndex, setCurIndex] = useState(initCurIndex); // 锚点的id const [anchorArr, setAnchorArr] = useState<Iarr[]>([]); // 存储锚点数组,记录滚动位置y 组件高度height 锚点id // 点击锚点,滚动到指定位置 const handleLocation = (index: number) => { setCurIndex(anchorArr[index].id); anchorScrollViewRef && anchorScrollViewRef.current && anchorScrollViewRef.current.scrollTo({ x: 0, y: anchorArr[index].y, animated: false }); //anchorArr 就是之前定义的arr }; // 文化滚动内容的一些布局属性 const onLayout = (e: any, id: string) => { const newAnchorArr = [...new Set([...anchorArr, { y: e.layout.y, height: e.layout.height, id: id }])]; // 按照y大小排序,因为苹果手机上顺序是乱的。 newAnchorArr.sort((a: Iarr, b: Iarr) => { return a.y - b.y; }); setAnchorArr([...newAnchorArr]); }; const onScroll = (event: any) => { const scrollY = event?.nativeEvent?.contentOffset.y; for (let i = 0; i < anchorArr.length - 1; i++) { if (scrollY < anchorArr[0].height - 10) { setCurIndex(anchorArr[0].id); } else if (scrollY > anchorArr[i + 1].y - (anchorArr[i].height / 2)) { //当滚动到超过当前盒子一半的时候 setCurIndex(anchorArr[i + 1].id); } } }; return ( <View style={{ flexDirection: 'row', flex: 1 }}> <ScrollView scrollEventThrottle={100} showsVerticalScrollIndicator={false} ref={anchorScrollViewRef} onScroll={onScroll} > {otherChildren} { anchorList.map((item) => { return ( <> <View key={item.id} onLayout={({ nativeEvent: e }) => onLayout(e, item.id)} > {item.reactNode} </View> </> ); }) } </ScrollView> <View style={{ position: 'absolute', top: 156, right: 10, width: 50, }}> <ScrollView showsVerticalScrollIndicator={false}> {anchorList.map((item, index) => ( <View key={item.id}> <Touchable onPress={() => handleLocation(index)}> <Text grey66 f12 l28 style={{ textAlign: 'center', backgroundColor: curIndex === item.id ? 'rgba(74, 144, 226, 0.8)' : 'transparent', color: curIndex === item.id ? Colors.white : Colors.grey66, borderRadius: 4, }} >{item.name || ''}</Text> </Touchable> <LineSpace height={24} /> </View> ))} </ScrollView> </View> </View> ); }; export default Anchor;

浙公网安备 33010602011771号