美文网首页
react-native-scrollable-tab-view

react-native-scrollable-tab-view

作者: MasterPaul | 来源:发表于2019-04-14 21:40 被阅读0次
    效果 QQ20190414-212423-HD.gif
    import React,{Component} from 'react'
    const { ViewPropTypes } = ReactNative = require('react-native');
    const PropTypes = require('prop-types');
    const createReactClass = require('create-react-class');
    const {
        View,
        Animated,
        StyleSheet,
        ScrollView,
        Text,
        Platform,
        Image,
        Dimensions,
        TouchableOpacity
    } = ReactNative;
    import screen from '../../util/Screen'
    
    const WINDOW_WIDTH = Dimensions.get('window').width;
    
    
    const menuItems =  [
        {
            image:require('../../image/court_announce.png'),
            title:'法院公告'
        },
        {
            image:require('../../image/house_value.png'),
            title:'房产价值'
        },
        {
            image:require('../../image/school.png'),
            title:'学校'
        },
        {
            image:require('../../image/traffic_icon.png'),
            title:'交通'
        },
        {
            image:require('../../image/life_icon.png'),
            title:'生活'
        },
        {
            image:require('../../image/medical.png'),
            title:'医疗'
        },
    ]
    
    export default  class MyScrollTabBar extends Component{
    
        // 构造
          constructor(props) {
              super(props);
              this.necessarilyMeasurementsCompleted = this.necessarilyMeasurementsCompleted.bind(this)
              this.onTabContainerLayout = this.onTabContainerLayout.bind(this)
              this.onContainerLayout = this.onContainerLayout.bind(this)
              this.updateTabPanel = this.updateTabPanel.bind(this)
              this.updateTabUnderline = this.updateTabUnderline.bind(this)
              this.updateView = this.updateView.bind(this)
    
            // 初始状态
            this._tabsMeasurements = [];
    
            this.state = {
                _leftTabUnderline: new Animated.Value(0),
                // _widthTabUnderline: new Animated.Value(0),
                _containerWidth: null,
            };
          }
    
    
        componentDidMount() {
            this.props.scrollValue.addListener(this.updateView);
        }
    
        updateView(offset) {
              console.log('offset',offset)
            const position = Math.floor(offset.value);
            const pageOffset = offset.value % 1;
            const tabCount = menuItems.length;
            const lastTabPosition = tabCount - 1;
    
            console.log('position',position)
    
            if (tabCount === 0 || offset.value < 0 || offset.value > lastTabPosition) {
                return;
            }
    
    
            if (this.necessarilyMeasurementsCompleted(position, position === lastTabPosition)) {
                this.updateTabPanel(position, pageOffset);
                this.updateTabUnderline(position, pageOffset, tabCount);
            }
        }
        //判断是否所有需要的值都已经赋值完毕
        necessarilyMeasurementsCompleted(position, isLastTab) {
            return this._tabsMeasurements[position] &&
                (isLastTab || this._tabsMeasurements[position + 1]) &&
                this._tabContainerMeasurements &&
                this._containerMeasurements;
        }
        //更新tab
        updateTabPanel(position, pageOffset) {
            const containerWidth = this._containerMeasurements.width;
            const tabWidth = this._tabsMeasurements[position].width;
            const nextTabMeasurements = this._tabsMeasurements[position + 1];
            const nextTabWidth = nextTabMeasurements && nextTabMeasurements.width || 0;
            const tabOffset = this._tabsMeasurements[position].left;
            const absolutePageOffset = pageOffset * tabWidth;
            let newScrollX = tabOffset + absolutePageOffset;
    
            // center tab and smooth tab change (for when tabWidth changes a lot between two tabs)
            newScrollX -= (containerWidth - (1 - pageOffset) * tabWidth - pageOffset * nextTabWidth) / 2;
            newScrollX = newScrollX >= 0 ? newScrollX : 0;
    
            if (Platform.OS === 'android') {
                this._scrollView.scrollTo({x: newScrollX, y: 0, animated: false, });
            } else {
                const rightBoundScroll = this._tabContainerMeasurements.width - (this._containerMeasurements.width);
                newScrollX = newScrollX > rightBoundScroll ? rightBoundScroll : newScrollX;
                this._scrollView.scrollTo({x: newScrollX, y: 0, animated: false, });
            }
    
        }
        //更新下划线
        updateTabUnderline(position, pageOffset, tabCount) {
            const lineLeft = this._tabsMeasurements[position].left;
            const lineRight = this._tabsMeasurements[position].right;
    
            if (position < tabCount - 1) {
                const nextTabLeft = this._tabsMeasurements[position + 1].left;
                const nextTabRight = this._tabsMeasurements[position + 1].right;
    
                const newLineLeft = (pageOffset * nextTabLeft + (1 - pageOffset) * lineLeft);
                const newLineRight = (pageOffset * nextTabRight + (1 - pageOffset) * lineRight);
    
                this.state._leftTabUnderline.setValue(newLineLeft);
                // this.state._widthTabUnderline.setValue(newLineRight - newLineLeft);
            } else {
                this.state._leftTabUnderline.setValue(lineLeft);
                // this.state._widthTabUnderline.setValue(lineRight - lineLeft);
            }
        }
    
        renderTab(item, page, isTabActive, onPressHandler,onLayoutHandler) {
            const { activeTextColor, inactiveTextColor, textStyle,activeBgColor,inactiveBgColor } = this.props;
            const textColor = isTabActive ? activeTextColor : inactiveTextColor;
            const fontWeight = isTabActive ? 'bold' : 'normal';
            const tabBackgroundColor = isTabActive ? activeBgColor : inactiveBgColor
    
    
            return <TouchableOpacity
                key={`page_${page}`}
                onPress={() => onPressHandler(page)}
                onLayout={onLayoutHandler}
            >
    
                <View style={{width:screen.width/4,height:screen.PIXEL_120 + 10 ,justifyContent:'center',alignItems:'center',
                    borderBottomColor:'#fff'
                }}
                >
                    <Image source={item.image} style={{width:screen.PIXEL_40,height:screen.PIXEL_40}}/>
                    <Text style={{fontSize:16,color:'#fff',marginTop:screen.PIXEL_10}}>{item.title}</Text>
                </View>
            </TouchableOpacity>;
        }
    
        measureTab(page, event) {
            const { x, width, height, } = event.nativeEvent.layout;
    
            console.log('tabLayout',event.nativeEvent.layout)
            this._tabsMeasurements[page] = {left: x, right: x + width, width, height, };
            this.updateView({value: this.props.scrollValue.__getValue(), });
        }
    
        render() {
            const tabUnderlineStyle = {
                position: 'absolute',
                height: 4,
                backgroundColor: '#fff',
                bottom: 0,
                width: screen.width/4,
            };
    
            const dynamicTabUnderline = {
                left: this.state._leftTabUnderline,
            };
    
            return (
                <View
                    style={[styles.container, {backgroundColor:'#4994ea', }, this.props.style, ]}
                    onLayout={this.onContainerLayout}
                >
                    <ScrollView
                        ref={(scrollView) => { this._scrollView = scrollView; }}
                        horizontal={true}
                        showsHorizontalScrollIndicator={false}
                        showsVerticalScrollIndicator={false}
                        directionalLockEnabled={true}
                        bounces={false}
                        scrollsToTop={false}
                    >
                        <View
                            style={styles.tabs}
                            onLayout={this.onTabContainerLayout}
                        >
    
                            {menuItems.map((item, page) => {
                                const isTabActive = this.props.activeTab === page;
                                return this.renderTab(item, page, isTabActive, this.props.goToPage,this.measureTab.bind(this, page));
                            })}
    
                            <Animated.View style={[tabUnderlineStyle, dynamicTabUnderline, this.props.underlineStyle, ]} />
                        </View>
                    </ScrollView>
                </View>
    
            )
        }
    
        componentWillReceiveProps(nextProps) {
            // If the tabs change, force the width of the tabs container to be recalculated
            if (JSON.stringify(this.props.tabs) !== JSON.stringify(nextProps.tabs) && this.state._containerWidth) {
                this.setState({ _containerWidth: null, });
            }
        }
    
        //获取容器的总宽度
        onTabContainerLayout(e) {
            this._tabContainerMeasurements = e.nativeEvent.layout;
            let width = this._tabContainerMeasurements.width;
            console.log('tabWidth',width)
            if (width < WINDOW_WIDTH) {
                // width = WINDOW_WIDTH;
            }
            this.setState({ _containerWidth: width, });
            this.updateView({value: this.props.scrollValue.__getValue(), });
        }
    
        onContainerLayout(e) {
            this._containerMeasurements = e.nativeEvent.layout;
            let width = this._containerMeasurements.width;
            console.log('containerWidth',width)
            this.updateView({value: this.props.scrollValue.__getValue(), });
        }
    }
    
    
    
    const styles = StyleSheet.create({
    
        container: {
            height: screen.PIXEL_120 + 10,
            borderWidth: 1,
            borderTopWidth: 0,
            borderLeftWidth: 0,
            borderRightWidth: 0,
            borderColor: '#ccc',
        },
        tabs: {
            flexDirection: 'row',
        },
    });
    
    
    

    调用

    
    import React, {Component} from 'react';
    import {Platform, StyleSheet, Text, View,ScrollView,Image,TouchableWithoutFeedback} from 'react-native';
    
    import ScrollableTabView,{ScrollableTabBar,DefaultTabBar} from 'react-native-scrollable-tab-view'
    import MyScrollTabBar from '../app/components/DetailSecond/MyScrollTabBar'
    import CourtAnnounce from '../app/components/DetailSecond/CourtAnnounce'
    import HouseValueDetail from '../app/components/DetailSecond/HouseValueDetail'
    import SchoolView from '../app/components/DetailSecond/SchoolView'
    import TrafficView from '../app/components/DetailSecond/TrafficView'
    import LifeView from '../app/components/DetailSecond/LifeView'
    import HospitalView from '../app/components/DetailSecond/HospitalView'
    
    
    export default class ScrollTabDemo extends Component{
    
        render(){
            return (
                <ScrollableTabView
                    renderTabBar={() => <MyScrollTabBar/>}>
                 {/*   <Text tabLabel='Tab1'/>
                    <Text tabLabel='Tab2'/>
                    <Text tabLabel='Tab3'/>
                    <Text tabLabel='Tab4'/>
                    <Text tabLabel='Tab5'/>
                    <Text tabLabel='Tab6'/>*/}
                    <CourtAnnounce/>
                    <HouseValueDetail/>
                    <SchoolView/>
                    <TrafficView/>
                    <LifeView/>
                    <HospitalView/>
                </ScrollableTabView>
            );
    
        }
    }
    

    我用的RN版本是0.58.4,"react-native-scrollable-tab-view": "^0.10.0",
    其中遇到了一个很蛋疼的bug,有必要吐槽下,就是在左右滚动页面的过程中上面的tabbar不能跟着滚动,而且手机会卡死重启,as中打印日志如下


    30211555243190_.pic_hd.jpg

    说是主线程做了太多任务,好奇怪 ,但是当我打开调试模式debug js remotely 就会正常运行了,一开始以为是RN版本的问题,去找作者的github上找issue,好像也没有人遇到过这个问题,后来我乱试一气,终于招到了原因

        <ScrollableTabView
                    // tabBarPosition='top'
                    prerenderingSiblingsNumber={2}
    
                    // onChangeTab={(index) => {
                    //
                    //     console.log(index)
                    //
                    // }}
                    initialPage={this.state.currentPage}
                    renderTabBar={()=>(<MyScrollTabBar/>)}
    
                >
    

    原来是因为使用了 onChangeTab这个方法,把它注释掉就可以正常运行了,因为项目需求是导航标题要跟着页面切换,所以要使用这个方法,但是那个bug比起这个需求,当然是解决Bug重要了。

    希望能帮助到遇到同样问题的小伙伴。

    相关文章

      网友评论

          本文标题:react-native-scrollable-tab-view

          本文链接:https://www.haomeiwen.com/subject/clcewqtx.html