上节说到了GestureDetector,接下来介绍下ScaleGestureDetector
首先我们知道 View 主要自带了 设置单击、长按等监听,一般来说就够用了,但我们有时自定义View 需要更多的功能,ScaleGestureDetector主要是解决双指捏合的手势监听,常见场景就是相册图片捏合时对图片的放大缩小
先直接上干货~
public interface OnScaleGestureListener {
public boolean onScale(@NonNull ScaleGestureDetector detector);
public boolean onScaleBegin(@NonNull ScaleGestureDetector detector);
public void onScaleEnd(@NonNull ScaleGestureDetector detector);
}
ScaleGestureDetector 只有这一个监听器,下面来介绍下监听器各个回调的详解~
一、OnScaleGestureListener 回调方法介绍
public boolean onScale(@NonNull ScaleGestureDetector detector);
onScale 是捏合过程的回调, 回调的 detector 我们主要用到
1、detector.focusX 是放缩时围绕的焦点 x 坐标
2、detector.focusY 是放缩时围绕的焦点 y 坐标
3、detector.scaleFactor 是放缩的倍数,这里我们要结合onScale的返回值来看如何使用该值。如果返回 true 就代表我已消费此次回调事件,下次再返回时就是相对上次的放缩倍数;如果返回 false 就代表我不消费此次回调事件,下次返回时是相对最后一次消费事件时(即上次返回true)的放缩倍数,所以如果写死了返回false就是相对最开始的放缩倍数。
public boolean onScaleBegin(@NonNull ScaleGestureDetector detector);
onScaleBegin 是开始捏合时的回调,在此必须返回true,如果不返回true,那么接下来您将不会得到onScale的回调
public void onScaleEnd(@NonNull ScaleGestureDetector detector);
onScaleEnd 很简单字面意思就是结束了捏合放缩
二、接下来看下如何使用
class CustomView2(context: Context, attrs: AttributeSet?) : View(context, attrs),
ScaleGestureDetector.OnScaleGestureListener{
private val scaleGestureDetector = ScaleGestureDetector(context,this)
override fun onTouchEvent(event: MotionEvent): Boolean {
return scaleGestureDetector.onTouchEvent(event)
}
}
使用起来也很简单,只是需要把 View 的 onTouchEvent 的方法用 ScaleGestureDetector 接管即可
这里额外说明一下,其实我们在写自定义触摸时,几乎都要在onTouchEvent返回true的,而ScaleGestureDetector的onTouchEvent也是写死了返回true的。这跟Android 的时间分发机制是有关系的,主要原因就在ACTION_DOWN返回true才可以消费接下来的事件序列,返回false就代表不再消费接下来的事件序列了,而其他事件返回什么是无所谓的。
三、接下来看下如何结合上节提到的GestureDetector来使用
class CustomView(context: Context, attrs: AttributeSet?) : View(context, attrs),
GestureDetector.OnGestureListener, GestureDetector.OnDoubleTapListener, ScaleGestureDetector.OnScaleGestureListener {
private val gestureDetector = GestureDetectorCompat(context,this).apply {
setOnDoubleTapListener(this@CustomView)
}
private val scaleGestureDetector = ScaleGestureDetector(context,this)
override fun onTouchEvent(event: MotionEvent): Boolean {
scaleGestureDetector.onTouchEvent(event);
if (!scaleGestureDetector.isInProgress){
gestureDetector.onTouchEvent(event)
}
return true
}
}
这里介绍下 ScaleGestureDetector 的 isInProgress 返回 true 意思就是正在识别为双指捏合了,反之返回 false 说明没有在捏合,所以不在捏合时,应该使用 GestureDetector来处理触摸事件。
这里可能会有人想为什么优先使用 ScaleGestureDetector 来处理触摸事件呢?细想一下当用户双指在屏幕上捏合时,当然优先处理捏合事件了,当不是双指捏合事件时,就应该由 GestureDetector 来处理了。这样做符合大多数的产品设计思路的,除非是比较奇葩的。