RN手勢

React Native框架底層的手勢響應(yīng)系統(tǒng)提供了響應(yīng)處理器朗若,PanResponder API將這些手勢響應(yīng)處理器再次進行封裝,便于開發(fā)者對手勢進行處理昌罩。
PanResponser API的基本思想就是:監(jiān)視屏幕上指定的位置的矩形區(qū)域哭懈。對手指觸發(fā)的事件作出響應(yīng)。
一茎用、利用PanResponser API監(jiān)視的步驟
1遣总、指定監(jiān)視區(qū)域
為了監(jiān)視一個區(qū)域,我們需要準(zhǔn)備一個view或者是從view組件擴展而來的組件轨功。(注意:如果要監(jiān)視兩個區(qū)域旭斥,一定不能讓他們重疊,不然監(jiān)視器無法工作)
2夯辖、定義監(jiān)視器的相關(guān)變量
指向監(jiān)視器的變量(必須)琉预。
用來指向監(jiān)視器監(jiān)視區(qū)域的變量,可以不定義蒿褂。
用來記錄監(jiān)視區(qū)域左上角頂點坐標(biāo)的兩個數(shù)值變量圆米。可以不定義啄栓。但當(dāng)觸摸發(fā)生需要給用戶視覺上的反饋時娄帖,有這個變量可以很容易實現(xiàn)反饋。
上一次觸摸點的橫昙楚、縱坐標(biāo)變量近速。可以不定義,但這兩個變量可以便于分析削葱、處理觸摸事件奖亚。
3、準(zhǔn)備監(jiān)視器的事件處理函數(shù)
一共有13個這樣的函數(shù)析砸,比如說onMoveShouldSetPanResponder用來判斷是否要監(jiān)視這個區(qū)域昔字,onMoveShouldSetPanResponderCapture等。那我們只需要挑選出自己需要的函數(shù)來開發(fā)就可以了首繁。
以下是監(jiān)視器的13個事件處理函數(shù)

 onMoveShouldSetPanResponder
 onMoveShouldSetPanResponderCapture
 onStartShouldSetPanResponder
 onStartShouldSetPanResponderCapture
 onPanResponderReject
 onPanResponderGrant
 onPanResponderStart
 onPanResponderEnd
 onPanResponderRelease
 onPanResponderMove
 onPanResponderTerminate
 onPanResponderTerminateRequest
 onShouldBlockNativeResponder

4作郭、建立監(jiān)視器
用PanResponder API提供的靜態(tài)函數(shù)create,建立監(jiān)聽器

this.watcher = PanResponder.create({
  ……
})

5弦疮、將監(jiān)視器和監(jiān)視區(qū)域掛接
我們先假設(shè)一下夹攒,監(jiān)視器就叫watcher。

{...this.watcher.panHandlers}

二胁塞、監(jiān)視事件的生命周期
一般來說咏尝,在點擊的生命周期我們自定義的被回調(diào)的函數(shù)都會收到兩個參數(shù),一個是原生事件闲先,另一個是手勢狀態(tài)状土。
而這里面會有很多的成員變量比如說觸摸點的位置无蜂,比如說手勢狀態(tài)的ID.
手勢狀態(tài)有以下變量

stateID—觸摸狀態(tài)的ID伺糠,在屏幕上至少有一個點的情況下,這個id會一直存在斥季。
moveX—最近一次移動時的屏幕橫坐標(biāo)
moveY—最近一次移動時的屏幕縱坐標(biāo)
x0—當(dāng)響應(yīng)器產(chǎn)生時的屏幕坐標(biāo)
y0—當(dāng)響應(yīng)器產(chǎn)生時的屏幕坐標(biāo)
dx—從觸摸開始累積的橫向路程
dy—從觸摸操作開始累積縱向路程
vx—當(dāng)前的橫向移動速度
vy—當(dāng)前的縱向移動速度
numberActiveTouches—當(dāng)前在屏幕上的有效觸摸點的數(shù)量训桶。

三、單次點擊事件的生命周期
onStartShouldSetPanResponderCapture:是否設(shè)置開始捕捉這次事件
onStartResponderStart:將這個事件視為點擊事件的開始點
onPanResponderEnd:將這個事件視為點擊事件的結(jié)束點酣倾。
這里列舉出的三個生命周期方法是最常見的舵揭,但是其實它還有其他很多的方法。不過我們平常用的單次點擊事件就是這三個躁锡。
在移動手勢中午绳,也有它自己的生命周期方法。這里不做詳解映之。通過下面一個小的案例進行解說盅弛。

四侨拦、案例
滑動解鎖:手指按壓的滑塊跟隨手指移動,按壓的監(jiān)視區(qū)域隨著手指移動而變化

75353037-EE9F-4BA8-8283-8B2F9528F7BF.png

從圖中我們可以看到,在這個RN界面中需要返回一個頂級元素view,然后在里面添加一個滑塊槽禀苦,之后是按鈕。
這個按鈕會有一個樣式呻澜,我們可以將它切成一個圓的樣子滥崩。并且,這個按鈕是需要滑動的,所以要給它添加一個表示距離滑動槽原點的位置搞糕。而這個樣式是需要及時改變的勇吊,所以我們可以定義一個狀態(tài)機。用leftPoint來表示它的位置窍仰。

export default class GusDemo extends Component {
  constructor(props){
    super(props);
    this.watcher = null;   //監(jiān)視器
    this.startX = 0; //開始的左邊
    this.state = {leftPoint:1}  //狀態(tài)機變量用來保存最左邊的卡槽
}

返回的UI界面

render() {
    return (
      <View style={styles.container}>
         <View style = {styles.barViewStyle}>
            <View style = {[styles.buttonViewStyle,{left:this.state.leftPoint}]}
                  {...this.watcher.panHandlers}  //將監(jiān)視器與監(jiān)視區(qū)域掛接
            />
        </View>
      </View>
    );
  }

設(shè)置樣式
首先要獲取寬度萧福。

var Dimensions = require('Dimensions');
var totalWidth = Dimensions.get('window').width;  //寬度

設(shè)置樣式

const styles = StyleSheet.create({
  container: {
    flex: 1,

    backgroundColor: '#F5FCFF',
  },
  barViewStyle: {
      width:totalWidth - 40,
      height:50,
    backgroundColor:'grey',
    borderRadius:25,
    left:20,
    top:50,
    flexDirection:'row',
  },
  buttonViewStyle: {
      width:48,
      height:48,
     borderRadius:24,
    backgroundColor:'pink',
    left:1,
    top:1,
  }
});

自此,所有的UI部分已經(jīng)構(gòu)建完畢辈赋,現(xiàn)在要做的就是到componentWillMount()方法里面去建立監(jiān)視器鲫忍。為啥要在這個方法里面呢,是因為這個方法在UI渲染之前運行的钥屈,我們可以讓它來做一些定義變量或賦值的操作悟民。所以我們將事件的按下、移動和結(jié)束的方法都寫到這邊來篷就。分別給這幾個屬性各自定義一個方法射亏。

componentWillMount(){
    this.watcher = PanResponder.create({  //建立監(jiān)視器
      onStartShouldSetPanResponder:()=>true,  //判斷是否要監(jiān)聽,這里直接返回true
      onPanResponderGrant:this._onPanResponderGrant,  //事件,按下
      onPanResponderMove:this._onPanResponderMove,  //移動
      onPanResponderEnd:this._onPanResponderEnd,   //結(jié)束

    });
  }

這些方法我們都用簡寫的方式竭业,所以到構(gòu)造函數(shù)中將它們綁定一下智润。

export default class GusDemo extends Component {
  constructor(props){
    super(props);
    this.watcher = null;   //監(jiān)視器
    this.startX = 0; //開始的左邊
    this.state = {leftPoint:1}  //狀態(tài)機變量用來保存最左邊的卡槽
    this._onPanResponderGrant = this._onPanResponderGrant.bind(this);
    this._onPanResponderEnd = this._onPanResponderEnd.bind(this);
    this._onPanResponderMove = this._onPanResponderMove.bind(this);
  }

現(xiàn)在來具體實現(xiàn)自定義的方法。雖然我們看到的是簡寫的方法未辆,但是實際上窟绷,系統(tǒng)按下的方法會給我們自定義的這個方法傳入兩個參數(shù),一個是事件咐柜,而另外一個是手指觸摸的位置兼蜈。在開始的時候,我們要將開始偏移的位置給記錄下來拙友。因為每次開始滑動的時候位置其實都是不一樣的为狸。

 _onPanResponderGrant(e,gestureState){
    this.startX = gestureState.x0;   //按住滑塊的時候,記錄偏移量
  }

下面來寫移動按鈕的時候的邏輯

_onPanResponderMove(e,gestureState){
    let leftPoint;   //用一個變量記錄滑動的偏移值
    if(gestureState.moveX > totalWidth-42-48+this.startX){  //正常位置
      leftPoint = totalWidth - 42 - 48;
    }else{
      leftPoint = gestureState.moveX - this.startX; //在后面可以寫解鎖或者是跳轉(zhuǎn)效果。
    }
    this.setState(()=>{
      return {leftPoint};    //改變狀態(tài)機
    })
  }

當(dāng)手指松開之后遗契,我們在這里不做復(fù)雜的判斷辐棒,直接讓它移動到最原始的位置。

 _onPanResponderEnd(e,gestureState){
      let leftPoint = 1;
    this.setState(()=>{
      return {leftPoint};   //改變狀態(tài)機到1的位置
    })
  }

滑動解鎖的案例就完成了牍蜂。

下面是源碼index.ios.js

import React, { Component } from 'react';
import {
  AppRegistry,
  StyleSheet,
  Text,
  View,
  PanResponder
} from 'react-native';
var Dimensions = require('Dimensions');
var totalWidth = Dimensions.get('window').width;  //寬度
export default class GusDemo extends Component {
  constructor(props){
    super(props);
    this.watcher = null;   //監(jiān)視器
    this.startX = 0; //開始的左邊
    this.state = {leftPoint:1}  //狀態(tài)機變量用來保存最左邊的卡槽

    this._onPanResponderGrant = this._onPanResponderGrant.bind(this);
    this._onPanResponderEnd = this._onPanResponderEnd.bind(this);
    this._onPanResponderMove = this._onPanResponderMove.bind(this);


  }

  componentWillMount(){
    this.watcher = PanResponder.create({  //建立監(jiān)視器
      onStartShouldSetPanResponder:()=>true,
      onPanResponderGrant:this._onPanResponderGrant,  //事件,按下
      onPanResponderMove:this._onPanResponderMove,  //移動
      onPanResponderEnd:this._onPanResponderEnd,   //結(jié)束

    });
  }

  //移動的邏輯
  _onPanResponderGrant(e,gestureState){
    this.startX = gestureState.x0;   //按住滑塊的時候,記錄偏移量
  }
  _onPanResponderMove(e,gestureState){
    let leftPoint;   //用一個變量記錄滑動的偏移值
    if(gestureState.moveX > totalWidth-42-48+this.startX){  //正常位置
      leftPoint = totalWidth - 42 - 48;
    }else{
      leftPoint = gestureState.moveX - this.startX; //在后面可以寫解鎖或者是跳轉(zhuǎn)效果漾根。
    }
    this.setState(()=>{
      return {leftPoint};    //改變狀態(tài)機
    })
  }
  _onPanResponderEnd(e,gestureState){
      let leftPoint = 1;
    this.setState(()=>{
      return {leftPoint};   //改變狀態(tài)機到1的位置
    })
  }
  render() {
    return (
      <View style={styles.container}>
         <View style = {styles.barViewStyle}>
            <View style = {[styles.buttonViewStyle,{left:this.state.leftPoint}]}
                  {...this.watcher.panHandlers}
            />
        </View>
      </View>
    );
  }
}

const styles = StyleSheet.create({
  container: {
    flex: 1,

    backgroundColor: '#F5FCFF',
  },
  barViewStyle: {
      width:totalWidth - 40,
      height:50,
    backgroundColor:'grey',
    borderRadius:25,
    left:20,
    top:50,
    flexDirection:'row',
  },
  buttonViewStyle: {
      width:48,
      height:48,
     borderRadius:24,
    backgroundColor:'pink',
    left:1,
    top:1,
  }
});

AppRegistry.registerComponent('GusDemo', () => GusDemo);

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市捷兰,隨后出現(xiàn)的幾起案子立叛,更是在濱河造成了極大的恐慌,老刑警劉巖贡茅,帶你破解...
    沈念sama閱讀 216,402評論 6 499
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件秘蛇,死亡現(xiàn)場離奇詭異其做,居然都是意外死亡,警方通過查閱死者的電腦和手機赁还,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,377評論 3 392
  • 文/潘曉璐 我一進店門妖泄,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人艘策,你說我怎么就攤上這事蹈胡。” “怎么了朋蔫?”我有些...
    開封第一講書人閱讀 162,483評論 0 353
  • 文/不壞的土叔 我叫張陵罚渐,是天一觀的道長。 經(jīng)常有香客問我驯妄,道長荷并,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,165評論 1 292
  • 正文 為了忘掉前任青扔,我火速辦了婚禮源织,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘微猖。我一直安慰自己谈息,他們只是感情好,可當(dāng)我...
    茶點故事閱讀 67,176評論 6 388
  • 文/花漫 我一把揭開白布凛剥。 她就那樣靜靜地躺著侠仇,像睡著了一般。 火紅的嫁衣襯著肌膚如雪当悔。 梳的紋絲不亂的頭發(fā)上傅瞻,一...
    開封第一講書人閱讀 51,146評論 1 297
  • 那天踢代,我揣著相機與錄音盲憎,去河邊找鬼。 笑死胳挎,一個胖子當(dāng)著我的面吹牛饼疙,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播慕爬,決...
    沈念sama閱讀 40,032評論 3 417
  • 文/蒼蘭香墨 我猛地睜開眼窑眯,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了医窿?” 一聲冷哼從身側(cè)響起磅甩,我...
    開封第一講書人閱讀 38,896評論 0 274
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎姥卢,沒想到半個月后卷要,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體渣聚,經(jīng)...
    沈念sama閱讀 45,311評論 1 310
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,536評論 2 332
  • 正文 我和宋清朗相戀三年僧叉,在試婚紗的時候發(fā)現(xiàn)自己被綠了奕枝。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 39,696評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡瓶堕,死狀恐怖隘道,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情郎笆,我是刑警寧澤谭梗,帶...
    沈念sama閱讀 35,413評論 5 343
  • 正文 年R本政府宣布,位于F島的核電站宛蚓,受9級特大地震影響默辨,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜苍息,卻給世界環(huán)境...
    茶點故事閱讀 41,008評論 3 325
  • 文/蒙蒙 一缩幸、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧竞思,春花似錦表谊、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,659評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至课梳,卻和暖如春距辆,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背暮刃。 一陣腳步聲響...
    開封第一講書人閱讀 32,815評論 1 269
  • 我被黑心中介騙來泰國打工跨算, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人椭懊。 一個月前我還...
    沈念sama閱讀 47,698評論 2 368
  • 正文 我出身青樓诸蚕,卻偏偏與公主長得像,于是被迫代替她去往敵國和親氧猬。 傳聞我的和親對象是個殘疾皇子背犯,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 44,592評論 2 353

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

  • Android 自定義View的各種姿勢1 Activity的顯示之ViewRootImpl詳解 Activity...
    passiontim閱讀 172,072評論 25 707
  • 發(fā)現(xiàn) 關(guān)注 消息 iOS 第三方庫、插件盅抚、知名博客總結(jié) 作者大灰狼的小綿羊哥哥關(guān)注 2017.06.26 09:4...
    肇東周閱讀 12,093評論 4 62
  • 頸椎病誤區(qū):"米字操" 在電腦前坐久了漠魏,不少人有喜歡“搖頭晃腦”的習(xí)慣,有的稱之為“米字操”妄均,目的是為了防頸椎病柱锹。...
    文五閱讀 452評論 0 1
  • 我深深懂得:給別人留下尊重和尊嚴(yán)破讨,給別人留下空間和余地,才會給自己留下最美好的東西奕纫,還有值得懷念的友誼提陶、親情和愛情!
    簡俊智閱讀 137評論 0 0
  • 打開籠子 一只白鴿飛遠(yuǎn)了 從此 我 一個人 成了深深的孤獨患者
    伍月的晴空閱讀 195評論 7 4