美文网首页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