ReactNative之手勢識別

ReactNative

  • 原文博客地址: ReactNative之手勢識別
  • 移動開發中最重要的就是交互, 說到交互, 就不得不說觸摸事件
  • iOS中有單擊, 雙擊, 長按, 拖拽等觸摸操做
  • React Native中點擊手勢都有其對應的組件, 每一個組件均可以用來包裹視圖來響應用戶的點擊事件

TouchableWithoutFeedback

  • 響應用戶的點擊事件, 點擊操做時, 組件沒有任何視覺反饋,看起來像Web效果而不是原生的效果Native
  • 是單節點組件, 只能包含一個組件, 若是你但願包含多個子組件,用一個View來包裝它們
  • 該控件除非你不得不使用,不然請不要使用該組件

屬性方法

  • accessibilityComponentType: View.AccessibilityComponentType
    設置可訪問的組件類型html

  • accessibilityTraits: View.AccessibilityTraits,[View.AccessibilityTraits] 設置訪問特徵android

  • accessible: bool
    設置當前組件是否能夠訪問數組

  • delayLongPress: number 設置延遲的時間,單位爲毫秒。從onPressIn方法開始,到onLongPress被調用這一段時間微信

  • delayPressIn: number 設置延遲的時間,單位爲毫秒,從用戶觸摸控件開始到onPressIn被調用這一段時間框架

  • delayPressOut: number
    設置延遲的時間,單位爲毫秒,從用戶觸摸事件釋放開始到onPressOut被調用這一段時間ide

  • onLayout: function
    當組件加載或者改組件的佈局發生變化的時候調用, 調用傳入的參數爲{nativeEvent:{layout:{x,y,width,height}}}函數

  • onLongPress: function
    當用戶長時間按壓組件(長按效果)的時候調用該方法佈局

  • onPress: function 當用戶點擊的時候調用(觸摸結束)。 可是若是事件被取消了就不會調用。(例如:當前被滑動事件所替代)ui

  • onPressIn: function
    用戶開始觸摸組件回調方法this

  • onPressOut: function 用戶完成觸摸組件以後回調方法

  • pressRetentionOffset: {top:number,left:number,bottom:number,right:number} 該設置當視圖滾動禁用的狀況下,能夠定義當手指距離組件的距離; 當大於該距離該組件會失去響應;當少於該距離的時候,該組件會從新進行響應

該組件咱們通常不會直接進行使用,下面三種Touchable*系列組件對於該組件的屬性方法均可以進行使用

TouchableOpacity

該組件封裝了響應觸摸事件。當點擊按下的時候,該組件的透明度會下降。該組件使用過程當中並不會改變視圖的層級關係,並且咱們能夠很是容易的添加到應用而且不會產生額外的異常錯誤

屬性方法

  • TouchableWithoutFeedback的全部 屬性,這邊TouchableOpacity組件所有能夠進行使用
  • activeOpacity: number---設置當用戶觸摸的時候,組件的透明度(取值0-1)

TouchableHighlight

當手指點擊按下的時候,該視圖的不透明度會進行下降同時會看到相應的顏色(視圖變暗或者變亮)。若是咱們去查看該組件的源代碼會發現,該底層實現是添加了一個新的視圖

屬性方法

  • 全部TouchableWithoutFeedback的屬性
  • activeOpacity: number---該用來設置視圖在進行觸摸的時候,要要顯示的不透明度(一般在0-1之間)
  • onHideUnderlay: function---當底層被隱藏的時候調用
  • onShowUnderlay: function---當底層顯示的時候調用
  • underlayColor: 當觸摸或者點擊控件的時候顯示出的顏色

TouchableNativeFeedback

  • 僅限Android平臺
  • Android設備上,這個組件利用原生狀態來渲染觸摸的反饋
  • 目前它只支持一個單獨的View實例做爲子節點

屬性方法

  • 全部TouchableWithoutFeedback的屬性
  • background: 決定在觸摸反饋的時候顯示什麼類型的背景

PanResponder

相關介紹

PanResponder類能夠將多點觸摸操做協調成一個手勢。它使得一個單點觸摸能夠接受更多的觸摸操做,也能夠用於識別簡單的多點觸摸手勢

手勢處理

React Native框架底層的手勢響應系統提供了響應處理器,PanResponder將這些手勢響應處理器再次進行封裝,以便開發者更容易對手勢進行處理,更容易預測用戶的手勢,對每個手勢響應處理器,PanResponder除了爲其提供表明觸摸行爲的原生事件外,還提供了一個新的手勢狀態對象用來詳細描述手勢的狀態

基本思想是:

監視屏幕上指定大小、位置的矩形區域,當用手指按壓這個區域中的某點後,開發者會收到這個事件,當按壓後拖動手指時,會收到手勢引起的各種事件,當手指離開這個矩形區域時,開發者也會收到相應的事件

注意事項:

  • 開發者能夠任意指定監視矩形區域的大小,但在這個區域裏,只有第一個按下的事件會上報和繼續監視處理,若是第一個手指按下尚未離開,接着第二個手指又來按下了,那麼對第二個手指的各類觸摸事件沒法捕獲
  • 開發者能夠在屏幕上指定多個監視矩形區域,可是不能同時監視多個矩形區域的不一樣觸摸事件
  • 監視區域會阻止被監視區域覆蓋的組件接收觸摸事件,好比監視區域覆蓋了一個按鈕,那麼就沒法經過按這個按鈕來觸發其對應的事件,只能在PanResponder監視器的事件處理中對觸摸行爲進行處理

使用操做

利用PanResponder實現監視器有如下幾個步驟:

指定監視區域

若是監視區域有多個,必定不能重疊,不然都失效

定義監視器相關變量

指向監視器的變量(必須有)、指向監視器監視區域的變量(能夠有)、記錄監視區域左上角頂點座標的兩個數值變量(能夠有)、上一次觸摸點的橫縱座標變量(能夠有)

事件處理

準備監視器的事件處理函數

創建監視器

PanResponder.create(config)

相關事件監聽

// 返回值爲布爾值, 若是返回值爲 true,則表示這個 View 可以響應滑動手勢, 二者有一個爲true便可響應
onMoveShouldSetPanResponder: (e, gestureState) => {...}
onMoveShouldSetPanResponderCapture: (e, gestureState) => {...}

// 返回值爲布爾值, 若是返回值爲 true,則表示這個 View 可以響應觸摸手勢, 二者有一個爲true便可響應
onStartShouldSetPanResponder: (e, gestureState) => {...}
onStartShouldSetPanResponderCapture: (e, gestureState) => {...}

// 當前有其餘的東西成爲響應器而且沒有釋放它。若是視圖正在響應,會觸發該方法
onPanResponderReject: (e, gestureState) => {...}
// 最近一次的移動距離.如:(獲取x軸方向的移動距離 gestureState.dx)
onPanResponderGrant: (e, gestureState) => {...}
// 開始按下時的響應事件
onPanResponderStart: (e, gestureState) => {...}
// 結束按下時的響應事件
onPanResponderEnd: (e, gestureState) => {...}
// 用戶手指離開屏幕時,調用該方法
onPanResponderRelease: (e, gestureState) => {...}
// 用戶滑動手指時,調用該方法
onPanResponderMove: (e, gestureState) => {...}

// 另外一個組件已經成爲了新的響應者,因此當前手勢將被取消
onPanResponderTerminate: (e, gestureState) => {...}
// 若是回調函數返回爲 true,則表示贊成釋放響應者角色 同時會回調onResponderTerminate函數,通知組件事件響應處理被終止了
onPanResponderTerminationRequest: (e, gestureState) => {...}

// 返回一個布爾值,決定當前組件是否應該阻止原生組件成爲JS響應者(暫只支持android)
onShouldBlockNativeResponder: (e, gestureState) => {...}
複製代碼

監視器與監視區域關聯

{…this.watcher.panHandlers}

實例:點擊、拖動選擇百分百參數 好比說播放器的音量大小

參數event(e)

獲取觸摸的位置在被響應的 View 中的相對座標,evt.nativeEvent.locationX

  • nativeEvent
    • changedTouches - 在上一次事件以後,全部發生變化的觸摸事件的數組集合(即上一次事件後,全部移動過的觸摸點)
    • identifier - 觸摸點的ID
    • locationX - 觸摸點相對於父元素的橫座標
    • locationY - 觸摸點相對於父元素的縱座標
    • pageX - 觸摸點相對於根元素的橫座標
    • pageY - 觸摸點相對於根元素的縱座標
    • target - 觸摸點所在的元素ID
    • timestamp - 觸摸事件的時間戳,可用於移動速度的計算
    • touches - 當前屏幕上的全部觸摸點的集合

gestureState對象

  • stateID -- 觸摸狀態的ID。在屏幕上有至少一個觸摸點的狀況下,這個ID會一直有效。
  • moveX - 最近一次移動時的屏幕橫座標
  • moveY - 最近一次移動時的屏幕縱座標
  • x0 - 當響應器產生時的屏幕座標
  • y0 - 當響應器產生時的屏幕座標
  • dx - 從觸摸操做開始時的累計橫向路程
  • dy - 從觸摸操做開始時的累計縱向路程
  • vx - 當前的橫向移動速度
  • vy - 當前的縱向移動速度
  • numberActiveTouches - 當前在屏幕上的有效觸摸點的數量

使用示例

相關代碼

export default class MyApp extends Component {

    constructor(props) {
        super(props)

        this.state = {
            backColor: 'red',
            left: 0,
            top: 100
        }
    }
    
    componentWillMount() {
        this._panResponse = PanResponder.create({
            onStartShouldSetPanResponder: () => true,
            onStartShouldSetPanResponderCapture: () => false,
            onMoveShouldSetPanResponder: () => true,
            onPanResponderGrant: () => {
                this._top = this.state.top
                this._left = this.state.left
                this.setState({ backColor: 'red' })
            },
            onPanResponderMove: (event, ges) => {
                console.log(`event = ${event}, guesture = ${ges}`)
                this.setState({
                    top: this._top + ges.dy,
                    left: this._left + ges.dx,
                    backColor: 'blue'
                })
            },
            onPanResponderRelease: (event, ges) => {
                this.setState({
                    backColor: 'orange'
                })
            }
        })
    }


    render() {
        return (
            <View style={styles.container}> <View {...this._panResponse.panHandlers} style={{ position: 'absolute', backgroundColor: this.state.backColor, left: this.state.left, top: this.state.top, width: 50, height: 50 }} /> </View> ); } } 複製代碼

歡迎您掃一掃下面的微信公衆號,訂閱個人博客!

微信公衆號
相關文章
相關標籤/搜索