效果示例图
示例代码
import React, {useEffect, useRef, useState} from 'react';
import {Animated,PanResponder,StyleSheet,Text,View,Dimensions,
} from 'react-native';
import {pxToPd} from '../../common/js/device';const TestSwiper = () => {//动态获取的值const [tempList, setTempList] = useState([{id: 1},{id: 2},{id: 3},{id: 4},]);const [swiperList, setSwiperList] = useState([]);const swiperListRef = useRef([]);//定时器手柄const intervalHandleRef = useRef(null);//手势滑动区域节点const animatedViewRef = useRef(null);//单个切换页面的宽度const deviceWidth = Dimensions.get('window').width;// 默认显示下标的页面let currentIndexRef = useRef(0);const panResponderEnabled = useRef(true);//滑动的距离const defaultMove = -currentIndexRef.current * deviceWidth;const pan = useRef(new Animated.Value(defaultMove)).current;//手势操作const panResponder = useRef(PanResponder.create({onStartShouldSetPanResponder: () => true,onPanResponderGrant: () => {clearInterval(intervalHandleRef.current); // 暂停自动轮播panResponderEnabled.current = true;},//处理手势移动事件,其中使用了`dx`参数来表示在x轴上的移动距离onPanResponderMove: (evt, gestureState) => {//获取当前滚动区域有几个孩子节点const count = animatedViewRef.current._children.length;//每次移动的距离const moveX = -currentIndexRef.current * deviceWidth;//当移动到最左侧或者最右侧时,禁止拖动const start = currentIndexRef.current == 0 && gestureState.dx > 0;const end = currentIndexRef.current == count - 1 && gestureState.dx < 0;if (start || end) {// 禁止继续拖动return false;}pan.setValue(moveX + gestureState.dx);if (panResponderEnabled.current) {panResponderEnabled.current = false; // 防止多次暂停自动轮播clearInterval(intervalHandleRef.current); // 暂停自动轮播}},//处理手势释放时的逻辑onPanResponderRelease: (_, gestureState) => {//获取当前滚动区域有几个孩子节点const count = animatedViewRef.current._children.length;//当手指拖动区域大于100的时候,开始切换页面if (Math.abs(gestureState.dx) > 100) {let newPageIndex = currentIndexRef.current;if (gestureState.dx > 0) {newPageIndex = Math.max(0, currentIndexRef.current - 1);} else {newPageIndex = Math.min(count - 1, currentIndexRef.current + 1);}const moveX = -newPageIndex * deviceWidth;currentIndexRef.current = newPageIndex;Animated.timing(pan, {toValue: moveX,duration: 300,useNativeDriver: true,}).start(() => {if (newPageIndex == count - 1) {currentIndexRef.current = 0;pan.setValue(0);}autoPlayAPI(); // 继续自动轮播});} else {pan.setValue(-currentIndexRef.current * deviceWidth);}if (!panResponderEnabled.current) {autoPlayAPI(); // 继续自动轮播}},}),).current;//自动轮播const autoPlayAPI = () => {const max = swiperListRef.current.length - 1;if (intervalHandleRef.current) {clearInterval(intervalHandleRef.current);}intervalHandleRef.current = setInterval(() => {let newPageIndex = 0;if (currentIndexRef.current == max) {newPageIndex = 0;} else {newPageIndex = currentIndexRef.current + 1;}const moveX = -newPageIndex * deviceWidth;currentIndexRef.current = newPageIndex;Animated.timing(pan, {toValue: moveX,duration: 300,useNativeDriver: true,}).start(() => {if (newPageIndex == max) {currentIndexRef.current = 0;pan.setValue(0);autoPlayAPI();}});}, 3000);};//初始化const initFunction = () => {let tempArr = [...tempList];let firstArr = tempArr[0];let contactArr = tempArr.concat(firstArr);swiperListRef.current = contactArr;setSwiperList(() => contactArr);autoPlayAPI();};useEffect(() => {initFunction();return () => {clearInterval(intervalHandleRef.current);};}, []);return (<><View style={styles.swiperWrap}><Animated.Viewref={animatedViewRef}style={{width: deviceWidth * swiperList.length,flex: 1,flexDirection: 'row',transform: [{translateX: pan}],onStartShouldSetResponderCapture: () => false, // 禁止拦截触摸事件}}{...panResponder.panHandlers}>{swiperList.map((item, index) => (<View key={'swiperItem' + index} style={{width: deviceWidth}}><View style={styles.swiperItem}><Text>item {item.id}</Text></View></View>))}</Animated.View></View></>);
};const styles = StyleSheet.create({swiperWrap: {borderColor: 'red',borderWidth: pxToPd(1),borderStyle: 'solid',width: '100%',height: pxToPd(400),},swiperItem: {borderColor: 'red',borderWidth: pxToPd(1),borderStyle: 'solid',borderRadius: pxToPd(12),width: '93.6%',marginLeft: '3.2%',height: '100%',},
});export default TestSwiper;