基于react native的简单手动切换功能示例
代码示例
import React, {useEffect, useRef, useState} from 'react';
import {Animated,PanResponder,StyleSheet,Text,View,Dimensions,ScrollView,
} from 'react-native';
import {pxToPd} from '../../common/js/device';
import MatchTab from './matchTab';const TestExampleTab = ({navigation}) => {const [tabCode, setTabCode] = useState(2);const [tabList, setTabList] = useState([{name: '报名中',code: 2,},{name: '进行中',code: 3,},{name: '已结束',code: 8,},{name: '已作废',code: 11,},]);//手势滑动区域节点const animatedViewRef = useRef(null);//单个切换页面的宽度const deviceWidth = Dimensions.get('window').width;// 默认显示下标的页面let currentIndexRef = useRef(0);//滑动的距离const defaultMove = -currentIndexRef.current * deviceWidth;const pan = useRef(new Animated.Value(defaultMove)).current;const panResponder = useRef(PanResponder.create({onStartShouldSetPanResponder: () => 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;}if (Math.abs(gestureState.dx) < 50) {return false;}pan.setValue(moveX + gestureState.dx);},//处理手势释放时的逻辑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;pan.setValue(moveX);} else {pan.setValue(-currentIndexRef.current * deviceWidth);}setTabCode(() => tabList[currentIndexRef.current].code);},}),).current;//tab切换const tabChangeHandle = row => {setTabCode(() => row.status);let subscript = tabList.findIndex(item => item.code == row.status);currentIndexRef.current = subscript;pan.setValue(-subscript * deviceWidth);};useEffect(() => {return () => {};}, []);return (<>{/* tab */}<View style={styles.tabWrap}><MatchTab list={tabList} code={tabCode} onClick={tabChangeHandle} /></View><View style={styles.wraper}><Animated.Viewref={animatedViewRef}style={{width: deviceWidth * tabList.length,flex: 1,flexDirection: 'row',transform: [{translateX: pan}],onStartShouldSetResponderCapture: () => false, // 禁止拦截触摸事件}}{...panResponder.panHandlers}><View style={{width: deviceWidth, backgroundColor: 'red'}}><Text>item One</Text></View><View style={{width: deviceWidth}}><Text>item Two</Text></View><View style={{width: deviceWidth, backgroundColor: 'green'}}><Text>item Three</Text></View><View style={{width: deviceWidth}}><Text>item Four</Text></View></Animated.View></View></>);
};
const styles = StyleSheet.create({// tabtabWrap: {width: '100%',height: pxToPd(80),},wraper: {flex: 1,backgroundColor: '#fff',},
});export default TestExampleTab;
matchTab
import React, {useRef, useState} from 'react';
import {Image,ScrollView,StyleSheet,Text,TouchableOpacity,View,
} from 'react-native';
import {pxToPd} from '../../common/js/device';const MatchTabItem = ({item, current, onClick}) => {const tabItemClickHandle = row => {onClick && onClick(row);};return (<><TouchableOpacitystyle={styles.tabItem}onPress={() => {tabItemClickHandle(item);}}>{item.code == current ? (<><Text style={styles.tabItemNameCurrent}>{item.name}</Text><View style={styles.tabLine}></View></>) : (<><Text style={styles.tabItemName}>{item.name}</Text></>)}</TouchableOpacity></>);
};const MatchTab = ({onClick, list = [], code = 2}) => {//点击tab切换const tabClickHandle = row => {onClick &&onClick({type: 'status',status: row.code,});};return (<><View style={styles.matchTab}><View style={styles.matchTabMenu}><ScrollView horizontal={true}>{list.map(item => (<MatchTabItemkey={item.code}item={item}current={code}onClick={tabClickHandle}/>))}</ScrollView></View></View></>);
};const styles = StyleSheet.create({matchTab: {width: '93.6%',marginLeft: '3.2%',flexDirection: 'row',},matchTabMenu: {flex: 1,},matchTabFilter: {width: pxToPd(120),flexDirection: 'row',justifyContent: 'flex-end',alignItems: 'center',},filterIcon: {width: pxToPd(32),height: pxToPd(32),},filterText: {fontSize: pxToPd(26),fontWeight: '400',color: '#333',marginLeft: pxToPd(10),},filterTextok: {fontSize: pxToPd(26),fontWeight: '400',color: '#FFA157',marginLeft: pxToPd(10),},tabItem: {height: pxToPd(70),position: 'relative',alignItems: 'center',justifyContent: 'center',marginRight: pxToPd(40),},tabItemName: {fontSize: pxToPd(26),fontWeight: '400',color: '#333',},tabItemNameCurrent: {fontSize: pxToPd(30),fontWeight: '500',color: '#ff9f50',},tabLine: {width: pxToPd(32),height: pxToPd(6),backgroundColor: '#ffa157',borderRadius: pxToPd(3),position: 'absolute',left: '50%',marginLeft: -pxToPd(16),bottom: 0,},
});export default MatchTab;