在Android应用中,图片随手势的拖拽、缩放、旋转在很多场景中都会用到,今天我们要做的就是在ImageView的基础上实现一个可以拖拽、缩放、转转的TouchView。
一、实现原理
OnTouch事件捕捉+Matrix矩阵变换
二、核心方法
拖拽:Matrix.postTranslate(DeltalX, DeltalY);
缩放:Matrix.postScale(mScale, mScale, mPoint.x, mPoint.y);
旋转:Matrix.postRotate(Angle, mPoint.x, mPoint.y);
三、具体实现
package com.Android.TouchView;
/*
* Android多点触控技术练习
* @Author:Robin
* @Date:2013年12月29日
* @边界处理暂时不知道怎么写啊
* 目前的问题有:
* 手势识别不是很顺畅,经常出现该放缩时放缩不了的情况
* 由于没有边界判断,程序可能会出现崩溃
*/
import android.annotation.SuppressLint;
import android.app.Activity;
import android.graphics.Bitmap;
import android.graphics.Bitmap.Config;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Matrix;
import android.graphics.Paint;
import android.graphics.PaintFlagsDrawFilter;
import android.graphics.PointF;
import android.util.DisplayMetrics;
import android.util.FloatMath;
import android.view.MotionEvent;
import android.widget.ImageView;
@SuppressLint({ "ViewConstructor", "FloatMath" })
public class MultiTouchView extends ImageView
{
//本地图像资源
private int mDrawable;
//图像位图
private Bitmap mBitmap;
//屏幕宽度
private int ScreenWidth;
//屏幕高度
private int ScreenHeight;
//原始图像矩阵
private Matrix mMatrix=new Matrix();
//过程图像矩阵
private Matrix mSavedMatrix=new Matrix();
//结果图像矩阵
private Matrix mResultMatrix=new Matrix();
//定义三种模式:None、Drag、Zoom
public static final int Mode_None=0;
public static final int Mode_Drag=1;
public static final int Mode_Zoom=2;
//当前操作模式
private int mMode=Mode_None;
//当前坐标
private float mDownX,mDownY;
//存储两点间的距离
private float mDistance=0f;
//存储旋转角
@SuppressWarnings("unused")
private float mAngle=0f;
//存储中点
private PointF mPoint;
//最大缩放比例
//private float MaxScale=3f;
//最小缩放比例
//private float MinScale=0.5f;
public MultiTouchView(Activity mActivity ,int Drawable)
{
super(mActivity);
//设置当前图片资源
this.mDrawable=Drawable;
//获取Bitmap
mBitmap=BitmapFactory.decodeResource(getResources(), mDrawable);
DisplayMetrics dm=new DisplayMetrics();
mActivity.getWindowManager().getDefaultDisplay().getMetrics(dm);
//获取屏幕宽度和高度
ScreenWidth=dm.widthPixels;
ScreenHeight=dm.heightPixels;
mMatrix=new Matrix();
}
@SuppressLint("DrawAllocation")
@Override
protected void onDraw(Canvas canvas)
{
//消除图像锯齿
canvas.setDrawFilter(new PaintFlagsDrawFilter(0,Paint.ANTI_ALIAS_FLAG|Paint.FILTER_BITMAP_FLAG));
canvas.save();
//绘制图像
canvas.drawBitmap(mBitmap, mMatrix, null);
canvas.restore();
}
@Override
public boolean onTouchEvent(MotionEvent Event)
{
switch(Event.getAction())
{
//单点触控处理
case MotionEvent.ACTION_DOWN:
//设置当前操作模式为Drag
mMode=Mode_Drag;
//获取当前坐标
mDownX=Event.getX();
mDownY=Event.getY();
mSavedMatrix.set(mMatrix);
break;
//多点触控处理
case MotionEvent.ACTION_POINTER_DOWN:
mMode=Mode_Zoom;
//获取两点间距离
mDistance=getDistance(Event);
//获取旋转角
mAngle=getAngle(Event);
//获取中点
mPoint=getMidPoint(Event);
mSavedMatrix.set(mMatrix);
break;
case MotionEvent.ACTION_MOVE:
//缩放处理
if(mMode==Mode_Zoom)
{
mResultMatrix.set(mSavedMatrix);
//获取缩放比率
float mScale=getDistance(Event)/mDistance;
//获取旋转角,这里可以不用
//float Angle=getAngle(Event)-mAngle;
//以中点为中心,进行缩放
mResultMatrix.postScale(mScale, mScale, mPoint.x, mPoint.y);
//以中点为中心,进行旋转,这里可以不用
//mResultMatrix.postRotate(Angle, mPoint.x, mPoint.y);
mMatrix.set(mResultMatrix);
invalidate();
}else if(mMode==Mode_Drag)//平移处理
{
mResultMatrix.set(mSavedMatrix);
//计算平移量
float DeltalX=Event.getX()-mDownX;
float DeltalY=Event.getY()-mDownY;
//平移
mResultMatrix.postTranslate(DeltalX, DeltalY);
mMatrix.set(mResultMatrix);
invalidate();
}
break;
case MotionEvent.ACTION_UP:
//这里要不要处理呢,如果需要,怎么办
case MotionEvent.ACTION_POINTER_UP:
mMode = Mode_None;
break;
}
return true;
}
//返回两点间的距离
public float getDistance(MotionEvent Event)
{
//计算X的变化量
float DeltalX=Event.getX(0)-Event.getX(1);
//计算Y的变化量
float DeltalY=Event.getY(0)-Event.getY(1);
//计算距离
return FloatMath.sqrt(DeltalX*DeltalX+DeltalY*DeltalY);
}
//返回两点的中点
@SuppressLint("FloatMath")
public PointF getMidPoint(MotionEvent Event)
{
float X=Event.getX(0)+Event.getX(1);
float Y=Event.getY(0)+Event.getY(1);
return new PointF(X/2,Y/2);
}
//获得旋转角
public float getAngle(MotionEvent Event)
{
double DeltalX=Event.getX(0)-Event.getX(1);
double DeltalY=Event.getY(0)-Event.getY(1);
return (float)Math.atan2(DeltalX, DeltalY);
}
//边界处理,暂时没找到比较好的方法
public boolean CheckBounary()
{
return false;
}
//存储当前图片
public Bitmap SaveImage()
{
Bitmap mBitmap = Bitmap.createBitmap(ScreenWidth, ScreenHeight,Config.ARGB_8888);
Canvas mCanvas = new Canvas(mBitmap);
mCanvas.drawBitmap(mBitmap, mMatrix, null);
mCanvas.save(Canvas.ALL_SAVE_FLAG);
mCanvas.restore();
return mBitmap;
}
}
四、 运行效果