import android.content.Context;
import android.graphics.Matrix;
import android.graphics.Rect;
import android.graphics.RectF;
import android.graphics.drawable.Drawable;
import android.util.AttributeSet;
import android.view.GestureDetector;
import android.view.MotionEvent;
import android.view.ScaleGestureDetector;
import android.view.ScaleGestureDetector.OnScaleGestureListener;
import android.view.View;
import android.view.ViewConfiguration;
import android.view.ViewTreeObserver.OnGlobalLayoutListener;
import android.widget.ImageView;
import android.view.View.OnTouchListener;
/**
* 缩放类
*
*
*
*
*
* Matrix 的set,pre和post的区别
*
* pre表示在队头插入一个方法 post表示在队尾插入一个方法 set表示把当前队列清空,并且总是位于队列的最中间位置.
*
* 当执行了一次set后:pre方法总是插入到set前部的队列的最前面,post方法总是插入到set后部的队列的最后面
*
*
* ScaleGestureDetector 类 和多点触控相关
*
*/
// 接口用于捕获图片加载完成
public class MyImageView extends ImageView implements OnGlobalLayoutListener,
OnScaleGestureListener, OnTouchListener {
// -------------------------------------------
// 缩放
// ------------------------------------------
private Boolean isOnce = true;
public static final float BASABLE_SCALE_RATE = 1.0f;
// 初始化时的缩放值,也是最小的缩放值
private float mInitScale;
// 双击时缩放达到的值
private float mMidScale;
// 放大的极限
private float mMaxScale;
// 局针对象
private Matrix mMatrix;
// 获得用户多点触控时缩放的比例
private ScaleGestureDetector mScaleGestureDetector;
// -------------------------------------------
// 自由移动
// ------------------------------------------
// 记录上一次多点触控的数量
private int mLastPointerCount;
private float mLastX, mLastY;
// 用于中心点的保留
private int mTouchSlop;
// 是否可移动
private boolean isCanDrag;
// 判断
private boolean isCheckLeftAndRight;
private boolean isCheckTopAndBottom;
// -------------------------------------------
// 双击放大与缩小
// ------------------------------------------
private GestureDetector mGestureDetector;
private boolean isAutoScale;
// -------------------------------------------
// 构造类
// ------------------------------------------
public MyImageView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
mMatrix = new Matrix();
setScaleType(ScaleType.MATRIX);
mScaleGestureDetector = new ScaleGestureDetector(context, this);
setOnTouchListener(this);
mTouchSlop = ViewConfiguration.get(context).getScaledTouchSlop();
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) {
// mMatrix.postScale(mMidScale / getScale(), mMidScale
// / getScale(), x, y);
// setImageMatrix(mMatrix);
postDelayed(new AutoScaleRunnable(mMidScale, x, y), 16);
isAutoScale = true;
} else {
// mMatrix.postScale(mInitScale / getScale(),
// mInitScale / getScale(), x, y);
// setImageMatrix(mMatrix);
postDelayed(new AutoScaleRunnable(mInitScale, x, y), 16);
isAutoScale = true;
}
return true;
}
});
}
public MyImageView(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public MyImageView(Context context) {
this(context, null);
}
// 图片加载到窗口完成
@Override
protected void onAttachedToWindow() {
super.onAttachedToWindow();
// View已经实现了这个接口,所以用this
getViewTreeObserver().addOnGlobalLayoutListener(this);
}
@SuppressWarnings("deprecation")
@Override
// 图片从窗口消失
protected void onDetachedFromWindow() {
super.onDetachedFromWindow();
// 兼容16一下的版本
getViewTreeObserver().removeGlobalOnLayoutListener(this);
}
// 获取ImageView加载完成的图片
@Override
public void onGlobalLayout() {
if (isOnce) {
// 获得控件的宽高
int width = getWidth();
int height = getHeight();
// 或的图片以及宽高
Drawable d = getDrawable();
if (d == null)
return;
int dw = d.getIntrinsicWidth();
int dh = d.getIntrinsicHeight();
// 缩放比例
float scale = 1.0f;
// 宽超出屏幕
if (dw > width && dh < height) {
scale = width * BASABLE_SCALE_RATE / dw;
}
// 高超出屏幕
if (dh > height && dw < width) {
scale = height * BASABLE_SCALE_RATE / dh;
}
// 同时超出屏幕 或 同时未超出 应调整到有一边是满边距
if ((dw < width && dh < height) || (dw > width && dh > height)) {
scale = Math.min(width * BASABLE_SCALE_RATE / dw, height
* BASABLE_SCALE_RATE / dh);
}
// 初始化时缩放的比例
mInitScale = scale;
mMaxScale = 4 * mInitScale;
mMidScale = 2 * mInitScale;
/**
*
* 将图片移动到控件的中心
*/
// 需要移动的宽高
int dx = width / 2 - dw / 2;
int dy = height / 2 - dh / 2;
// 利用矩阵,对图像进行移动 等操作
mMatrix.postTranslate(dx, dy);
mMatrix.postScale(mInitScale, mInitScale, width / 2, height / 2);
setImageMatrix(mMatrix);
isOnce = false;
} else {
}
}
/**
* 获取当前的缩放比例
*
* 此方法不甚了解
* */
public float getScale() {
float values[] = new float[9];
mMatrix.getValues(values);
return values[Matrix.MSCALE_X];
}
// 缩放中
@Override
public boolean onScale(ScaleGestureDetector detector) {
// scaleFactor 是缩放的值
float scaleFactor = detector.getScaleFactor();
float scale = getScale();
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) {
scale = mMaxScale / scale;
}
// 缩放
mMatrix.postScale(scaleFactor, scaleFactor, detector.getFocusX(),
detector.getFocusY());
// 防止出现白边,并居中
checkBorderAndCenter();
setImageMatrix(mMatrix);
}
return false;
}
// 此处应该设置为true
@Override
public boolean onScaleBegin(ScaleGestureDetector detector) {
return true;
}
@Override
public void onScaleEnd(ScaleGestureDetector detector) {
}
// 利用触摸事件,mScaleGestureDetector获得多个焦点坐标,以便实现多点触控
@Override
public boolean onTouch(View v, MotionEvent event) {
if (mGestureDetector.onTouchEvent(event))
return true;
mScaleGestureDetector.onTouchEvent(event);
// x,y是中心点的位置
float x = 0, y = 0;
// 多点触控的数量
int pointerCount = event.getPointerCount();
for (int i = 0; i < pointerCount; i++) {
x += event.getX(i);
y += event.getY(i);
isCanDrag = false;
}
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()) {
dx = 0;
isCheckLeftAndRight = false;
}
// 高度小于控件高度,不允许移动
if (rectF.height() < getHeight()) {
dy = 0;
isCheckTopAndBottom = false;
}
mMatrix.postTranslate(dx, dy);
checkBorderWhenTranslate();
setImageMatrix(mMatrix);
}
}
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;
}
mMatrix.postTranslate(deltaX, deltaY);
}
/**
* 是否是move
*/
private boolean isMoveAction(float dx, float dy) {
return Math.sqrt(dx * dx + dy * dy) > mTouchSlop;
}
// Rect是矩形,边界是float,所以是RectF
// 此方法用来RectF对象来获得放大缩小后的宽高
public RectF getMatrixRectF() {
Matrix matrix = mMatrix;
RectF rectF = new RectF();
Drawable d = getDrawable();
if (d != null) {
rectF.set(0, 0, d.getIntrinsicWidth(), d.getIntrinsicHeight());
matrix.mapRect(rectF);
}
return rectF;
}
// 在缩放时对边界的控制
public void checkBorderAndCenter() {
RectF rectF = getMatrixRectF();
// 超出屏幕的长度
float deltaX = 0;
float deltaY = 0;
int width = getWidth();
int height = getHeight();
// 边界检测,防止出现白边
if (rectF.width() >= width) {
// 左边出现空白
if (rectF.left > 0) {
deltaX = -rectF.left;
}
// 右边出现空白
if (rectF.right < width) {
deltaX = width - rectF.right;
}
}
if (rectF.height() >= height) {
if (rectF.top > 0) {
deltaY = -rectF.top;
}
if (rectF.bottom < width) {
deltaY = height - rectF.bottom;
}
}
// 如果图片的宽高小于控件的宽高,则让其居中显示
if (rectF.width() < width) {
deltaX = width / 2f - rectF.right + rectF.width() / 2f;
}
if (rectF.height() < height) {
deltaY = height / 2f - rectF.bottom + rectF.height() / 2f;
}
mMatrix.postTranslate(deltaX, deltaY);
}
/**
* 自动缩放
*
*
*/
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) {
super();
this.mTargetScale = mTargetScale;
this.x = x;
this.y = y;
if (getScale() > mTargetScale) {
tmpScale = BIGGER;
}
if (getScale() < mTargetScale) {
tmpScale = SMALL;
}
}
public void run() {
//进行缩放
mMatrix.postScale(tmpScale, tmpScale, x, y);
checkBorderAndCenter();
setImageMatrix(mMatrix);
float currentScale = getScale();
if ((tmpScale > 1.0f && currentScale < mTargetScale)
|| (tmpScale < 1.0f && currentScale > mTargetScale)) {
postDelayed(this, 16);
} else {
float scale = mTargetScale/currentScale;
mMatrix.postScale(scale, scale, x, y);
checkBorderAndCenter();
setImageMatrix(mMatrix);
isAutoScale = false;
}
}
}
}
android 图片缩放
最新推荐文章于 2023-02-15 17:05:51 发布