自定义图片查看器,下面是效果图(分别是:原图,双指放大,缩小,移动):
下面主要的代码为(复制即可使用):
- 三个工具类
- 在 Activity 和 xml 文件中设置
CSDN 下载地址:https://download.csdn.net/download/wuqingsen1/10782132
GitHub 下载地址:https://github.com/wuqingsen/PhotoView
1. 三个工具类:
1.1 PhotoView 工具类(注意包的导入):
import android.annotation.SuppressLint;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Matrix;
import android.graphics.PointF;
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.View;
import android.view.ViewGroup;
import android.view.ViewParent;
import android.view.animation.DecelerateInterpolator;
import android.view.animation.Interpolator;
import android.widget.ImageView;
import android.widget.OverScroller;
import android.widget.Scroller;
/**
* author: wu
* date: on 2018/11/13.
* describe:图片查看器工具类,包括:
* * 双击放大、缩小;
* * 根据两指进行缩放;
* * 缩放后回弹;
* * 根据手指上下左右移动;
* 注意上面的包不要导入错了
*/
@SuppressLint("AppCompatCustomView")
public class PhotoView extends ImageView{
private final static int MIN_ROTATE = 35;
private final static int ANIMA_DURING = 340;
private final static float MAX_SCALE = 2.5f;
private int mMinRotate;
private int mAnimaDuring;
private float mMaxScale;
private int MAX_OVER_SCROLL = 0;
private int MAX_FLING_OVER_SCROLL = 0;
private int MAX_OVER_RESISTANCE = 0;
private int MAX_ANIM_FROM_WAITE = 500;
private Matrix mBaseMatrix = new Matrix();
private Matrix mAnimaMatrix = new Matrix();
private Matrix mSynthesisMatrix = new Matrix();
private Matrix mTmpMatrix = new Matrix();
private RotateGestureDetector mRotateDetector;
private GestureDetector mDetector;
private ScaleGestureDetector mScaleDetector;
private OnClickListener mClickListener;
private ScaleType mScaleType;
private boolean hasMultiTouch;
private boolean hasDrawable;
private boolean isKnowSize;
private boolean hasOverTranslate;
private boolean isEnable = false;
private boolean isRotateEnable = false;
private boolean isInit;
private boolean mAdjustViewBounds;
// 当前是否处于放大状态
private boolean isZoonUp;
private boolean canRotate;
private boolean imgLargeWidth;
private boolean imgLargeHeight;
private float mRotateFlag;
private float mDegrees;
private float mScale = 1.0f;
private int mTranslateX;
private int mTranslateY;
private float mHalfBaseRectWidth;
private float mHalfBaseRectHeight;
private RectF mWidgetRect = new RectF();
private RectF mBaseRect = new RectF();
private RectF mImgRect = new RectF();
private RectF mTmpRect = new RectF();
private RectF mCommonRect = new RectF();
private PointF mScreenCenter = new PointF();
private PointF mScaleCenter = new PointF();
private PointF mRotateCenter = new PointF();
private Transform mTranslate = new Transform();
private RectF mClip;
private Info mFromInfo;
private long mInfoTime;
private Runnable mCompleteCallBack;
private OnLongClickListener mLongClick;
public PhotoView(Context context) {
super(context);
init();
}
public PhotoView(Context context, AttributeSet attrs) {
super(context, attrs);
init();
}
public PhotoView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init();
}
private void init() {
super.setScaleType(ScaleType.MATRIX);
if (mScaleType == null) mScaleType = ScaleType.CENTER_INSIDE;
mRotateDetector = new RotateGestureDetector(mRotateListener);
mDetector = new GestureDetector(getContext(), mGestureListener);
mScaleDetector = new ScaleGestureDetector(getContext(), mScaleListener);
float density = getResources().getDisplayMetrics().density;
MAX_OVER_SCROLL = (int) (density * 30);
MAX_FLING_OVER_SCROLL = (int) (density * 30);
MAX_OVER_RESISTANCE = (int) (density * 140);
mMinRotate = MIN_ROTATE;
mAnimaDuring = ANIMA_DURING;
mMaxScale = MAX_SCALE;
}
/**
* 获取默认的动画持续时间
*/
public int getDefaultAnimaDuring() {
return ANIMA_DURING;
}
@Override
public void setOnClickListener(OnClickListener l) {
super.setOnClickListener(l);
mClickListener = l;
}
@Override
public void setScaleType(ScaleType scaleType) {
if (scaleType == ScaleType.MATRIX) return;
if (scaleType != mScaleType) {
mScaleType = scaleType;
if (isInit) {
initBase();
}
}
}
@Override
public void setOnLongClickListener(OnLongClickListener l) {
mLongClick = l;
}
/**
* 设置动画的插入器
*/
public void setInterpolator(Interpolator interpolator) {
mTranslate.setInterpolator(interpolator);
}
/**
* 获取动画持续时间
*/
public int getAnimaDuring() {
return mAnimaDuring;
}
/**
* 设置动画的持续时间
*/
public void setAnimaDuring(int during) {
mAnimaDuring = during;
}
/**
* 设置最大可以缩放的倍数
*/
public void setMaxScale(float maxScale) {
mMaxScale = maxScale;
}
/**
* 获取最大可以缩放的倍数
*/
public float getMaxScale() {
return mMaxScale;
}
/**
* 启用缩放功能
*/
public void enable() {
isEnable = true;
}
/**
* 禁用缩放功能
*/
public void disenable() {
isEnable = false;
}
/**
* 启用旋转功能
*/
public void enableRotate() {
isRotateEnable = true;
}
/**
* 禁用旋转功能
*/
public void disableRotate() {
isRotateEnable = false;
}
/**
*/
public void setMaxAnimFromWaiteTime(int wait) {
MAX_ANIM_FROM_WAITE = wait;
}
@Override
public void setImageResource(int resId) {
Drawable drawable = null;
try {
drawable = getResources().getDrawable(resId);
} catch (Exception e) {
}
setImageDrawable(drawable);
}
@Override
public void setImageDrawable(Drawable drawable) {
super.setImageDrawable(drawable);
if (drawable == null) {
hasDrawable = false;
return;
}
if (!hasSize(drawable))
return;
if (!hasDrawable) {
hasDrawable = true;
}
initBase();
}
private boolean hasSize(Drawable d) {
if ((d.getIntrinsicHeight() <= 0 || d.getIntrinsicWidth() <= 0)
&& (d.getMinimumWidth() <= 0 || d.getMinimumHeight() <= 0)
&& (d.getBounds().width() <= 0 || d.getBounds().height() <= 0)) {
return false;
}
return true;
}
private static int getDrawableWidth(Drawable d) {
int width = d.getIntrinsicWidth();
if (width <= 0) width = d.getMinimumWidth();
if (width <= 0) width = d.getBounds().width();
return width;
}
private static int getDrawableHeight(Drawable d) {
int height = d.getIntrinsicHeight();
if (height <= 0) height = d.getMinimumHeight();
if (height <= 0) height = d.getBounds().height();
return height;
}
private void initBase() {
if (!hasDrawable) return;
if (!isKnowSize) return;
mBaseMatrix.reset();
mAnimaMatrix.reset();
isZoonUp = false;
Drawable img = getDrawable();
int w = getWidth();
int h = getHeight();
int imgw = getDrawableWidth(img);
int imgh = getDrawableHeight(img);
mBaseRect.set(0, 0, imgw, imgh);
// 以图片中心点居中位移
int tx = (w - imgw) / 2;
int ty = (h - imgh) / 2;
float sx = 1;
float sy = 1;
// 缩放,默认不超过屏幕大小
if (imgw > w) {
sx = (float) w / imgw;
}
if (imgh > h) {
sy = (float) h / imgh;
}
float scale = sx < sy ? sx : sy;
mBaseMatrix.reset();
mBaseMatrix.postTranslate(tx, ty);
mBaseMatrix.postScale(scale, scale, mScreenCenter.x, mScreenCenter.y);
mBaseMatrix.mapRect(mBaseRect);
mHalfBaseRectWidth = mBaseRect.width() / 2;
mHalfBaseRectHeight = mBaseRect.height() / 2;
mScaleCenter.set(mScreenCenter);
mRotateCenter.set(mScaleCenter);
executeTranslate();
switch (mScaleType) {
case CENTER:
initCenter();
break;
case CENTER_CROP:
initCenterCrop();
break;
case CENTER_INSIDE:
initCenterInside();
break;
case FIT_CENTER:
initFitCenter();
break;
case FIT_START:
initFitStart();
break;
case FIT_END:
initFitEnd();
break;
case FIT_XY:
initFitXY();
break;
}
isInit = true;
if (mFromInfo != null && System.currentTimeMillis() - mInfoTime < MAX_ANIM_FROM_WAITE) {
animaFrom(mFromInfo);
}
mFromInfo = null;
}
private void initCenter() {
if (!hasDrawable) return;
if (!isKnowSize) return;
Drawabl