一步一步打造自己的GestureImageView


 本文最後修改於2015-12-31,修復了縮放時候沒有判斷是否越出邊界的bug.


第一步:打造多點觸摸放大,單點移動的imageview,請看我的博客多點縮放,單點移動的imagview    

第二部:在第一步的基礎上,增加雙擊放大縮小的功能,請看我的博客點擊打開鏈接    

最後一步:在第二步的基礎上,增加判斷移動是否移出邊界的判斷。至此大功告成。


看代碼


package com.wellav.dolphin.media.ui;


import android.annotation.SuppressLint;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Matrix;
import android.graphics.PointF;
import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.Drawable;
import android.util.AttributeSet;
import android.util.FloatMath;
import android.view.MotionEvent;
import android.widget.ImageView;


/**
 * @author cf
 *
 */
@SuppressLint("FloatMath") public class ZoomImageView extends ImageView {
private Matrix matrix = new Matrix();
private Matrix savedMatrix = new Matrix();


private static final int NONE = 0;
private static final int DRAG = 1;
private static final int ZOOM = 2;
private int mode = NONE;
private static final float MAX_SCALE = 3;
private static float mStartScale;
// 第一個按下的手指的點
private PointF startPoint = new PointF();
private int mWidth;
private int mHeight;
// 兩個按下的手指的觸摸點的中點
// private PointF midPoint;
// 初始的兩個手指按下的觸摸點的距離
private float oriDis = 1f;
private boolean isZoomed=false;
public ZoomImageView(Context context) {
super(context);
// TODO Auto-generated constructor stub

}


public ZoomImageView(Context context, AttributeSet attrs) {
super(context, attrs);
// mGestureDetector=new GestureDetector(context, new GestureListener());

}



@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
// TODO Auto-generated method stub
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
}
@Override
protected void onLayout(boolean changed, int left, int top, int right,
int bottom) {
// TODO Auto-generated method stub
super.onLayout(changed, left, top, right, bottom);
mWidth=getWidth();
mHeight=getHeight();
}
private boolean mPrepared = false;//
@Override
protected void onDraw(Canvas canvas) {
// TODO Auto-generated method stub
super.onDraw(canvas);
if (!mPrepared) {
float[] values = new float[9];
getImageMatrix().getValues(values);
mStartScale = values[Matrix.MSCALE_X];
mPrepared=true;
}


}

/**
* @return 雙擊後應該放大的scale值
*/
private float getScacleAfterDoubleClick() {
float[] values = new float[9];
getImageMatrix().getValues(values);


float scale = values[Matrix.MSCALE_X];
if (scale != mStartScale)
{
isZoomed=false;
return mStartScale / scale;
}
else
{
isZoomed=true;
return 2.0f;
}
}




private long startTime = 0;


@Override
public boolean onTouchEvent(MotionEvent event) {
if(isZoomed)
getParent().requestDisallowInterceptTouchEvent(true);
// 進行與操作是爲了判斷多點觸摸
switch (event.getAction() & MotionEvent.ACTION_MASK) {
case MotionEvent.ACTION_DOWN:
// 第一個手指按下事件
setScaleType(ScaleType.MATRIX);
long interval = event.getEventTime() - startTime;
// Log.e("", "now-st=" + interval + "st=" + startTime);


if (interval < 300&&50<interval) {
//雙擊事件處理
// Log.e("", "double click");
matrix.set(getImageMatrix());


float scale = getScacleAfterDoubleClick();
// Log.e("", "scale=" + scale);
matrix.postScale(scale, scale, getWidth() / 2, getHeight() / 2);
setImageMatrix(matrix);
if(scale<2)
{
matrix.setTranslate(0, 0);
setImageMatrix(matrix);
}


break;
}


startTime = event.getEventTime();
matrix.set(getImageMatrix());
savedMatrix.set(matrix);
startPoint.set(event.getX(), event.getY());
mode = DRAG;
break;
case MotionEvent.ACTION_POINTER_DOWN:
// 第二個手指按下事件

// Log.e("", "double down");
oriDis = distance(event);
if (oriDis > 10f) {
savedMatrix.set(matrix);
// midPoint = middle(event);
mode = ZOOM;
}
break;
case MotionEvent.ACTION_UP:
// 手指放開事件
mode = NONE;
break;
case MotionEvent.ACTION_POINTER_UP:
// 手指放開事件


mode = NONE;


break;
case MotionEvent.ACTION_MOVE:


// 手指滑動事件
if (mode == DRAG) {
// 是一個手指拖動
matrix.set(savedMatrix);
float[] values = new float[9];
matrix.getValues(values);
float dx=event.getX() - startPoint.x;
float dy=event.getY()- startPoint.y;
checkBound(dx, dy, values);



} else if (mode == ZOOM) {
// 兩個手指滑動
float newDist = distance(event);
if (newDist > 10f) {
matrix.set(savedMatrix);
float scale = newDist / oriDis;
float[] values = new float[9];
matrix.getValues(values);
scale = checkMaxScale(scale, values);
values = new float[9];
matrix.getValues(values);
checkBound(0, 0, values);
}
}
break;
}


// 設置ImageView的Matrix
this.setImageMatrix(matrix);
return true;
}
/**
* 移動不能超出控件邊界
* @param dx橫向移動距離
* @param dy縱向移動距離
* @param values
*/
private void checkBound(float dx,float dy,float[] values)
{
float wlen=mWidth*values[Matrix.MSCALE_X]-mWidth;
float minTX=-wlen;
float hlen=mHeight*values[Matrix.MSCALE_Y]-mHeight;
float minTY=-hlen;
float tx=0;
if((values[Matrix.MTRANS_X]+dx)>=minTX&&(values[Matrix.MTRANS_X]+dx)<=0)
{
tx=dx;
}
else if((values[Matrix.MTRANS_X]+dx)>0)
{
tx=0-values[Matrix.MTRANS_X];
}
else if(values[Matrix.MTRANS_X]+dx<minTX)
{
tx=minTX-values[Matrix.MTRANS_X];
}
float ty=0;
if(values[Matrix.MTRANS_Y]+dy>=minTY&&values[Matrix.MTRANS_Y]+dy<=0)
ty=dy;
else if(values[Matrix.MTRANS_Y]+dy>0)
ty=0-values[Matrix.MTRANS_Y];
else if(values[Matrix.MTRANS_Y]+dy<minTY)
ty=minTY-values[Matrix.MTRANS_Y];
matrix.postTranslate(tx, ty);
}
/**
* 檢驗scale,使圖像縮放後不會超出最大倍數,不會小於最小倍數

* @param scale 根據手指動作計算出的放大係數
* @param values
* @return 返回實際放大係數
*/
private float checkMaxScale(float scale, float[] values) {


if (scale * values[Matrix.MSCALE_X] >= MAX_SCALE)
{
isZoomed=true;
scale = MAX_SCALE / values[Matrix.MSCALE_X];
}
else if (scale * values[Matrix.MSCALE_X] <=mStartScale)
{
isZoomed=false;
scale = mStartScale / values[Matrix.MSCALE_X];
}
else
isZoomed=true;
matrix.postScale(scale, scale, getWidth() / 2, getHeight() / 2);
return scale;
}


/**
* 計算兩個觸摸點之間的距離
* @param event
* @return
*/
private float distance(MotionEvent event) {
float x = event.getX(0) - event.getX(1);
float y = event.getY(0) - event.getY(1);
return FloatMath.sqrt(x * x + y * y);
}


/**
* 計算兩個觸摸點的中點
* @param event
* @return
*/
// private PointF middle(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);
// }

/**
* 調用該方法恢復初始狀態
*/
private void restoreScale(){
matrix.setTranslate(0, 0);
setImageMatrix(matrix);
isZoomed=false;
}
/**
* 調用該方法圖片旋轉90°
*/
public void rotateBy90()
{
Drawable d = getDrawable(); // xxx根據自己的情況獲取drawable
if(d==null)
return;
BitmapDrawable bd = (BitmapDrawable) d;
Bitmap bitmap = bd.getBitmap();
Matrix matrix = new Matrix();
matrix.postRotate(90);
Bitmap bm = Bitmap.createBitmap(bitmap, 0, 0,
bitmap.getWidth(), bitmap.getHeight(), matrix, true);
setImageBitmap(bm);
restoreScale();
}

}


發佈了39 篇原創文章 · 獲贊 55 · 訪問量 6萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章