Android通过OnTouchListener缩放、拖拽ImageView图片

来源:互联网 发布:玄牝之门是什么知乎 编辑:程序博客网 时间:2024/06/05 17:49

正在做一个项目,在很多地方有用到图片,要求图片都可以单击(双击)查看大图。在网上找的代码都是直接在activity里设置ImageView 的OnTouchListener事件来实现的。如果有多个地方要用到的话,代码重复量很大,所以自己封装了一下,当然了,OnTouchListener的代码还是在网上借鉴来的,上代码:

package org.vstinspection.activity.uihelper;

import org.vstinspection.utils.AppUtils;
import android.graphics.Bitmap;
import android.graphics.Matrix;
import android.graphics.PointF;
import android.graphics.RectF;
import android.util.FloatMath;
import android.view.MotionEvent;
import android.view.View;
import android.view.View.OnTouchListener;
import android.widget.ImageView;

public class ImageViewTouchListener implements OnTouchListener {
private ImageView imageView;
private Bitmap bm;
private CustomDialog dialog;

public ImageViewTouchListener(CustomDialog dialog, ImageView imageView,
Bitmap bm) {
this.imageView = imageView;
this.bm = Bitmap.createBitmap(bm, 0, 0, bm.getWidth() - 1,
bm.getHeight() - 1);
this.dialog = dialog;
init();
}

private void init() {
center(true,true);
imageView.setImageMatrix(matrix);
}

/** 记录是拖拉照片模式还是放大缩小照片模式 */
private int mode = 0;// 初始状态
/** 拖拉照片模式 */
private static final int MODE_DRAG = 1;
/** 放大缩小照片模式 */
private static final int MODE_ZOOM = 2;

/** 用于记录开始时候的坐标位置 */
private PointF startPoint = new PointF();
/** 用于记录拖拉图片移动的坐标位置 */
private Matrix matrix = new Matrix();
/** 用于记录图片要进行拖拉时候的坐标位置 */
private Matrix currentMatrix = new Matrix();

/** 两个手指的开始距离 */
private float startDis;
/** 两个手指的中间点 */
private PointF midPoint;

@Override
public boolean onTouch(View v, MotionEvent event) {
/** 通过与运算保留最后八位 MotionEvent.ACTION_MASK = 255 */
switch (event.getAction() & MotionEvent.ACTION_MASK) {
// 手指压下屏幕
case MotionEvent.ACTION_DOWN:
if (AppUtils.Utils.isFastDoubleClick(500)) {
dialog.dismiss();
return true;
}
mode = MODE_DRAG;
// 记录ImageView当前的移动位置
currentMatrix.set(imageView.getImageMatrix());
startPoint.set(event.getX(), event.getY());
break;
// 手指在屏幕上移动,改事件会被不断触发
case MotionEvent.ACTION_MOVE:
// 拖拉图片
if (mode == MODE_DRAG) {
float dx = event.getX() - startPoint.x; // 得到x轴的移动距离
float dy = event.getY() - startPoint.y; // 得到x轴的移动距离
// 在没有移动之前的位置上进行移动
matrix.set(currentMatrix);
matrix.postTranslate(dx, dy);
}
// 放大缩小图片
else if (mode == MODE_ZOOM) {
float endDis = distance(event);// 结束距离
if (endDis > 10f) { // 两个手指并拢在一起的时候像素大于10
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) { // 两个手指并拢在一起的时候像素大于10
midPoint = mid(event);
// 记录当前ImageView的缩放倍数
currentMatrix.set(imageView.getImageMatrix());
}
break;
}
imageView.setImageMatrix(matrix);
CheckView();
return true;
}

/** 计算两个手指间的距离 */
private float distance(MotionEvent event) {
float dx = event.getX(1) - event.getX(0);
float dy = event.getY(1) - event.getY(0);
/** 使用勾股定理返回两点之间的距离 */
return FloatMath.sqrt(dx * dx + dy * dy);
}

/** 计算两个手指间的中间点 */
private PointF mid(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);
}


private void CheckView() {
float p[] = new float[9];
matrix.getValues(p);
if (mode == 2) {
if (p[0] < 1f) {
matrix.setScale(1f, 1f);
}
if (p[0] > 4f) {
matrix.setScale(4f, 4f);
}
}
center(true, true);
}

/**
* 横向、纵向居中
*/
protected void center(boolean horizontal, boolean vertical) {
Matrix m = new Matrix();
m.set(matrix);
RectF rect = new RectF(0, 0, bm.getWidth(), bm.getHeight());
m.mapRect(rect);
float height = rect.height();
float width = rect.width();
float deltaX = 0, deltaY = 0;
if (vertical) {
// 图片小于屏幕大小,则居中显示。大于屏幕,上方留空则往上移,下方留空则往下移
int screenHeight = UIHelper.height;
if (height < screenHeight) {
deltaY = (screenHeight - height) / 2 - rect.top;
} else if (rect.top > 0) {
deltaY = -rect.top;
} else if (rect.bottom < screenHeight) {
deltaY = imageView.getHeight() - rect.bottom;
}
}

if (horizontal) {
int screenWidth = UIHelper.width;
if (width < screenWidth) {
deltaX = (screenWidth - width) / 2 - rect.left;
} else if (rect.left > 0) {
deltaX = -rect.left;
} else if (rect.right < screenWidth) {
deltaX = screenWidth - rect.right;
}
}
matrix.postTranslate(deltaX, deltaY);
}
}


ps:我是以弹出Dialog的方式实现的,在dialog里设置ImageView的OnTouchListener 

具体用法:

在具体要缩放图片的Activity里调用方法:PopuDialogUtil.popuImageDialog(Context,Bitmap);

public static void popuImageDialog(Context context, Bitmap bm) {
if (bm == null) {
return;
}
final CustomDialog dialog = new CustomDialog(context,
R.layout.imageview1, LayoutParams.MATCH_PARENT,
LayoutParams.MATCH_PARENT);
ImageView imageView = (ImageView) dialog.findViewById(R.id.image);
imageView.setImageBitmap(bm);
imageView.setOnTouchListener(new ImageViewTouchListener(dialog,
imageView, bm));
dialog.show();
}

顺便附上CustomDialog 代码(实现无外/黑框的弹出框)

public CustomDialog(Context context, int layout, int width, int height) {
super(context, R.style.DialogStyle);
setContentView(layout);
Window window = getWindow();
WindowManager.LayoutParams params = window.getAttributes();
params.width = width;
params.height = height;
params.gravity = Gravity.CENTER;
window.setAttributes(params);
setCanceledOnTouchOutside(true);// 点击对话框外部取消对话框显示
}

R.style.DialogStyle:

 <style name="DialogStyle" parent="@android:Theme.Dialog">
        <item name="android:windowFrame">@null</item>
        <item name="android:windowNoTitle">true</item>
        <item name="android:windowBackground">@null</item>
        <item name="android:windowIsFloating">true</item>
        <item name="android:windowContentOverlay">@null</item>
    </style>

很详尽吧,不用谢啦~~~~

原创粉丝点击