美文网首页RNReact Native开发经验集React Native 专题
React Native 支付宝更多页面的实现

React Native 支付宝更多页面的实现

作者: IT界的段子手 | 来源:发表于2018-07-24 18:45 被阅读560次
    效果图
    • 实现的效果:
      • 页面向上滑动有吸顶的效果。
      • 便民服务,查询服务 ...所在的 tabBar 与页面下方对应的模块内容一一对应。
      • 页面滑动对应的 tabBartitle 居中偏移。
      • 编辑模式下:数据的 新增删除

    • 效果展示:


      实现效果图.gif

    • 实现吸顶的代码(噗~感觉这个没啥好写 ...... 很尴尬):
      —— 段子手是运用 ScrollView ==> onScroll ==> e.nativeEvent.contentOffset.y 获取页面滑动的当前坐标;
      然后和页面初次加载时 tabBar ==> onLayout ==> e.nativeEvent.layout.y 的值做比较获取状态。

       this.moveHeight = e.nativeEvent.contentOffset.y;
      
        if (this.moveHeight >= typeY) {
            this.setState({
                 positionType: true,
            })
        } else {
            this.setState({
                 positionType: false
             })
        }
      
    • 实现滑动模块和标题一一对应代码(这个有点篇幅):

      • 先说:点击标题,对应的模块自动置顶

        1. 首先初次加载时,我把 tabBar 下的各个模块的 y 坐标都存下来, push 到数组中,并且对应的模块下标 i 也存起来。
                    //保存 模块的下标和 y 轴
                    let params = {
                        key: i,
                        tmpY: e.nativeEvent.layout.y
                    };
        
                    //数组去重(判断命名的变量不建议用 type)
                    let typePis = tmpArr.some(v => v.key == params.key);
        
                    if (typePis) {
                        tmpArr.filter((v) => {
                            return v.key != params.key
                        })
                    } else {
                        tmpArr.push(params);
                    }
                    break;
        
        • 去重是因为吸顶的原因,会导致页面的 onLayout 重新加载。
        • 这里还有一个小坑:模块返回的坐标顺序并不是按页面展示顺序来的。
        1. 拿到模块的坐标数组 tmpArr 后,根据点击 tabBar 的下标 indextmpArrkey 去匹配,一致时取出 tmpArr 对应的 tmpY 值,根据该值去计算页面的偏移量。
           let y;
           tmpArr.map((v, i) => {
               if (v.key == index) {
                   y = v.tmpY;
               }
           });
        
           // 页面中模块的 y 轴移动 (typeY: tabBar 的坐标,
           // y:模块的坐标,头部    固定位置的搜索: autoHeight(45))
           this.refs.refMoveHeight.scrollTo({y: typeY + y - autoHeight(45)});
        
        1. 在点击 tabBar 最后的标题,模块的内容的高度不够去偏移到置顶的位置的处理(根据已有的内容高度,去自适应填充空白区域)。
          • 保存最后一个模块的 y
            // i:就是点击标题的下标;typeList:是标题数组。
            if (i == typeList.length - 1) {
                  this.setState({
                       listCellHeight: e.nativeEvent.layout.y
                 })
            }
          
          • 在最后的一个模块后面添加一个高度为 1View ,然后保存它的坐标 footHeight = e.nativeEvent.layout.y,接着再设置一个填充空白页面 View,高度为 屏幕全高 - (footHeight - listCellHeight - typeY + autoHeight(45))
      • 再说下滑动模块和 tabBar 的标题对应

        • 获取手势在屏幕上的滑动方向,把 <= 当前页面滑动高度的模块都塞选出来,然后取出最大的下标,然后和 tabBar 中的标题下标去匹配,一致则标题显示高亮。
          let maxValue = 0;
          if (this.moveHeight > e.nativeEvent.contentOffset.y) {
              tmpArr.map((v, i) => {
                    if (e.nativeEvent.contentOffset.y >= (typeY + v.tmpY -     autoHeight(45))) {
          
                        // console.log(i + '下下下');
                        //因为模块高度的下标不是按在页面中的位置返回的,所以和 tabBar 的下标并不能一一对应,所以要塞选出下标的最大值
                        if (tmpArr[i].key >= maxValue) {
                            maxValue = tmpArr[i].key
                        }
          
                        // console.log(maxValue + 'maxValue下=========');
                    }
                }
            )
          } else {
            tmpArr.map((v, i) => {
                    if (e.nativeEvent.contentOffset.y >= (typeY + v.tmpY - autoHeight(45))) {
                        // console.log(i + '下下下');
                        //因为模块高度的下标不是按在页面中的位置返回的,所以和 tabBar 的下标并不能一一对应,所以要塞选出下标的最大值
                        if (tmpArr[i].key >= maxValue) {
                            maxValue = tmpArr[i].key
                        }
          
                        // console.log(maxValue + 'maxValue上======');
                    }
                }
            )
          }
          
          this.state.currentIndex = maxValue;
          
    • 实现页面滑动对应的 tabBartitle 居中偏移代码

      • 获取屏幕 width 的宽度的一半。

          let widthHalf = 屏幕宽度 / 2;
        
      • 获取到 tabBar 中各个标题位置的 width,同时保存对应的挑剔位置的下标,数组为 tmpArrX

               //保存 tabBar 的下标和 width
                let param = {
                    index: i,
                    tmpX: e.nativeEvent.layout.width
                };
        
                //数组去重
                let tmpType = tmpArrX.some(v => v.index == param.index);
        
                if (tmpType) {
                    tmpArrX.filter((v) => {
                        return v.index != param.index
                    })
                } else {
                    tmpArrX.push(param);
                }
        
      • 拿到点击 tabBar 的下标,获取到这个下标之前的模块 width

         //获取 index 之前模块 width
        let widthX = 0;
        //获取选中的 width
        let indexWidth;
        
        for (let i = 0; i <= index; i++) {
            // console.log('i===' + i);
            tmpArrX.map((item, key) => {
                if (item.index == i) {
                    widthX += item.tmpX
                }
        
                if (index == item.index) {
                    indexWidth = item.tmpX
                }
            })
        }
        
      • 根据判断出来是不是 tabBar 中最后一个标题,然后拿 widthXindexWidth 然后去判断编写逻辑。

        let moveX;
        // index*20 是每个模块的空隙 20
        if (widthX + index * 20 > widthHalf && index != tmpArrX.length - 1) {
            moveX = (widthX - widthHalf + indexWidth) / 2
        } else if (index == tmpArrX.length - 1) {
            //index + 1 :间距比个数多一个; 10 :marGinLeft = 10
            moveX = (index + 1) * 20 + widthX - SCREEN_WIDTH + 10
        }
        
        // 页面中  tabBar 的 x 轴移动
        this.refs.moveX.scrollTo({x: autoWidth(moveX)})
        
    • 实现编辑模式下:数据的 新增删除 的代码(段子手快饿死了,写不动注释了 ......)

        //数组的加减
        _addOrDelete(keyType, data, i) {
            console.log('data===' + JSON.stringify(data) + '===' + i);
            //更改 severListType 的数据
            const {severListType, headList}=this.state;
            let tmpType = severListType.some(item => item.id === data.id);
      
            switch (keyType) {
                case 1:
                    // severListType.splice(i, 1);
                    if (tmpType) {
                        // tmpSeverId :用来存储选中的截取的 id
                        this.state.severListType = severListType.filter((item) => {
                            return item.id != data.id
                        });
                        //编辑模式下,是否为已有模块, true:加号,false:减号
                        data.select = !tmpType;
                    }
                    break;
                case 2:
                case 3:
                    if (!tmpType) {
                        if (severListType.length > 10) {
                            RootToast.show('首页最多添加 11 个应用')
                        } else {
                            severListType.push(data)
                        }
                    } else {
                        //获取输入的值和在另一个模块数组中的下标,然后删除
                        console.log('data1===' + JSON.stringify(data) + '===ss' + i);
                        console.log('severListType===' + JSON.stringify(severListType));
                        this.state.severListType = severListType.filter((item) => {
                            return item.id != data.id
                        });
                        data.select = !tmpType;
                    }
                    break;
            }
            //刷新数据
            this.setState({
                severListType: this.state.severListType
            }, () => {
                // console.log('severListType===' + JSON.stringify(this.state.severListType));
      
            });
        }
      

    TIP:
    • 吸顶效果在 android 低配中会出现卡顿现象。
    • 页面滑动对应的 tabBartitle 居中偏移(我的写法还是有问题的,还有就是模块滑动时 tabBar 对应居中也会有卡顿)。

    段子手不才,欢迎来补充
    • 由于篇幅原因,具体想要知道整个效果图的代码或者有补充地方的可以加技术群:631730313

    相关文章

      网友评论

        本文标题:React Native 支付宝更多页面的实现

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