[Android]可缩放性ImageView(可以放大缩小)

[Android]可缩放性ImageView(可以放大缩小)

分类:[Android]开发

由于项目需求的原因,最近一直在研究可缩放性ImageView,,用本文来记录一下最近所学:

该ImageView的实现功能有:

1)初步打开时,图片按比例满屏(填充ImageView)显示。

2)在放大缩小过程中,可以控制最大放大比例和最小缩小比例。

3)在缩放过程中,若图片的宽或高小于ImageView,则在图片在宽或高居中显示。

4)在放大后,可以移动图片,并且限制好移动的边界,不会超出图片。

5)实现双击放大或缩小的功能。(若当前图片显示为最大的比例则缩小为最小比例,若不是最小比例则放大了最大比例)

在讲代码之前,首先应该说说一个类,Matrix。因为我们在处理图片的过程中,需要图片的位移,缩放等等,而Matrix刚好就是帮我们封装好了这些数据,具体的,大家可以看看这篇文章:android 从matrix获取处理过的图片的实际宽度重点是了解Matrix里面数组的含义。

上代码,具体的说明代码都有一一介绍:

MyZoomImageView.java文件:

package com.xiaoyan.doubletouch;import android.content.Context;import android.graphics.Matrix;import android.graphics.PointF;import android.graphics.drawable.Drawable;import android.util.AttributeSet;import android.util.FloatMath;import android.view.MotionEvent;import android.view.View;import android.view.ViewTreeObserver;import android.view.ViewTreeObserver.OnGlobalLayoutListener;import android.widget.ImageView;/** * 缩放ImageView * * @author xiejinxiong * */public class MyZoomImageView extends ImageView {/** ImageView高度 */private int imgHeight;/** ImageView宽度 */private int imgWidth;/** 图片高度 */private int intrinsicHeight;/** 图片宽度 */private int intrinsicWidth;/** 最大缩放级别 */private float mMaxScale = 2.0f;/** 最小缩放级别 */private float mMinScale = 0.2f;/** 用于记录拖拉图片移动的坐标位置 */private Matrix matrix = new Matrix();/** 用于记录图片要进行拖拉时候的坐标位置 */private Matrix currentMatrix = new Matrix();/** 记录第一次点击的时间 */private long firstTouchTime = 0;/** 时间点击的间隔 */private int intervalTime = 250;/** 第一次点完坐标 */private PointF firstPointF;public MyZoomImageView(Context context) {super(context);initUI();}public MyZoomImageView(Context context, AttributeSet attrs) {super(context, attrs);initUI();}public MyZoomImageView(Context context, AttributeSet attrs, int defStyle) {super(context, attrs, defStyle);// TODO Auto-generated constructor stubinitUI();}/** * 初始化UI */private void initUI() {this.setScaleType(ScaleType.FIT_CENTER);this.setOnTouchListener(new TouchListener());getImageViewWidthHeight();getIntrinsicWidthHeight();}/** * 获得图片内在宽高 */private void getIntrinsicWidthHeight() {Drawable drawable = this.getDrawable();// 初始化bitmap的宽高intrinsicHeight = drawable.getIntrinsicHeight();intrinsicWidth = drawable.getIntrinsicWidth();}private final class TouchListener implements OnTouchListener {/** 记录是拖拉照片模式还是放大缩小照片模式 */private int mode = 0;// 初始状态/** 拖拉照片模式 */private static final int MODE_DRAG = 1;/** 放大缩小照片模式 */private static final int MODE_ZOOM = 2;/** 用于记录开始时候的坐标位置 */private PointF startPoint = new PointF();/** 两个手指的开始距离 */private float startDis;/** 两个手指的中间点 */private PointF midPoint;public boolean onTouch(View v, MotionEvent event) {/** 通过与运算保留最后八位 MotionEvent.ACTION_MASK = 255 */switch (event.getAction() & MotionEvent.ACTION_MASK) {// 单点监听和多点触碰监听// 手指压下屏幕case MotionEvent.ACTION_DOWN:mode = MODE_DRAG;// 记录ImageView当前的移动位置currentMatrix.set(getImageMatrix());startPoint.set(event.getX(), event.getY());matrix.set(currentMatrix);makeImageViewFit();break;// 手指在屏幕上移动,改事件会被不断触发case MotionEvent.ACTION_MOVE:// 拖拉图片if (mode == MODE_DRAG) {// System.out.println("ACTION_MOVE_____MODE_DRAG");float dx = event.getX() – startPoint.x; // 得到x轴的移动距离float dy = event.getY() – startPoint.y; // 得到x轴的移动距离// 在没有移动之前的位置上进行移动zmatrix.set(currentMatrix);float[] values = new float[9];matrix.getValues(values);dx = checkDxBound(values, dx);dy = checkDyBound(values, dy);matrix.postTranslate(dx, dy);}// 放大缩小图片else if (mode == MODE_ZOOM) {float endDis = distance(event);// 结束距离if (endDis > 10f) { // 两个手指并拢在一起的时候像素大于10float scale = endDis / startDis;// 得到缩放倍数matrix.set(currentMatrix);float[] values = new float[9];matrix.getValues(values);scale = checkFitScale(scale, values);matrix.postScale(scale, scale, midPoint.x, midPoint.y);}}break;// 手指离开屏幕case MotionEvent.ACTION_UP:setDoubleTouchEvent(event);case MotionEvent.ACTION_POINTER_UP:// System.out.println("ACTION_POINTER_UP");mode = 0;// matrix.set(currentMatrix);float[] values = new float[9];matrix.getValues(values);makeImgCenter(values);break;// 当屏幕上已经有触点(手指),再有一个触点压下屏幕case MotionEvent.ACTION_POINTER_DOWN:// System.out.println("ACTION_POINTER_DOWN");mode = MODE_ZOOM;/** 计算两个手指间的距离 */startDis = distance(event);/** 计算两个手指间的中间点 */if (startDis > 10f) { // 两个手指并拢在一起的时候像素大于10midPoint = mid(event);// 记录当前ImageView的缩放倍数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 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);}/** * 和当前矩阵对比,检验dy,使图像移动后不会超出ImageView边界 ** @param values * @param dy * @return */private float checkDyBound(float[] values, float dy) {float height = imgHeight;if (intrinsicHeight * values[Matrix.MSCALE_Y] < height)return 0;if (values[Matrix.MTRANS_Y] + dy > 0)dy = -values[Matrix.MTRANS_Y];else if (values[Matrix.MTRANS_Y] + dy < -(intrinsicHeight* values[Matrix.MSCALE_Y] – height))dy = -(intrinsicHeight * values[Matrix.MSCALE_Y] – height)- values[Matrix.MTRANS_Y];return dy;}/** * 和当前矩阵对比,检验dx,使图像移动后不会超出ImageView边界 ** @param values * @param dx * @return */private float checkDxBound(float[] values, float dx) {float width = imgWidth;if (intrinsicWidth * values[Matrix.MSCALE_X] < width)return 0;if (values[Matrix.MTRANS_X] + dx > 0)dx = -values[Matrix.MTRANS_X];else if (values[Matrix.MTRANS_X] + dx < -(intrinsicWidth* values[Matrix.MSCALE_X] – width))dx = -(intrinsicWidth * values[Matrix.MSCALE_X] – width)- values[Matrix.MTRANS_X];return dx;}/** * MSCALE用于处理缩放变换 *** MSKEW用于处理错切变换 *** MTRANS用于处理平移变换 *//** * 检验scale,使图像缩放后不会超出最大倍数 ** @param scale * @param values * @return */private float checkFitScale(float scale, float[] values) {if (scale * values[Matrix.MSCALE_X] > mMaxScale)scale = mMaxScale / values[Matrix.MSCALE_X];if (scale * values[Matrix.MSCALE_X] < mMinScale)scale = mMinScale / values[Matrix.MSCALE_X];return scale;}/** * 促使图片居中 ** @param values *(包含着图片变化信息) */private void makeImgCenter(float[] values) {// 缩放后图片的宽高float zoomY = intrinsicHeight * values[Matrix.MSCALE_Y];float zoomX = intrinsicWidth * values[Matrix.MSCALE_X];// 图片左上角Y坐标float leftY = values[Matrix.MTRANS_Y];// 图片左上角X坐标float leftX = values[Matrix.MTRANS_X];// 图片右下角Y坐标float rightY = leftY + zoomY;// 图片右下角X坐标float rightX = leftX + zoomX;// 使图片垂直居中if (zoomY < imgHeight) {float marY = (imgHeight – zoomY) / 2.0f;matrix.postTranslate(0, marY – leftY);}// 使图片水平居中if (zoomX < imgWidth) {float marX = (imgWidth – zoomX) / 2.0f;matrix.postTranslate(marX – leftX, 0);}// 使图片缩放后上下不留白(即当缩放后图片的大小大于imageView的大小,但是上面或下面留出一点空白的话,将图片移动占满空白处)if (zoomY >= imgHeight) {if (leftY > 0) {// 判断图片上面留白matrix.postTranslate(0, -leftY);}if (rightY < imgHeight) {// 判断图片下面留白matrix.postTranslate(0, imgHeight – rightY);}}// 使图片缩放后左右不留白if (zoomX >= imgWidth) {if (leftX > 0) {// 判断图片左边留白matrix.postTranslate(-leftX, 0);}if (rightX < imgWidth) {// 判断图片右边不留白matrix.postTranslate(imgWidth – rightX, 0);}}}}/** * 获取ImageView的宽高 */private void getImageViewWidthHeight() {ViewTreeObserver vto2 = getViewTreeObserver();vto2.addOnGlobalLayoutListener(new OnGlobalLayoutListener() {@SuppressWarnings("deprecation")public void onGlobalLayout() {getViewTreeObserver().removeGlobalOnLayoutListener(this);imgWidth = getWidth();imgHeight = getHeight();}});}/** * 使得ImageView一开始便显示最适合的宽高比例,便是刚好容下的样子 */private void makeImageViewFit() {if (getScaleType() != ScaleType.MATRIX) {setScaleType(ScaleType.MATRIX);matrix.postScale(1.0f, 1.0f, imgWidth / 2, imgHeight / 2);}}/** * 双击事件触发 * * @param values */private void setDoubleTouchEvent(MotionEvent event) {float values[] = new float[9];matrix.getValues(values);// 存储当前时间long currentTime = System.currentTimeMillis();// 判断两次点击间距时间是否符合if (currentTime – firstTouchTime >= intervalTime) {firstTouchTime = currentTime;firstPointF = new PointF(event.getX(), event.getY());} else {// 判断两次点击之间的距离是否小于30fif (Math.abs(event.getX() – firstPointF.x) < 30f&& Math.abs(event.getY() – firstPointF.y) < 30f) {// 判断当前缩放比例与最大最小的比例if (values[Matrix.MSCALE_X] < mMaxScale) {matrix.postScale(mMaxScale / values[Matrix.MSCALE_X],mMaxScale / values[Matrix.MSCALE_X], event.getX(),event.getY());} else {matrix.postScale(mMinScale / values[Matrix.MSCALE_X],mMinScale / values[Matrix.MSCALE_X], event.getX(),event.getY());}}}}/** * 设置图片的最大和最小的缩放比例 * * @param mMaxScale * @param mMinScale */public void setPicZoomHeightWidth(float mMaxScale, float mMinScale) {this.mMaxScale = mMaxScale;this.mMinScale = mMinScale;}}xml文件:

你所缺少的部分,也早已被我用想像的画笔填满。

[Android]可缩放性ImageView(可以放大缩小)

相关文章:

你感兴趣的文章:

标签云: