React Native带你实现scrollable-tab-view(完结)

前言:上一节React Native带你实现scrollable-tab-view(五)中我们最后实现了我们scrollable-tab-view的效果为:

这里写图片描述

我们要做的就只差一步了,那就是点击tab的时候,让指定tab居中,也就是要改变srollview的水平偏移量,但是偏移量控制范围为:
(0<=x<=tabcontainer的宽度-container的宽度),也就是scrollview到顶部和到底部的判断,不懂的朋友自己脑补一下画面哈~~ 画图不太好,不然就画一张图了,/傻笑。

所以我们需要拿到的是:TabBarView的宽度、TabBarContainer的宽度。

 render() {
        let {containerWidth, tabs, scrollValue}=this.props;
        //给传过来的动画一个插值器
        let tabStyle = {
            width: this.state._widthTabUnderline,
            position: 'absolute',
            bottom: 0,
            left: this.state._leftTabUnderline,
        };
        return (
            <View
                //获取tabbarview的宽度
                onLayout={(e)=>this._measureContainer(e)}
            >
                <ScrollView
                   ....
                >
                    <View
                        //获取tab到底有多宽
                        onLayout={(e)=>this._measureTabContainer(e)}
                    >
                       ....
                    </View>
                </ScrollView>
            </View>
        );
    }
 /**
     * 测量内容view
     * @param event
     * @private
     */
    _measureContainer(event) {
        this._containerMeasure = event.nativeEvent.layout;
        this._updateView({value: this.props.scrollValue._value});
    }

    /**
     * 测量tab内容view
     * @param event
     * @private
     */
    _measureTabContainer(event) {
        this._tabContainerMeasure = event.nativeEvent.layout;
        if (this.state._tabContainerWidth !== this._tabContainerMeasure.width) {
            this.setState({
                _tabContainerWidth: this._tabContainerMeasure.width,
            }, ()=> {
                this._updateView({value: this.props.scrollValue._value});
            });
        }
    }

然后测量完毕后去执行下_updateView去更新底部线view的状态。

 /**
     * 根据scrollview的滑动改变底部线条的宽度跟left
     * @param value
     * @private
     */
    _updateView = ({value = 0}) => {
        //因为value 的值是[0-1-2-3-4]变换
        const position = Math.floor(value);
        //取小数部分
        const offset = value % 1;
        const tabCount = this.props.tabs.length;
        const lastTabPosition = tabCount - 1;
        //如果没有tab||(有bounce效果)直接return
        if (tabCount === 0 || value < 0 || value > lastTabPosition) {
            return;
        }
        if (this._necessarilyMeasurementsCompleted(position, position === tabCount - 1)) {
            this._updateTabLine(position, offset);
            //控制pannel的移动(也就是tab外部的scrollview的滚动)
            this._updateTabPanel(position, offset);
        }
    }

如果我们要想tab页面一居中显示:
这里写图片描述

那scrollview x轴的偏移量是不是等于:

当前选中tab的x轴偏移量-(控件的宽度 - (第一个tab的宽度*(1-offset)-(第二个tab的宽度*offset)))/2

也就是:
* 当前选中tab的x轴偏移量 -= (containerWidth - (1 - pageOffset) tabWidth - pageOffset * nextTabWidth) / 2;**

小伙伴可以自己把值带进去看看哈。

嗯嗯,知道原理后,我们首先要拿到的就是当前选中的tab在x轴的偏移量:

 /**
     * 修改tab内容view的scroll在y轴的偏移量
     * @private
     */
    _updateTabPanel(position, pageOffset) {
        //父控件的宽度
        const containerWidth = this._containerMeasure.width;// width
        //获取当前选中tab的宽度
        const tabWidth = this._tabsMeasurements[position].width;
        //获取选中tab的下一个tab的测量值
        const nextTabMeasurements = this._tabsMeasurements[position + 1];
        //获取选中tab的下一个tab的宽度
        const nextTabWidth = nextTabMeasurements && nextTabMeasurements.width || 0;
        //当前选中tab的x坐标
        const tabOffset = this._tabsMeasurements[position].left;
        //当前选中tab距离下一个tab的偏移量(也就是底部线条还停留在当前tab的宽度)
        const absolutePageOffset = pageOffset * tabWidth;
        //所以当前tab实际偏移量=(当前tab的x轴坐标+当前tab的底部线条偏移量)
        let newScrollX = tabOffset + absolutePageOffset;

        //计算当前tab显示在控件中央位置需要在(当前scrollview偏移量的基础上再偏移多少)
        newScrollX -= (containerWidth - (1 - pageOffset) * tabWidth - pageOffset * nextTabWidth) / 2;
        //因为tabcontainer里面内容最大宽度=(最大scrollx+控件自身的宽度),
        //所以最大scrollx=tabcontainer里面内容最大宽度-控件自身的宽度
        const rightBoundScroll = this._tabContainerMeasure.width - (this._containerMeasure.width);
        //求出scrollview x轴偏移临界值【0,rightBoundScroll】
        newScrollX = newScrollX >= 0 ? ( newScrollX > rightBoundScroll ? rightBoundScroll : newScrollX) : 0;
        this._scrollView.scrollTo({x: newScrollX, y: 0, animated: false,});
    }

然后再次运行我们的代码:
这里写图片描述
可以看到,我们已经基本实现了scrollable-tab-view,哈哈~ 其实scrollable-tab-view也是一步一步完善的,所以我们只能叫基本实现了它,不得不感叹作者牛逼~!!!

上一节在处理底部线条view的left的时候,我们还有一个bug,我们先看一幅图:

这里写图片描述

假如我们的绿色线段是从ab区间滑动到bc区间,那绿色线段的left偏移量等于

left=oa*(1-offset)+ob*offset;

哈哈,数学好的一看就会了哈,比如我们要计算ab的中点坐标是不是等于(oa*0.5+ob*0.5)? 哈哈~~ 原谅我上班时间写了这篇博客,不知道我领导知道了会不会搞我,哈哈~~~

说实话,感觉自己也做了很久的开发了,一开始是准备去做java后台的,然后不小心做了andoird,并且android已经到了痴迷的程度了,因为公司的需要接触了rn,于是也到了痴迷的程度(可惜还是个渣渣啊~~),然后又是由于公司的需要做了h5,h5做了大半年,于是跳槽到了现在的公司,继续rn生涯,感觉吧经历了许多,身边的人也是换了一批又一批,如果要继续走rn跟h5路线的话,我要走的路还很长很长,而且短时间也不会看到回报,但是如果走得好的话,回报还算比较大,因为前段近几年应该还是会保持一个比较火的状态,如果要继续走android路线的话,可能稍微轻松点,但是也还是要不断学习,由于android市场毕竟现在以至将能可能都不太理想,说白了,在这么一座大城市工作,无非就是为了多一点收入,但是收入跟付出也是成正比的,付出了也不一定有回报,但是反过来可能就不成立了,哈哈~~ 原谅我这么长的感慨哈,不知道小伙伴是不是跟我有一样的烦恼,抱怨一下总是好的,至少把自己内心的想法说出来了哈,好啦!! 不扯啦~~~

写到这里,这个系列的文章就要跟小伙伴说再见了,辛苦了那些一直关注的小伙伴,谢谢你们,也欢迎一起交流,一起学习,欢迎入群。

猜你喜欢

转载自blog.csdn.net/vv_bug/article/details/77897004

相关文章