本文是采用重写ImgView实现图片放大,缩放,移动,裁剪,
package com.example.app.view;
import android.content.Context;
import android.graphics.Matrix;
import android.graphics.RectF;
import android.graphics.drawable.Drawable;
import android.util.AttributeSet;
import android.util.Log;
import android.view.GestureDetector;
import android.view.MotionEvent;
import android.view.ScaleGestureDetector;
import android.view.View;
import android.view.ViewConfiguration;
import android.view.ViewTreeObserver;
import android.widget.ImageView;
/**
* Created by User on 2015/12/13.
*/
public class ZoomImageView extends ImageView implements ViewTreeObserver.OnGlobalLayoutListener,
ScaleGestureDetector.OnScaleGestureListener, View.OnTouchListener {
private boolean mOnce = false;
/**
* 初始化时缩放的值
*/
private float mInitScale;
//private float minInitScale;
/**
* 双击放大值到达的值
*/
private float mMidScale;
/**
* 放大的大值到达的值
*/
private float mMaxScale;
/**
* 捕获用户多指触控是缩放的比例
*/
private ScaleGestureDetector scaleGestureDetector;
private Matrix mScaleMatrix;
//----------自由移动
/**
* 记录上一次多点触控的数量
*/
private int mLastPointerCount;
private float mLastX;
private float mLastY;
private int mTouchSlop;
private boolean isCanDrag;
private RectF matrixRectF;
private boolean isCheckLeftAndRight;
private boolean isCheckTopAndBottom;
/**
* 双击放大与缩小——————————————————————————
*/
private GestureDetector mGestureDetector;
private boolean isAutoScale;
public ZoomImageView(Context context) {
this(context, null);
}
public ZoomImageView(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public ZoomImageView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
mScaleMatrix = new Matrix();
super.setScaleType(ScaleType.MATRIX);
scaleGestureDetector = new ScaleGestureDetector(context, this);
mGestureDetector = new GestureDetector(context, new
GestureDetector.SimpleOnGestureListener() {
@Override
public boolean onDoubleTap(MotionEvent e) {
if (isAutoScale) {
return true;
}
float x = e.getX();
float y = e.getY();
if (getScale() < mMidScale) {
// mScaleMatrix.postScale(mMidScale / getScale(), mMidScale / getScale(), x,
y);
// setImageMatrix(mScaleMatrix);
postDelayed(new AutoScaleRunnable(mMidScale, x, y), 16);
isAutoScale = true;
} else {
// mScaleMatrix.postScale(mInitScale / getScale(), mInitScale / getScale(), x,
y);
// setImageMatrix(mScaleMatrix);
postDelayed(new AutoScaleRunnable(mInitScale, x, y), 16);
isAutoScale = true;
}
return true;
}
});
this.setOnTouchListener(this);
//判断是否是移动
mTouchSlop = ViewConfiguration.get(context).getScaledTouchSlop();
}
private class AutoScaleRunnable implements Runnable {
/**
* 缩放的目标
*/
private float mTargetScale;
//缩放的中心
private float x;
private float y;
private final float BIGGER = 1.07f;
private final float SMALL = 0.93f;
private float tmpScale;
public AutoScaleRunnable(float mTargetScale, float x, float y) {
this.mTargetScale = mTargetScale;
this.x = x;
this.y = y;
if (getScale() < mTargetScale) {
tmpScale = BIGGER;
}
if (getScale() > mTargetScale) {
tmpScale = SMALL;
}
}
@Override
public void run() {
//进行缩放
mScaleMatrix.postScale(tmpScale, tmpScale, x, y);
ckecheBorderAndCenterWhenScale();
setImageMatrix(mScaleMatrix);
float currentScale = getScale();
if ((tmpScale > 1.0f && currentScale < mTargetScale) || (tmpScale < 1.0f &&
currentScale > mTargetScale)) {
postDelayed(this, 16);
} else {
//设置为目标值
float scale = mTargetScale / currentScale;
mScaleMatrix.postScale(scale, scale, x, y);
ckecheBorderAndCenterWhenScale();
setImageMatrix(mScaleMatrix);
isAutoScale = false;
}
}
}
@Override
protected void onAttachedToWindow() {
super.onAttachedToWindow();
//添加
getViewTreeObserver().addOnGlobalLayoutListener(this);
}
@Override
protected void onDetachedFromWindow() {
super.onDetachedFromWindow();
//删除
getViewTreeObserver().removeGlobalOnLayoutListener(this);
}
/**
* 获取ImageView加载完成的图片
*/
@Override
public void onGlobalLayout() {
if (!mOnce) {
//得到控件的宽和高
int width = getWidth();
int height = getHeight();
//得到我们的图片,以及宽和高
Drawable drawable = getDrawable();
if (drawable == null) {
return;
}
int drawableWidth = drawable.getIntrinsicWidth();
int drawableHeight = drawable.getIntrinsicHeight();
float scale = 1.0f;
float minScale = 1.0f;
/**
* 如果图片的宽度大于控件宽度,但是高度小于控件宽度,我们将其放大、
* */
if (drawableWidth > width && drawableHeight < height) {
scale = width * 1.0f / drawableWidth;
}
/**
* 如果图片的高度于控件高度,但是宽度小于控件宽度,我们将其缩小、
* */
if (drawableHeight > height && drawableWidth < width) {
scale = height * 1.0f / drawableHeight;
}
/**
* 如果图片的宽高都大于控件,我们将其缩小,。
* */
if (drawableWidth > width && drawableHeight > height) {
scale = Math.min(width * 1.0f / drawableWidth, height * 1.0f / drawableHeight);
}
/**
* 如果图片的宽高都小于控件,我们将其放大。
* */
if (drawableWidth < width && drawableHeight < height) {
scale = Math.min(width * 1.0f / drawableWidth, height * 1.0f / drawableHeight);
}
/**
* 得到了初始化时缩放的比例
* */
mInitScale = scale;
mMaxScale = mInitScale * 4;
mMidScale = mInitScale * 2;
// minInitScale = minScale;
mOnce = true;
/**
* 将图片移动至控件的中心
* */
int dx = getWidth() / 2 - drawableWidth / 2;
int dy = getHeight() / 2 - drawableHeight / 2;
mScaleMatrix.postTranslate(dx, dy);
mScaleMatrix.postScale(mInitScale, mInitScale, width / 2, height / 2);
setImageMatrix(mScaleMatrix);
}
}
//缩放的区间:initScale,MaxScale
//获取图片当前的缩放值
public float getScale() {
float[] values = new float[9];
mScaleMatrix.getValues(values);
return values[Matrix.MSCALE_X];
}
@Override
public boolean onScale(ScaleGestureDetector detector) {
float scale = getScale();
//获得当前的缩放值
float scaleFactor = detector.getScaleFactor();
Log.d("scaleFactor", ":" + scaleFactor);
if (getDrawable() == null) {
return true;
}
//缩放范围的控制
if ((scale < mMaxScale && scaleFactor > 1.0f) ||
(scale > mInitScale && scaleFactor < 1.0f)) {
if (scale * scaleFactor < mInitScale) {
scaleFactor = mInitScale / scale;
}
if (scale * scaleFactor > mMaxScale) {
scaleFactor = mMaxScale / scale;
}
mScaleMatrix.postScale(scaleFactor, scaleFactor, detector.getFocusX(),
detector.getFocusY());
ckecheBorderAndCenterWhenScale();
setImageMatrix(mScaleMatrix);
}
return true;
}
/**
* 获得图片放大缩小以后的宽和高,以及l,r,t,b
*/
private RectF getMatrixRectF() {
Matrix rMatrix = mScaleMatrix;
RectF rectF = new RectF();
Drawable d = getDrawable();
if (d != null) {
rectF.set(0, 0, d.getIntrinsicWidth(), d.getIntrinsicHeight());
rMatrix.mapRect(rectF);
}
return rectF;
}
/**
* 再缩放的时候进行边界控制已经我们的位置的控制
*/
private void ckecheBorderAndCenterWhenScale() {
RectF rect = getMatrixRectF();
float deltaX = 0;
float deltaY = 0;
int width = getWidth();
int height = getHeight();
if (rect.width() >= width) {
if (rect.left > 0) {
deltaX = -rect.left;
}
if (rect.right < width) {
deltaX = width - rect.right;
}
}
if (rect.height() >= height) {
if (rect.top > 0) {
deltaY = -rect.top;
}
if (rect.bottom < height) {
deltaY = height - rect.bottom;
}
}
/**
* 如果宽度或者高度小于控件的宽或者高;则让其居中
*
* */
if (rect.width() < width) {
deltaX = width * 0.5f - rect.right + 0.5f * rect.width();
}
if (rect.height() < height) {
deltaY = height * 0.5f - rect.bottom + 0.5f * rect.height();
}
mScaleMatrix.postTranslate(deltaX, deltaY);
}
@Override
public boolean onScaleBegin(ScaleGestureDetector detector) {
return true;
}
@Override
public void onScaleEnd(ScaleGestureDetector detector) {
}
@Override
public boolean onTouch(View v, MotionEvent event) {
if (mGestureDetector.onTouchEvent(event)) {
return true;
}
scaleGestureDetector.onTouchEvent(event);
float X = 0;
float Y = 0;
/**
* 拿到多点触控的数量
* */
int pointerCount = event.getPointerCount();
for (int i = 0; i < pointerCount; i++) {
X += event.getX(i);
Y += event.getY(i);
}
X /= pointerCount;
Y /= pointerCount;
if (mLastPointerCount != pointerCount) {
mLastX = X;
mLastY = Y;
}
mLastPointerCount = pointerCount;
switch (event.getAction()) {
case MotionEvent.ACTION_MOVE:
float dx = X - mLastX;
float dy = Y - mLastY;
if (!isCanDrag) {
isCanDrag = isMoveAction(dx, dy);
}
if (isCanDrag) {
RectF rectF = getMatrixRectF();
if (getDrawable() != null) {
isCheckLeftAndRight = isCheckTopAndBottom = true;
/**
* 如果宽度小于控件宽度,不允许横向移动
* */
if (rectF.width() < getWidth()) {
isCheckLeftAndRight = false;
dx = 0;
}
/**
* 如果高度小于控件高度,不允许纵向移动
* */
if (rectF.height() < getHeight()) {
isCheckTopAndBottom = false;
dy = 0;
}
mScaleMatrix.postTranslate(dx, dy);
checkBorderWhenTranslate();
setImageMatrix(mScaleMatrix);
}
}
mLastX = X;
mLastY = Y;
break;
case MotionEvent.ACTION_UP:
case MotionEvent.ACTION_CANCEL:
mLastPointerCount = 0;
break;
}
return true;
}
/**
* 当移动,进行边界检查
*/
private void checkBorderWhenTranslate() {
RectF rectF = getMatrixRectF();
float deltaX = 0;
float deltaY = 0;
int width = getWidth();
int height = getHeight();
if (rectF.top > 0 && isCheckTopAndBottom) {
deltaY = -rectF.top;
}
if (rectF.bottom < height && isCheckTopAndBottom) {
deltaY = height - rectF.bottom;
}
if (rectF.left > 0 && isCheckLeftAndRight) {
deltaX = -rectF.left;
}
if (rectF.right < width && isCheckLeftAndRight) {
deltaX = width - rectF.right;
}
mScaleMatrix.postTranslate(deltaX, deltaY);
}
/**
* 判断是否是Move
*/
private boolean isMoveAction(float dx, float dy) {
return Math.sqrt(dx * dx + dy * dy) > mTouchS
}
/**
* 剪切图片,返回剪切后的bitmap对象 圆形用
*
* @return
*/
public Bitmap clip() {
Bitmap bitmap = Bitmap.createBitmap(getWidth(), getHeight(),
Bitmap.Config.ARGB_8888);
Canvas canvas = new Canvas(bitmap);
int yStartPoint = DensityUtils.dp2px(getContext(), (float) 135.333);
int xStartPoint = DensityUtils.dp2px(getContext(), (float) 62);
int circleRadius = DensityUtils.dp2px(getContext(), (float) 236);
draw(canvas);
return Bitmap.createBitmap(bitmap, xStartPoint,
yStartPoint, circleRadius,
circleRadius);
}
}