import React, {useEffect, useRef, useState} from 'react'; import { Dimensions, ScrollView, StyleProp, StyleSheet, View, ViewStyle, } from 'react-native'; import {ScrollEvent} from '../../types'; interface ViewPagerProps { /** 当前激活的 `index` */ index: number; /** `ViewPager` 的长度 */ length: number; /** 是否有动画效果 */ enableScrollAnimation?: boolean; /** 渲染什么布局,把决定权交给你自己,我只管给你空间 */ renderItem: (item: any, index: number) => React.ReactNode; /** 每个 Item 的样式 */ /** `ViewPager` 的宽度取其中的 `width` */ itemStyle?: StyleProp; /** `currentIndex` 变化的时候 */ onIndexChange?: (index: number) => void; } const ViewPager: React.FC = props => { const [datas, setDatas] = useState([]); const [currentIndex, setCurrentIndex] = useState(0); const [scrollEvent, setScrollEvent] = useState({ start: 0, end: 0, finish: false, }); let viewPager = useRef(); const { index = 0, length = 0, enableScrollAnimation = true, renderItem, itemStyle = {width: Dimensions.get('screen').width}, onIndexChange, } = props; useEffect(() => { setDatas(Array.from({length}, (_, i) => i)); return function () {}; }, [length]); useEffect(() => { if (scrollEvent.finish) { let _index = index + Math.sign(scrollEvent.end - scrollEvent.start); setCurrentIndex( _index <= 0 ? 0 : _index == datas.length - 1 ? _index - 1 : _index, ); } return () => {}; }, [scrollEvent]); useEffect(() => { if (index != currentIndex) { setCurrentIndex(index); viewPager.current.scrollTo({ x: (index - 1) * itemStyle.width, animated: enableScrollAnimation, }); } return function () {}; }, [index]); useEffect(() => { onIndexChange && onIndexChange(currentIndex); return function () {}; }, [currentIndex]); return ( { let x = e.nativeEvent.contentOffset.x; setScrollEvent({ start: x, end: scrollEvent.end, finish: false, }); }} onScrollEndDrag={e => { let x = e.nativeEvent.contentOffset.x; setScrollEvent({ start: scrollEvent.start, end: x, finish: true, }); }} disableIntervalMomentum={true} bounces={false} showsHorizontalScrollIndicator={false} horizontal={true} ref={ref => (viewPager.current = ref)}> {datas.map((it, i) => ( {renderItem(it, i)} ))} ); }; const styles = StyleSheet.create({ viewItem: { flex: 1, height: '100%', width: Dimensions.get('screen').width, }, }); export default ViewPager;