在App的使用过程中,经常会用到返回键。随着主流手机屏幕尺寸的增大,以及全面屏的普及,手势返回也越来越常见。如果App仅仅是在页面上固定的位置放个返回按钮,而不支持手势返回,对于用户来说,体验感就没那没好了。
本篇文章介绍下如何通过GestureDetector来实现手势回退功能。
GestureDetector
直接通过重写onTouchEvent来实现手势返回也是可以的,但GestureDetector是Android提供的用于检测常用手势的类,我们封装好了计算的代码,方便了很多。
GestureDetector实例化时需要传入的参数之一是实现GestureDetector.OnGestureListener接口的类,发生特定轻触事件时,GestureDetector.OnGestureListener 中相应的回调就会触发。
可以直接实现GestureDetector.OnGestureListener
private val gestureListener = object : GestureDetector.OnGestureListener {
override fun onDown(e: MotionEvent?): Boolean {
//首次按下
return false
}
override fun onSingleTapUp(e: MotionEvent?): Boolean {
//单击
return false
}
override fun onScroll(e1: MotionEvent?, e2: MotionEvent?, distanceX: Float, distanceY: Float): Boolean {
//滑动
return false
}
override fun onFling(e1: MotionEvent?, e2: MotionEvent?, velocityX: Float, velocityY: Float): Boolean {
//快速滑动
return false
}
override fun onShowPress(e: MotionEvent?) {
//触摸
}
override fun onLongPress(e: MotionEvent?) {
//长按
}
}
或者,当你仅需关注部分手势时,可以继承GestureDetector.SimpleOnGestureListener
private val simpleOnGestureListener = object : GestureDetector.SimpleOnGestureListener() {
override fun onFling(e1: MotionEvent?, e2: MotionEvent?, velocityX: Float, velocityY: Float): Boolean {
return super.onFling(e1, e2, velocityX, velocityY)
}
}
GestureDetector.OnGestureListener中的返回值表示是否消耗了事件,true表示事件被消耗,false表示未消耗继续向下传递。
实现手势返回
我们可以创建基类BaseActivity,在BaseActivity中实现手势返回,所有的Activity都继承BaseActivity,那么所有的Activity都支持手势返回了。
实现代码如下:
open class BaseGestureDetectorActivity : AppCompatActivity() {
private lateinit var gestureDetectorCompat: GestureDetectorCompat
private var widthPixels: Int = 0
private val simpleOnGestureListener = object : GestureDetector.SimpleOnGestureListener() {
override fun onDown(e: MotionEvent): Boolean {
onUserInteraction()
return e.x < 100 || e.x > resources.displayMetrics.widthPixels - 100
}
override fun onFling(e1: MotionEvent?, e2: MotionEvent?, velocityX: Float, velocityY: Float): Boolean {
//计算移动的距离
val distantX = abs((e2?.x ?: 0f) - (e1?.x ?: 0f))
val distantY = abs((e2?.y ?: 0f) - (e1?.y ?: 0f))
e1?.x?.let {
//判定事件起点是屏幕左侧或右侧边缘(根据需求也可以只判断一侧)
if (it < 100 || it > widthPixels - 100) {
//判定x轴移动距离大于y轴移动距离
if (distantX > distantY) {
onBackPressed()
}
}
}
return super.onFling(e1, e2, velocityX, velocityY)
}
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
gestureDetectorCompat = GestureDetectorCompat(this, simpleOnGestureListener)
widthPixels = resources.displayMetrics.widthPixels
}
override fun dispatchTouchEvent(ev: MotionEvent): Boolean {
val consumeMotionEvent = gestureDetectorCompat.onTouchEvent(ev)
return if (consumeMotionEvent) {
true
} else {
super.dispatchTouchEvent(ev)
}
}
}
这边使用onFling而不是onScroll,是为了与普通的滑动事件区分。
效果如图: