React Native 支付寶更多頁面的實(shí)現(xiàn)

支付寶效果圖
  • 實(shí)現(xiàn)的效果:
    • 頁面向上滑動(dòng)有吸頂?shù)男Ч?/li>
    • 便民服務(wù)芹枷,查詢服務(wù) ...所在的 tabBar 與頁面下方對(duì)應(yīng)的模塊內(nèi)容一一對(duì)應(yīng)斤富。
    • 頁面滑動(dòng)對(duì)應(yīng)的 tabBartitle 居中偏移。
    • 編輯模式下:數(shù)據(jù)的 新增刪除 份帐。

  • 效果展示:
還原支付寶效果圖

  • 實(shí)現(xiàn)吸頂?shù)拇a(噗~感覺這個(gè)沒啥好寫 ...... 很尷尬):
    —— 段子手是運(yùn)用 ScrollView ==> onScroll ==> e.nativeEvent.contentOffset.y 獲取頁面滑動(dòng)的當(dāng)前坐標(biāo)膏萧;
    然后和頁面初次加載時(shí) tabBar ==> onLayout ==> e.nativeEvent.layout.y 的值做比較獲取狀態(tài)。

     this.moveHeight = e.nativeEvent.contentOffset.y;
    
      if (this.moveHeight >= typeY) {
          this.setState({
               positionType: true,
          })
      } else {
          this.setState({
               positionType: false
           })
      }
    
  • 實(shí)現(xiàn)滑動(dòng)模塊和標(biāo)題一一對(duì)應(yīng)代碼(這個(gè)有點(diǎn)篇幅):

    • 先說:點(diǎn)擊標(biāo)題饮怯,對(duì)應(yīng)的模塊自動(dòng)置頂

      1. 首先初次加載時(shí)闰歪,我把 tabBar 下的各個(gè)模塊的 y 坐標(biāo)都存下來, push 到數(shù)組中蓖墅,并且對(duì)應(yīng)的模塊下標(biāo) i 也存起來库倘。
                  //保存 模塊的下標(biāo)和 y 軸
                  let params = {
                      key: i,
                      tmpY: e.nativeEvent.layout.y
                  };
      
                  //數(shù)組去重(判斷命名的變量不建議用 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;
      
      • 去重是因?yàn)槲數(shù)脑颍瑫?huì)導(dǎo)致頁面的 onLayout 重新加載论矾。
      • 這里還有一個(gè)小坑:模塊返回的坐標(biāo)順序并不是按頁面展示順序來的教翩。
      1. 拿到模塊的坐標(biāo)數(shù)組 tmpArr 后,根據(jù)點(diǎn)擊 tabBar 的下標(biāo) indextmpArrkey 去匹配贪壳,一致時(shí)取出 tmpArr 對(duì)應(yīng)的 tmpY 值饱亿,根據(jù)該值去計(jì)算頁面的偏移量。
         let y;
         tmpArr.map((v, i) => {
             if (v.key == index) {
                 y = v.tmpY;
             }
         });
      
         // 頁面中模塊的 y 軸移動(dòng) (typeY: tabBar 的坐標(biāo),
         // y:模塊的坐標(biāo)彪笼,頭部    固定位置的搜索: autoHeight(45))
         this.refs.refMoveHeight.scrollTo({y: typeY + y - autoHeight(45)});
      
      1. 在點(diǎn)擊 tabBar 最后的標(biāo)題钻注,模塊的內(nèi)容的高度不夠去偏移到置頂?shù)奈恢玫奶幚恚ǜ鶕?jù)已有的內(nèi)容高度,去自適應(yīng)填充空白區(qū)域)配猫。
        • 保存最后一個(gè)模塊的 y
          // i:就是點(diǎn)擊標(biāo)題的下標(biāo)幅恋;typeList:是標(biāo)題數(shù)組。
          if (i == typeList.length - 1) {
                this.setState({
                     listCellHeight: e.nativeEvent.layout.y
               })
          }
        
        • 在最后的一個(gè)模塊后面添加一個(gè)高度為 1View 泵肄,然后保存它的坐標(biāo) footHeight = e.nativeEvent.layout.y捆交,接著再設(shè)置一個(gè)填充空白頁面 View,高度為 屏幕全高 - (footHeight - listCellHeight - typeY + autoHeight(45))凡伊。
    • 再說下滑動(dòng)模塊和 tabBar 的標(biāo)題對(duì)應(yīng)

      • 獲取手勢(shì)在屏幕上的滑動(dòng)方向零渐,把 <= 當(dāng)前頁面滑動(dòng)高度的模塊都塞選出來,然后取出最大的下標(biāo)系忙,然后和 tabBar 中的標(biāo)題下標(biāo)去匹配诵盼,一致則標(biāo)題顯示高亮。
        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 + '下下下');
                      //因?yàn)槟K高度的下標(biāo)不是按在頁面中的位置返回的银还,所以和 tabBar 的下標(biāo)并不能一一對(duì)應(yīng)风宁,所以要塞選出下標(biāo)的最大值
                      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 + '下下下');
                      //因?yàn)槟K高度的下標(biāo)不是按在頁面中的位置返回的,所以和 tabBar 的下標(biāo)并不能一一對(duì)應(yīng)蛹疯,所以要塞選出下標(biāo)的最大值
                      if (tmpArr[i].key >= maxValue) {
                          maxValue = tmpArr[i].key
                      }
        
                      // console.log(maxValue + 'maxValue上======');
                  }
              }
          )
        }
        
        this.state.currentIndex = maxValue;
        
  • 實(shí)現(xiàn)頁面滑動(dòng)對(duì)應(yīng)的 tabBartitle 居中偏移代碼

    • 獲取屏幕 width 的寬度的一半戒财。

        let widthHalf = 屏幕寬度 / 2;
      
    • 獲取到 tabBar 中各個(gè)標(biāo)題位置的 width,同時(shí)保存對(duì)應(yīng)的挑剔位置的下標(biāo)捺弦,數(shù)組為 tmpArrX饮寞。

             //保存 tabBar 的下標(biāo)和 width
              let param = {
                  index: i,
                  tmpX: e.nativeEvent.layout.width
              };
      
              //數(shù)組去重
              let tmpType = tmpArrX.some(v => v.index == param.index);
      
              if (tmpType) {
                  tmpArrX.filter((v) => {
                      return v.index != param.index
                  })
              } else {
                  tmpArrX.push(param);
              }
      
    • 拿到點(diǎn)擊 tabBar 的下標(biāo),獲取到這個(gè)下標(biāo)之前的模塊 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
              }
          })
      }
      
    • 根據(jù)判斷出來是不是 tabBar 中最后一個(gè)標(biāo)題幽崩,然后拿 widthXindexWidth 然后去判斷編寫邏輯。

      let moveX;
      // index*20 是每個(gè)模塊的空隙 20
      if (widthX + index * 20 > widthHalf && index != tmpArrX.length - 1) {
          moveX = (widthX - widthHalf + indexWidth) / 2
      } else if (index == tmpArrX.length - 1) {
          //index + 1 :間距比個(gè)數(shù)多一個(gè); 10 :marGinLeft = 10
          moveX = (index + 1) * 20 + widthX - SCREEN_WIDTH + 10
      }
      
      // 頁面中  tabBar 的 x 軸移動(dòng)
      this.refs.moveX.scrollTo({x: autoWidth(moveX)})
      
  • 實(shí)現(xiàn)編輯模式下:數(shù)據(jù)的 新增刪除 的代碼(段子手快餓死了寞钥,寫不動(dòng)注釋了 ......)

      //數(shù)組的加減
      _addOrDelete(keyType, data, i) {
          console.log('data===' + JSON.stringify(data) + '===' + i);
          //更改 severListType 的數(shù)據(jù)
          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 :用來存儲(chǔ)選中的截取的 id
                      this.state.severListType = severListType.filter((item) => {
                          return item.id != data.id
                      });
                      //編輯模式下慌申,是否為已有模塊, true:加號(hào),false:減號(hào)
                      data.select = !tmpType;
                  }
                  break;
              case 2:
              case 3:
                  if (!tmpType) {
                      if (severListType.length > 10) {
                          RootToast.show('首頁最多添加 11 個(gè)應(yīng)用')
                      } else {
                          severListType.push(data)
                      }
                  } else {
                      //獲取輸入的值和在另一個(gè)模塊數(shù)組中的下標(biāo)理郑,然后刪除
                      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;
          }
          //刷新數(shù)據(jù)
          this.setState({
              severListType: this.state.severListType
          }, () => {
              // console.log('severListType===' + JSON.stringify(this.state.severListType));
    
          });
      }
    

TIP:
  • 吸頂效果在 android 低配中會(huì)出現(xiàn)卡頓現(xiàn)象蹄溉。
  • 頁面滑動(dòng)對(duì)應(yīng)的 tabBartitle 居中偏移(我的寫法還是有問題的,還有就是模塊滑動(dòng)時(shí) tabBar 對(duì)應(yīng)居中也會(huì)有卡頓)您炉。
新增手勢(shì)
  • TouchableHighlight 屬性
名稱 屬性 注釋
accessibilityComponentType View.AccessibilityComponentType 設(shè)置可訪問的組件類型
accessibilityTraits View.AccessibilityTraits 設(shè)置訪問特征
accessible bool 設(shè)置當(dāng)前組件是否可以訪問
delayLongPress View.AccessibilityTraits 設(shè)置當(dāng)前組件是否可以訪問
accessibilityTraits number 設(shè)置延遲的時(shí)間柒爵,單位為毫秒。從 onPressIn 方法開始赚爵,到 onLongPress 被調(diào)用這一段時(shí)間
delayPressIn number 設(shè)置延遲的時(shí)間餐弱,單位為毫秒宴霸,從用戶觸摸控件開始到 onPressIn 被調(diào)用這一段時(shí)間
delayPressOut number 設(shè)置延遲的時(shí)間,單位為毫秒膏蚓,從用戶觸摸事件釋放開始到 onPressOut 被調(diào)用這一段時(shí)間
onLayout function 當(dāng)組件加載或者改組件的布局發(fā)生變化的時(shí)候調(diào)用瓢谢。調(diào)用傳入的參數(shù)為 {nativeEvent:{layout:{x,y,width,height}}}
onLongPress function 當(dāng)用戶長時(shí)間按壓組件(長按效果)的時(shí)候調(diào)用該方法
onPress function 當(dāng)用戶點(diǎn)擊的時(shí)候調(diào)用(觸摸結(jié)束)。 但是如果事件被取消了就不會(huì)調(diào)用驮瞧。(例如:當(dāng)前被滑動(dòng)事件所替代)
onPressIn function 用戶開始觸摸組件回調(diào)方法
onPressOut function 用戶完成觸摸組件之后回調(diào)方法
pressRetentionOffset {top: ,left: ,bottom: ,right: } 該設(shè)置當(dāng)視圖滾動(dòng)禁用的情況下氓扛,可以定義當(dāng)手指距離組件的距離。當(dāng)大于該距離該組件會(huì)失去響應(yīng)论笔。當(dāng)少于該距離的時(shí)候采郎,該組件會(huì)重新進(jìn)行響應(yīng)。確保你傳入一個(gè)常量來減少內(nèi)存分配狂魔。

段子手不才蒜埋,歡迎來補(bǔ)充
  • 由于篇幅原因,具體想要知道整個(gè)效果圖的代碼或者有補(bǔ)充地方的可以加技術(shù)群:631730313
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末最楷,一起剝皮案震驚了整個(gè)濱河市整份,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌籽孙,老刑警劉巖烈评,帶你破解...
    沈念sama閱讀 217,185評(píng)論 6 503
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異犯建,居然都是意外死亡讲冠,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,652評(píng)論 3 393
  • 文/潘曉璐 我一進(jìn)店門适瓦,熙熙樓的掌柜王于貴愁眉苦臉地迎上來竿开,“玉大人,你說我怎么就攤上這事玻熙》癫剩” “怎么了?”我有些...
    開封第一講書人閱讀 163,524評(píng)論 0 353
  • 文/不壞的土叔 我叫張陵揭芍,是天一觀的道長胳搞。 經(jīng)常有香客問我卸例,道長称杨,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,339評(píng)論 1 293
  • 正文 為了忘掉前任筷转,我火速辦了婚禮姑原,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘呜舒。我一直安慰自己锭汛,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,387評(píng)論 6 391
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著唤殴,像睡著了一般般婆。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上朵逝,一...
    開封第一講書人閱讀 51,287評(píng)論 1 301
  • 那天蔚袍,我揣著相機(jī)與錄音,去河邊找鬼配名。 笑死啤咽,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的渠脉。 我是一名探鬼主播宇整,決...
    沈念sama閱讀 40,130評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼芋膘!你這毒婦竟也來了鳞青?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 38,985評(píng)論 0 275
  • 序言:老撾萬榮一對(duì)情侶失蹤索赏,失蹤者是張志新(化名)和其女友劉穎盼玄,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體潜腻,經(jīng)...
    沈念sama閱讀 45,420評(píng)論 1 313
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡埃儿,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,617評(píng)論 3 334
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了融涣。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片童番。...
    茶點(diǎn)故事閱讀 39,779評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖威鹿,靈堂內(nèi)的尸體忽然破棺而出剃斧,到底是詐尸還是另有隱情,我是刑警寧澤忽你,帶...
    沈念sama閱讀 35,477評(píng)論 5 345
  • 正文 年R本政府宣布幼东,位于F島的核電站,受9級(jí)特大地震影響科雳,放射性物質(zhì)發(fā)生泄漏根蟹。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,088評(píng)論 3 328
  • 文/蒙蒙 一糟秘、第九天 我趴在偏房一處隱蔽的房頂上張望简逮。 院中可真熱鬧,春花似錦尿赚、人聲如沸散庶。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,716評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽悲龟。三九已至屋讶,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間须教,已是汗流浹背丑婿。 一陣腳步聲響...
    開封第一講書人閱讀 32,857評(píng)論 1 269
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留没卸,地道東北人羹奉。 一個(gè)月前我還...
    沈念sama閱讀 47,876評(píng)論 2 370
  • 正文 我出身青樓,卻偏偏與公主長得像约计,于是被迫代替她去往敵國和親诀拭。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,700評(píng)論 2 354

推薦閱讀更多精彩內(nèi)容

  • Lua 5.1 參考手冊(cè) by Roberto Ierusalimschy, Luiz Henrique de F...
    蘇黎九歌閱讀 13,791評(píng)論 0 38
  • 在C語言中,五種基本數(shù)據(jù)類型存儲(chǔ)空間長度的排列順序是: A)char B)char=int<=float C)ch...
    夏天再來閱讀 3,341評(píng)論 0 2
  • "use strict";function _classCallCheck(e,t){if(!(e instanc...
    久些閱讀 2,030評(píng)論 0 2
  • SwiftDay011.MySwiftimport UIKitprintln("Hello Swift!")var...
    smile麗語閱讀 3,834評(píng)論 0 6
  • “孩子煤蚌,不要怕耕挨,叔叔帶你去玩一會(huì) 兒”老男人猥瑣的聲音傳入女孩的耳朵里, 女孩害怕的不知所措尉桩。 不一會(huì)兒筒占,車停下了...
    盈盈子清閱讀 623評(píng)論 1 3