第三章 View的事件体系
2019-01-10 本文已影响0人
ByteStefan
-
TouchSlop
系统所能识别的最小滑动距离。可通过 ViewConfiguration.get(getContext).getScaledTouchSlop() 获取这个常量。 -
VelocityTracker
速度追踪,用于追踪手指在滑动过程中的速度,包括水平和竖直方向。
//在 onTouchEvent 中跟踪
override fun onTouchEvent(event: MotionEvent?): Boolean {
val velocityTracker = VelocityTracker.obtain()
velocityTracker.addMovement(event)
//计算1s内的速度
velocityTracker.computeCurrentVelocity(1000)
Log.e("ASD123","${velocityTracker.xVelocity} --- ${velocityTracker.yVelocity}")
return super.onTouchEvent(event)
}
//在不需要的时候清除回收掉
velocityTracker.clear()
velocityTracker.recycle()
- GestureDetector
手势监听,用于辅助检测用户的单击、滑动、长按、双击等行为。
val mGestureDetector by lazy {
GestureDetector(this, object : GestureDetector.OnGestureListener {
override fun onShowPress(p0: MotionEvent?) {
Log.e("ASD123", "手指轻轻触摸屏幕,尚未松开和拖动")
}
override fun onSingleTapUp(p0: MotionEvent?): Boolean {
Log.e("ASD123", "手指轻轻触摸屏幕松开--单击")
return true
}
override fun onDown(p0: MotionEvent?): Boolean {
Log.e("ASD123", "手指轻轻触摸屏幕")
return true
}
override fun onFling(p0: MotionEvent?, p1: MotionEvent?, p2: Float, p3: Float): Boolean {
Log.e("ASD123", "手指按下屏幕并拖动 -- 拖动")
return true
}
override fun onScroll(p0: MotionEvent?, p1: MotionEvent?, p2: Float, p3: Float): Boolean {
Log.e("ASD123", "快速滑动")
return true
}
override fun onLongPress(p0: MotionEvent?) {
Log.e("ASD123", "手指按下屏幕不放 -- 长按")
}
})
}
override fun onTouchEvent(event: MotionEvent?): Boolean {
mGestureDetector.setOnDoubleTapListener(object :GestureDetector.OnDoubleTapListener{
override fun onDoubleTap(p0: MotionEvent?): Boolean {
Log.e("ASD123", "手指两次连续单击 -- 双击")
return true
}
override fun onDoubleTapEvent(p0: MotionEvent?): Boolean {
Log.e("ASD123", "发生了双击行为,在双击期间,ACTION_DOWN、ACTION_MOVE、ACTION_UP都会触法此回调")
return true
}
override fun onSingleTapConfirmed(p0: MotionEvent?): Boolean {
Log.e("ASD123", "严格的单击行为")
return true
}
})
return mGestureDetector.onTouchEvent(event)
}
- View 的事件分发机制
dispatchTouchEvent -> onInterceptTouchEvent -> onTouchEvent
事件传递的机制:
① 同一个事件序列是指从手指接触屏幕的那一刻起,到手指离开屏幕的那一刻结束,在这个过程中产生的一系列事件,这个事件序列以 down 事件开始,中间含有数量不定的 move 事件,最终以 up 事件结束。
② 正常情况下,一个事件序列只能被一个 View 拦截且消耗。除非通过特殊手段,如一个 View 将本该自己处理的事件通过 onTouchEvent 强行传递给其他 View 处理。
③ 某个 View 一旦决定拦截,那么这一个事件序列都只能由它来处理,并且它的 onInterceptTouchEvent 不会再被调用。
④ 某个 View 一旦开始处理事件,如果它不消耗 ACTION_DOWN 事件(onTouchEvent 返回了 false),那么同一事件序列中的其他事件都不会再交给它来处理,并且事件将重新交由它的父元素去处理,即调用父元素的 onTuchEvent。
⑤ 如果 View 不消耗除 ACTION_DOWN 以外的其他事件,那么这个点击事件会消失,此时父元素的 onTouchEvent 并不会都调用,并且当前 View 可以持续收到后续事件,最终这些消失的点击事件会传递到 Activity 处理。
⑥ ViewGroup 默认不拦截任何时间,即 ViewGroup 的 onInterceptTouchEvent 方法默认返回 false
⑦ View 没有 onInterceptTouchEvent 方法,一旦有点击事件传递给它,那么它的 onTouchEvent 方法就会被调用。
⑧ View 的 onTouchEvent 默认都会消耗事件(返回 true),除非它是不可点击的(clickable 和 longClickable 同时为 false)。View 的 longClickable 属性默认都为 false,clickable 属性要分情况,Button 默认为 true,TextView 默认为 false
⑨ View 的 enable 属性不影响 onTouchEvent 的默认返回值。
⑩ onClick 会发生的前提是当前 View 是可点击的,并且它收到了 down 和 up 事件。
⑪ 事件传递过程是由外向内的,即事件总是先传递给父元素,然后再由父元素分发给子 View,通过 requestDisallowInterceptTouchEvent 方法可以在子元素中干预父元素的事件分发过程,但是 ACTION_DOWN 事件除外。