实现自定义拖拽、放大的imageview
这种控件很简单,基本上没什么难度,无非就是onTouch事件的处理:
我们先从简单的做起,实现自定义拖拽:
首先,你移动的过程中,你得记录一下你刚开始的位置,然后你移动完成后,需要记录一下终点,至于这个距离如何记录,onTouch正好给你API去获取移动的距离,然后学过数学的都知道,一个手机屏幕是一个二维坐标系统,你都知道了起点,知道了终点,然后你做一下加法,不就出来了。
getImageMatrix()你先获取手机屏幕的矩阵元素,然后通过MotionEvent获取起点的坐标,如下图所示:
然后你移动,产生距离,那距离就来搞一下下啊,你往前,就用终点减去起点,就是移动距离,你既然获得距离了,就来移动啊!
postTranslate(),使用这个方法就可以实现移动的功能了。
然后接下来就得实现缩小放大的功能;一般你放大是不是得两根手指头,那触摸点是不是就得有两个了,那你如何获取放大的倍数?我给你一个思路:你手指动了,你是不是会产生缩放距离,同时在X或者Y轴或者同时,那你就会有一个产生的缩放距离,在X轴和Y轴上的,你都知道了X和Y的距离了,那来一个勾股定理,是不是就得算出来了斜边的距离,因为你动手指,产生了距离,不管你移动了多少,斜边都会产生移动。那你用初始的斜边长度去除以手势在屏幕上移动后产生的斜边长度,结果就是缩放的比例大小。这个比例你获取到了,但是你是不是得有一个缩放点,就是你根据哪个点进行缩放的,我们一般取缩放后的中间点,如果你取起点,那就是反向了,取终点,就缩放不正常,会产生二倍放大,这个是线性代数里面的一个基本的知识。然后你用postScale()方法进行缩放,第一个是X轴的缩放,第二个是Y轴的缩放,然后后面两个是中点,中间点就是你两个手指的中间点。思路都出来了,代码就出来了:
package com.ireader.plug.testapplication;
import android.content.Context;
import android.graphics.Matrix;
import android.graphics.PointF;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;
import android.widget.ImageView;
public class BaseDragZoomImageViewextends ImageViewimplements View.OnTouchListener{
private int mode =0;
private static final int MODE_DRAG =1;
private static final int MODE_ZOOM =2;
private PointFstartPoint =new PointF();
private Matrixmatrix =new Matrix();
private MatrixcurrentMatrix =new Matrix();
private float startDis;
private PointFmidPoint;
public BaseDragZoomImageView(Context context, AttributeSet attrs, int defStyle)
{
super(context, attrs, defStyle);
setOnTouchListener(this);
}
public BaseDragZoomImageView(Context context, AttributeSet attrs)
{
this(context, attrs, 0);
setOnTouchListener(this);
}
public BaseDragZoomImageView(Context context)
{
this(context, null);
setOnTouchListener(this);
}
@Override
public boolean onTouch(View v, MotionEvent event) {
switch (event.getAction() & MotionEvent.ACTION_MASK) {
case MotionEvent.ACTION_DOWN:
mode = MODE_DRAG;
currentMatrix.set(getImageMatrix());
startPoint.set(event.getX(), event.getY());
break;
// 手指在屏幕上移动,改事件会被不断触发
case MotionEvent.ACTION_MOVE:
if (mode == MODE_DRAG) {
float dx = event.getX() - startPoint.x;
float dy = event.getY() - startPoint.y;
matrix.set(currentMatrix);
matrix.postTranslate(dx, dy);
}
else if (mode == MODE_ZOOM) {
float endDis = distance(event);
if (endDis > 10f) {
float scale = endDis / startDis;
matrix.set(currentMatrix);
matrix.postScale(scale, scale,midPoint.x,midPoint.y);
}
}
break;
case MotionEvent.ACTION_UP:
case MotionEvent.ACTION_POINTER_UP:
mode = 0;
break;
case MotionEvent.ACTION_POINTER_DOWN:
mode = MODE_ZOOM;
startDis = distance(event);
if (startDis > 10f) {
midPoint = mid(event);
currentMatrix.set(getImageMatrix());
}
break;
}
setImageMatrix(matrix);
return true;
}
private float distance(MotionEvent event) {
float dx = event.getX(1) - event.getX(0);
float dy = event.getY(1) - event.getY(0);
return (float) Math.sqrt(dx * dx + dy * dy);
}
private PointFmid(MotionEvent event) {
float midX =(event.getX(1) + event.getX(0)) /2;
float midY =(event.getY(1) + event.getY(0)) /2;
return new PointF(midX, midY);
}
}