手势检测
Android 手势检测,也就是对 GestureDetector 的使用。
而 GestureDetector 则可以使用 MotionEvents 检测各种手势和事件。
GestureDetector.OnGestureListener 是个回调方法,在发生特定事件时会调用 Listener 中对应的方法回调。
这个类只能用于检测触摸事件的 MotionEvent,不能用于轨迹球事件。
使用步骤
- 创建一个 GestrueDetector 实例
- 在 onTouchEvent(MontionEvent) 方法中,确保调用 GestrueDetector 实例的onTouchEvent(MotionEvent)。回调中定义的方法将在事件发生时执行。
- 如果侦听 onContextClick(MotionEvent),则必须在 View 的 onGenericMotionEvent(MotionEvent)中调用 GestureDetector OnGenericMotionEvent(MotionEvent)。
GestureDetector
//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by Fernflower decompiler)
//
package android.view;
import android.content.Context;
import android.os.Handler;
public class GestureDetector {
/**
* GestureDetector 共有5种构造函数
* 但前两种已舍弃,一种是重复的。
* 所以,只需要关注两种。
**/
/**
* 已舍弃
**/
@Deprecated
public GestureDetector(GestureDetector.OnGestureListener listener, Handler handler) {
throw new RuntimeException("Stub!");
}
/**
* 已舍弃
**/
@Deprecated
public GestureDetector(GestureDetector.OnGestureListener listener) {
throw new RuntimeException("Stub!");
}
/**
* 关注这个构造函数
* context:上下文
* listener:手势监听器
**/
public GestureDetector(Context context, GestureDetector.OnGestureListener listener) {
throw new RuntimeException("Stub!");
}
/**
* 关注这个构造函数
* context:上下文
* listener:手势监听器
* handler:用于给 GestureDetector 提供一个Looper
* 由于GestureDetector会在内部自动创建一个Handler用于处理数据,如果是在主线程创建的GestureDetector,其内部的Hanlder会自动获得主线程的Looper。
* 但如果是在一个没有创建Looper的子线程中创建的GestureDetector,则需要传递一个带有Looper的Handler给它,否则会因为无法获取到Looper导致创建失败。
**/
public GestureDetector(Context context, GestureDetector.OnGestureListener listener, Handler handler) {
throw new RuntimeException("Stub!");
}
public GestureDetector(Context context, GestureDetector.OnGestureListener listener, Handler handler, boolean unused) {
throw new RuntimeException("Stub!");
}
public void setOnDoubleTapListener(GestureDetector.OnDoubleTapListener onDoubleTapListener) {
throw new RuntimeException("Stub!");
}
public void setContextClickListener(GestureDetector.OnContextClickListener onContextClickListener) {
throw new RuntimeException("Stub!");
}
public void setIsLongpressEnabled(boolean isLongpressEnabled) {
throw new RuntimeException("Stub!");
}
public boolean isLongpressEnabled() {
throw new RuntimeException("Stub!");
}
public boolean onTouchEvent(MotionEvent ev) {
throw new RuntimeException("Stub!");
}
public boolean onGenericMotionEvent(MotionEvent ev) {
throw new RuntimeException("Stub!");
}
/**
* 四种手势监听器:
* OnContextClickListener
* OnDoubleTapListener
* OnGestureListener
* SimpleOnGestureListener
**/
/**
* 另外三个接口的空实现。
* 一般情况下,使用这个就好了,比较方便。
**/
public static class SimpleOnGestureListener implements GestureDetector.OnGestureListener, GestureDetector.OnDoubleTapListener, GestureDetector.OnContextClickListener {
public SimpleOnGestureListener() {
throw new RuntimeException("Stub!");
}
public boolean onSingleTapUp(MotionEvent e) {
throw new RuntimeException("Stub!");
}
public void onLongPress(MotionEvent e) {
throw new RuntimeException("Stub!");
}
public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) {
throw new RuntimeException("Stub!");
}
public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) {
throw new RuntimeException("Stub!");
}
public void onShowPress(MotionEvent e) {
throw new RuntimeException("Stub!");
}
public boolean onDown(MotionEvent e) {
throw new RuntimeException("Stub!");
}
public boolean onDoubleTap(MotionEvent e) {
throw new RuntimeException("Stub!");
}
public boolean onDoubleTapEvent(MotionEvent e) {
throw new RuntimeException("Stub!");
}
public boolean onSingleTapConfirmed(MotionEvent e) {
throw new RuntimeException("Stub!");
}
public boolean onContextClick(MotionEvent e) {
throw new RuntimeException("Stub!");
}
}
/**
* Android6.0(API23)添加的
* 用于检测外部设备上的按钮是否按下的,
* 例如蓝牙触控笔上的按钮,一般情况下,忽略即可。
**/
public interface OnContextClickListener {
boolean onContextClick(MotionEvent var1);
}
/**
* 双击事件,有三个回调类型:
* 双击(DoubleTap)、单击确认(SingleTapConfirmed) 和 双击事件回调(DoubleTapEvent)
**/
public interface OnDoubleTapListener {
boolean onSingleTapConfirmed(MotionEvent var1);
boolean onDoubleTap(MotionEvent var1);
boolean onDoubleTapEvent(MotionEvent var1);
}
/**
* 手势检测,主要有以下类型事件:
* 按下(Down)、 抛(Fling)、长按(LongPress)、滚动(Scroll)、触摸反馈(ShowPress) 和 单击抬起(SingleTapUp)
**/
public interface OnGestureListener {
// 保证控件拥有消费事件的能力,以接受后续的事件。
boolean onDown(MotionEvent var1);
// 监听用户按下时
// 延迟回调,延迟时间180ms
// 假如用户手指按下后立即抬起或者事件立即被拦截,时间没有超过 180 ms的话,这条消息会被 remove 掉
void onShowPress(MotionEvent var1);
// 监听用户单击抬起时
// 区别在于双击时的触发次数:
// onSingleTapUp:1次(在双击的第一次抬起时触发)
// onSingleTapConfirmed:0次(双击发生时不会触发)
// onClick:2次(在双击事件时触发两次)
//
// 触发顺序如下:
// onSingleTapUp
// onClick
// onDoubleTap // <- 双击
// onClick
boolean onSingleTapUp(MotionEvent var1);
// 监听滚动事件
// var1:手指按下时的Event
// var2:手指提起时的Event
// var3:在 X 轴上划过的距离
// var4:在 Y 轴上划过的距离
boolean onScroll(MotionEvent var1, MotionEvent var2, float var3, float var4);
// 检测长按事件
void onLongPress(MotionEvent var1);
// 扔,抛,常见与列表中
// var1:手指按下时的Event
// var2:手指提起时的Event
// var3:在 X 轴上的运动速度(像素/秒)
// var4:在 Y 轴上的运动速度(像素/秒)
boolean onFling(MotionEvent var1, MotionEvent var2, float var3, float var4);
}
}
示例
使用无 Handler 的构造函数
// 创建一个监听回调
final GestureDetector.SimpleOnGestureListener onGestureListener = new GestureDetector.SimpleOnGestureListener(){
/**
* 单击事件发生后300ms后触发
*/
@Override
public boolean onSingleTapConfirmed(MotionEvent e) {
// 如果想同时监听双击与单击事件,则监听单击事件不推荐使用OnClickListener,原因有二:
// 一,它们是存在冲突的,若要同时出发,则 setOnTouchListener 不能消费事件,如果 onTouchListener 消费了事件,就可能导致 OnClick 无法正常触发。
// 二,使用 OnClickListener 会在双击事件发生时触发两次
Toast.makeText(MainActivity.this,"不要单击",Toast.LENGTH_SHORT).show();
return super.onSingleTapConfirmed(e);
}
@Override
public boolean onDoubleTap(MotionEvent e) {
Toast.makeText(MainActivity.this,"双击666",Toast.LENGTH_SHORT).show();
Log.e("TAG","第二次按下时触发");
return super.onDoubleTap(e);
}
/**
* 与 onDoubleTap 的差别很小
* onDoubleTapEvent 用来进行更细微的控制
*
* 函数的执行顺序如下:
* onDoubleTap
* onDoubleTapEvent - down
* onDoubleTapEvent - move
* onDoubleTapEvent - up
*/
@Override
public boolean onDoubleTapEvent(MotionEvent e) {
switch (e.getActionMasked()){
case MotionEvent.ACTION_DOWN:
Log.e("TAG","ACTION_DOWN");
break;
case MotionEvent.ACTION_MOVE:
Log.e("TAG","ACTION_MOVE");
break;
case MotionEvent.ACTION_UP:
Log.e("TAG","第二次抬起时触发");
break;
default:
break;
}
return super.onDoubleTapEvent(e);
}
};
// 创建一个检测器
GestureDetector gestureDetector;
private void initData() {
// 使用无Handler的构造函数
gestureDetector = new GestureDetector(this,onGestureListener);
// 给监听器设置数据源
btn_doubleTap.setOnTouchListener(new View.OnTouchListener() {
@Override
public boolean onTouch(View view, MotionEvent motionEvent) {
return gestureDetector.onTouchEvent(motionEvent);
}
});
}
使用有 Handler 的构造函数
/**
* 由于GestureDetector会在内部自动创建一个Handler用于处理数据,
* 如果是在主线程创建的GestureDetector,其内部的Hanlder会自动获得主线程的Looper。
* 可以直接使用无Handler的构造函数
*
* 但如果是在一个没有创建Looper的子线程中创建的GestureDetector,
* 则需要传递一个带有Looper的Handler给它,否则会因为无法获取到Looper导致创建失败。
* 需要使用带Handler的构造函数
**/
// 创建一个监听回调
final GestureDetector.SimpleOnGestureListener onGestureListener = new GestureDetector.SimpleOnGestureListener(){
@Override
public boolean onDoubleTap(MotionEvent e) {
Toast.makeText(MainActivity.this,"双击666",Toast.LENGTH_SHORT).show();
return super.onDoubleTap(e);
}
};
// 创建一个检测器
GestureDetector gestureDetector;
private void initData() {
// 使用有Handler的构造函数的几种方式;
// 1.主线程中创建Handler
// 重点在于传递的 Handler 一定要有 Looper
final Handler handler = new Handler();
// 主线程创建的hanlder会自动关联主线程的Looper
new Thread(new Runnable() {
@Override
public void run() {
gestureDetector = new GestureDetector(MainActivity.this,onGestureListener,handler);
}
}).start();
// 2.子线程中创建Handler
// 重点在于传递的 Handler 一定要有 Looper
new Thread(new Runnable() {
@Override
public void run() {
Handler handler1 = new Handler(Looper.getMainLooper());
gestureDetector = new GestureDetector(MainActivity.this,onGestureListener,handler1);
}
}).start();
// 3.若子线程准备了 Looper 那么可以直接使用无Handler的构造函数进行创建
// 重点在于传递的 Handler 一定要有 Looper
new Thread(new Runnable() {
@Override public void run() {
Looper.prepare(); // <- 重点在这里
gestureDetector = new GestureDetector(MainActivity.this,onGestureListener);
}
}).start();
// 给监听器设置数据源
btn_doubleTap.setOnTouchListener(new View.OnTouchListener() {
@Override
public boolean onTouch(View view, MotionEvent motionEvent) {
return gestureDetector.onTouchEvent(motionEvent);
}
});
}
相关方法
除了各类监听器之外,还有几个相关的方法
方法 | 说明 |
---|---|
setIsLongpressEnabled | 是否允许触发长按事件,true 表示允许,false 表示不允许。 |
isLongpressEnabled | 判断当前是否允许触发长按事件,true 表示允许,false 表示不允许。 |
onTouchEvent | 这个是其中一个重要的方法,在最开始已经演示过使用方式了。 |
onGenericMotionEvent | 这个是在 API 23 之后才添加的内容,主要是为 OnContextClickListener 服务的,暂时不用关注。 |
setContextClickListener | 设置 ContextClickListener 。 |
setOnDoubleTapListener | 设置 OnDoubleTapListener 。 |
缩放手势检测
Android 缩放手势检测,ScaleGestureDetector
一般来讲,缩放手势都不是单独存在的。
如果用在自定义控件上,则配合 Matrix 相关内容使用更好。
使用方式与 GestureDetector 类似,也是通过 Listener 进行监听用户的操作手势,它是对缩放手势进行了一次封装。
ScaleGestureDetector
//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by Fernflower decompiler)
//
package android.view;
import android.content.Context;
import android.os.Handler;
public class ScaleGestureDetector {
/**
* 有两个构造函数
**/
public ScaleGestureDetector(Context context, ScaleGestureDetector.OnScaleGestureListener listener) {
throw new RuntimeException("Stub!");
}
public ScaleGestureDetector(Context context, ScaleGestureDetector.OnScaleGestureListener listener, Handler handler) {
throw new RuntimeException("Stub!");
}
public boolean onTouchEvent(MotionEvent event) {
throw new RuntimeException("Stub!");
}
public void setQuickScaleEnabled(boolean scales) {
throw new RuntimeException("Stub!");
}
public boolean isQuickScaleEnabled() {
throw new RuntimeException("Stub!");
}
public void setStylusScaleEnabled(boolean scales) {
throw new RuntimeException("Stub!");
}
public boolean isStylusScaleEnabled() {
throw new RuntimeException("Stub!");
}
public boolean isInProgress() {
throw new RuntimeException("Stub!");
}
public float getFocusX() {
throw new RuntimeException("Stub!");
}
public float getFocusY() {
throw new RuntimeException("Stub!");
}
public float getCurrentSpan() {
throw new RuntimeException("Stub!");
}
public float getCurrentSpanX() {
throw new RuntimeException("Stub!");
}
public float getCurrentSpanY() {
throw new RuntimeException("Stub!");
}
public float getPreviousSpan() {
throw new RuntimeException("Stub!");
}
public float getPreviousSpanX() {
throw new RuntimeException("Stub!");
}
public float getPreviousSpanY() {
throw new RuntimeException("Stub!");
}
public float getScaleFactor() {
throw new RuntimeException("Stub!");
}
public long getTimeDelta() {
throw new RuntimeException("Stub!");
}
public long getEventTime() {
throw new RuntimeException("Stub!");
}
/**
* 两个手势监听器
* SimpleOnScaleGestureListener:缩放收拾检测器的空实现
* OnScaleGestureListener:缩放收拾检测器
**/
public static class SimpleOnScaleGestureListener implements ScaleGestureDetector.OnScaleGestureListener {
public SimpleOnScaleGestureListener() {
throw new RuntimeException("Stub!");
}
public boolean onScale(ScaleGestureDetector detector) {
throw new RuntimeException("Stub!");
}
public boolean onScaleBegin(ScaleGestureDetector detector) {
throw new RuntimeException("Stub!");
}
public void onScaleEnd(ScaleGestureDetector detector) {
throw new RuntimeException("Stub!");
}
}
public interface OnScaleGestureListener {
// 缩放被触发(会调用0次或者多次),如果返回 true 则表示当前缩放事件已经被处理,检测器会重新积累缩放因子,返回 false 则会继续积累缩放因子。
boolean onScale(ScaleGestureDetector var1);
// 缩放手势开始,当两个手指放在屏幕上的时候会调用该方法(只调用一次)。如果返回 false 则表示不使用当前这次缩放手势。
boolean onScaleBegin(ScaleGestureDetector var1);
// 缩放手势结束
void onScaleEnd(ScaleGestureDetector var1);
}
}
示例
public class ScaleGestureDemoView extends View{
private static final String TAG="ScaleGestureDemoView";
private ScaleGestureDetector scaleGestureDetector;
public ScaleGestureDemoView(Context context) {
super(context);
init();
}
public ScaleGestureDemoView(Context context, @Nullable AttributeSet attrs) {
super(context, attrs);
init();
}
private void init() {
scaleGestureDetector=new ScaleGestureDetector(getContext(),new ScaleGestureDetector.SimpleOnScaleGestureListener(){
@Override
public boolean onScale(ScaleGestureDetector detector) {
// 缩放手势触发
// 主要关心这两个值,缩放中心点和缩放因子。
// 中心点:将所有的坐标都加起来,然后除以数量。
// 缩放因子:计算各个手指到焦点的平均距离,在用户手指移动后用新的平均距离除以旧的平均距离,并以此计算得出缩放比例。
Log.e(TAG, "focusX = " + detector.getFocusX()); // 缩放中心,x坐标
Log.e(TAG, "focusY = " + detector.getFocusY()); // 缩放中心y坐标
Log.e(TAG, "scale = " + detector.getScaleFactor()); // 缩放因子
return true;
}
@Override
public boolean onScaleBegin(ScaleGestureDetector detector) {
// 缩放手势开始
Log.e(TAG,"缩放手势开始");
return true;
}
@Override
public void onScaleEnd(ScaleGestureDetector detector) {
// super.onScaleEnd(detector);
// 缩放手势结束
Log.e(TAG,"缩放手势结束");
}
});
}
@Override
public boolean onTouchEvent(MotionEvent event) {
scaleGestureDetector.onTouchEvent(event);
return true;
}
}
综合示例
public class GestureDemoView extends View {
GestureDetector mGestureDetector;
ScaleGestureDetector mScaleGestureDetector;
// 画布当前的 Matrix, 用于获取当前画布的一些状态信息,例如缩放大小,平移距离等
private Matrix mCanvasMatrix = new Matrix();
// 将用户触摸的坐标转换为画布上坐标所需的 Matrix, 以便找到正确的缩放中心位置
private Matrix mInvertMatrix = new Matrix();
// 所有用户触发的缩放、平移等操作都通过下面的 Matrix 直接作用于画布上,
// 将系统计算的一些初始缩放平移信息与用户操作的信息进行隔离,让操作更加直观
private Matrix mUserMatrix = new Matrix();
private Bitmap mBitmap;
// 基础的缩放和平移信息,该信息与用户的手势操作无关
private float mBaseScale;
private float mBaseTranslateX;
private float mBaseTranslateY;
private Paint mPaint;
public GestureDemoView(Context context) {
super(context);
}
public GestureDemoView(Context context, @Nullable AttributeSet attrs) {
super(context, attrs);
mPaint = new Paint();
mBitmap = BitmapFactory.decodeResource(getResources(), R.drawable.test);
initGesture(context);
}
@Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
super.onSizeChanged(w, h, oldw, oldh);
if (mBitmap.getWidth() * 1.0f / mBitmap.getHeight() > w * 1.0f / h) {
mBaseScale = w * 1.0f / mBitmap.getWidth();
mBaseTranslateX = 0;
mBaseTranslateY = (h - mBitmap.getHeight() * mBaseScale) / 2;
} else {
mBaseScale = h * 1.0f / mBitmap.getHeight() * 1.0f;
mBaseTranslateX = (w - mBitmap.getWidth() * mBaseScale) / 2;
mBaseTranslateY = 0;
}
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
mPaint.setStyle(Paint.Style.STROKE);
mPaint.setStrokeWidth(6);
canvas.translate(mBaseTranslateX, mBaseTranslateY);
canvas.scale(mBaseScale, mBaseScale);
canvas.save();
canvas.concat(mUserMatrix);
mCanvasMatrix = canvas.getMatrix();
mCanvasMatrix.invert(mInvertMatrix);
canvas.drawBitmap(mBitmap, 0, 0, mPaint);
canvas.restore();
}
//--- 手势处理 ----------------------------------------------------------------------------------
private void initGesture(Context context) {
mGestureDetector = new GestureDetector(context, new GestureDetector.SimpleOnGestureListener() {
@Override
public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) {
float scale = getMatrixValue(MSCALE_X, mCanvasMatrix);
mUserMatrix.preTranslate(-distanceX / scale, -distanceY / scale);
//fixTranslate(); // 在用户滚动时不进行修正,保证用户滚动时也有响应, 在用户抬起手指后进行修正
invalidate();
return true;
}
@Override
public boolean onDoubleTap(MotionEvent e) {
if (!mUserMatrix.isIdentity()) {
mUserMatrix.reset();
} else {
float[] points = mapPoint(e.getX(), e.getY(), mInvertMatrix);
mUserMatrix.postScale(MAX_SCALE, MAX_SCALE, points[0], points[1]);
}
fixTranslate();
invalidate();
return true;
}
});
mScaleGestureDetector = new ScaleGestureDetector(context, new ScaleGestureDetector.SimpleOnScaleGestureListener() {
@Override
public boolean onScale(ScaleGestureDetector detector) {
float scaleFactor = detector.getScaleFactor();
float fx = detector.getFocusX();
float fy = detector.getFocusY();
float[] points = mapPoint(fx, fy, mInvertMatrix);
scaleFactor = getRealScaleFactor(scaleFactor);
mUserMatrix.preScale(scaleFactor, scaleFactor, points[0], points[1]);
fixTranslate();
invalidate();
return true;
}
});
}
// 修正缩放
private void fixTranslate() {
// 对 Matrix 进行预计算,并根据计算结果进行修正
Matrix viewMatrix = getMatrix(); // 获取当前控件的Matrix
viewMatrix.preTranslate(mBaseTranslateX, mBaseTranslateY);
viewMatrix.preScale(mBaseScale, mBaseScale);
viewMatrix.preConcat(mUserMatrix);
Matrix invert = new Matrix();
viewMatrix.invert(invert);
Rect rect = new Rect();
getGlobalVisibleRect(rect);
float userScale = getMatrixValue(MSCALE_X, mUserMatrix);
float scale = getMatrixValue(MSCALE_X, viewMatrix);
float[] center = mapPoint(mBitmap.getWidth() / 2.0f, mBitmap.getHeight() / 2.0f, viewMatrix);
float distanceX = center[0] - getWidth() / 2.0f;
float distanceY = center[1] - getHeight() / 2.0f;
float[] wh = mapVectors(mBitmap.getWidth(), mBitmap.getHeight(), viewMatrix);
if (userScale <= 1.0f) {
mUserMatrix.preTranslate(-distanceX / scale, -distanceY / scale);
} else {
float[] lefttop = mapPoint(0, 0, viewMatrix);
float[] rightbottom = mapPoint(mBitmap.getWidth(), mBitmap.getHeight(), viewMatrix);
// 如果宽度小于总宽度,则水平居中
if (wh[0] < getWidth()) {
mUserMatrix.preTranslate(distanceX / scale, 0);
} else {
if (lefttop[0] > 0) {
mUserMatrix.preTranslate(-lefttop[0] / scale, 0);
} else if (rightbottom[0] < getWidth()) {
mUserMatrix.preTranslate((getWidth() - rightbottom[0]) / scale, 0);
}
}
// 如果高度小于总高度,则垂直居中
if (wh[1] < getHeight()) {
mUserMatrix.preTranslate(0, -distanceY / scale);
} else {
if (lefttop[1] > 0) {
mUserMatrix.preTranslate(0, -lefttop[1] / scale);
} else if (rightbottom[1] < getHeight()) {
mUserMatrix.preTranslate(0, (getHeight() - rightbottom[1]) / scale);
}
}
}
invalidate();
}
@Override
public boolean onTouchEvent(MotionEvent event) {
mGestureDetector.onTouchEvent(event);
mScaleGestureDetector.onTouchEvent(event);
if (event.getActionMasked() == MotionEvent.ACTION_UP) {
fixTranslate();
}
return true;
}
//--- Tools ------------------------------------------------------------------------------------
//--- 将坐标转换为画布坐标 ---
private float[] mapPoint(float x, float y, Matrix matrix) {
float[] temp = new float[2];
temp[0] = x;
temp[1] = y;
matrix.mapPoints(temp);
return temp;
}
private float[] mapVectors(float x, float y, Matrix matrix) {
float[] temp = new float[2];
temp[0] = x;
temp[1] = y;
matrix.mapVectors(temp);
return temp;
}
//--- 获取 Matrix 中的属性 ---
private float[] matrixValues = new float[9];
private static final int MSCALE_X = 0, MSKEW_X = 1, MTRANS_X = 2;
private static final int MSKEW_Y = 3, MSCALE_Y = 4, MTRANS_Y = 5;
private static final int MPERSP_0 = 6, MPERSP_1 = 7, MPERSP_2 = 8;
@IntDef({MSCALE_X, MSKEW_X, MTRANS_X, MSKEW_Y, MSCALE_Y, MTRANS_Y, MPERSP_0, MPERSP_1, MPERSP_2})
@Retention(RetentionPolicy.SOURCE)
private @interface MatrixName {}
private float getMatrixValue(@MatrixName int name, Matrix matrix) {
matrix.getValues(matrixValues);
return matrixValues[name];
}
//--- 限制缩放比例 ---
private static final float MAX_SCALE = 4.0f; //最大缩放比例
private static final float MIN_SCALE = 0.5f; // 最小缩放比例
private float getRealScaleFactor(float currentScaleFactor) {
float realScale = 1.0f;
float userScale = getMatrixValue(MSCALE_X, mUserMatrix); // 用户当前的缩放比例
float theoryScale = userScale * currentScaleFactor; // 理论缩放数值
// 如果用户在执行放大操作并且理论缩放数据大于4.0
if (currentScaleFactor > 1.0f && theoryScale > MAX_SCALE) {
realScale = MAX_SCALE / userScale;
} else if (currentScaleFactor < 1.0f && theoryScale < MIN_SCALE) {
realScale = MIN_SCALE / userScale;
} else {
realScale = currentScaleFactor;
}
return realScale;
}
}
备注
参考资料:
传送门:GitHub
欢迎关注微信公众号:非也缘也