自定义实现双击放大缩小的ImageView控件

xiaoxiao2021-02-28  25

一、创建一个名为 ZoomImageView的类,里面写有支持图片放大缩小的功能

package cgg.com.threeapp.view.costomView; import android.annotation.SuppressLint; import android.content.Context; import android.graphics.Matrix; import android.graphics.RectF; import android.graphics.drawable.Drawable; import android.support.v4.view.ViewPager; import android.util.AttributeSet; 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; /** * author: Wanderer * date: 2018/3/21 20:49 * email: none */ @SuppressLint("AppCompatCustomView") public class ZoomImageView extends ImageView implements ViewTreeObserver.OnGlobalLayoutListener, ScaleGestureDetector.OnScaleGestureListener, View.OnTouchListener { private boolean mOnce; /** * 初始化时缩放的值 */ private float mInitScale; /** * 双击放大值到达的值 */ private float mMidScale; /** * 放大的最大值 */ private float mMaxScale; private Matrix mScaleMatrix; /** * 捕获用户多指触控时缩放的比例 */ private ScaleGestureDetector mScaleGestureDetector; // **********自由移动的变量*********** /** * 记录上一次多点触控的数量 */ private int mLastPointerCount; private float mLastX; private float mLastY; private int mTouchSlop; private boolean isCanDrag; 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 defStyle) { super(context, attrs, defStyle); // init mScaleMatrix = new Matrix(); setScaleType(ScaleType.MATRIX); setOnTouchListener(this); mTouchSlop = ViewConfiguration.get(context).getScaledTouchSlop(); mScaleGestureDetector = 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) { postDelayed(new AutoScaleRunnable(mMidScale, x, y), 16); isAutoScale = true; } else { postDelayed(new AutoScaleRunnable(mInitScale, x, y), 16); isAutoScale = true; } return true; } }); } /** * 自动放大与缩小 * * @author zhangyan@lzt.com.cn * */ 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; /** * @param mTargetScale * @param x * @param y */ 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); checkBorderAndCenterWhenScale(); setImageMatrix(mScaleMatrix); float currentScale = getScale(); if ((tmpScale >1.0f && currentScale <mTargetScale) ||(tmpScale<1.0f &¤tScale>mTargetScale)) { //这个方法是重新调用run()方法 postDelayed(this, 16); }else{ //设置为我们的目标值 float scale = mTargetScale/currentScale; mScaleMatrix.postScale(scale, scale, x, y); checkBorderAndCenterWhenScale(); setImageMatrix(mScaleMatrix); isAutoScale = false; } } } /** * 获取ImageView加载完成的图片 */ @Override public void onGlobalLayout() { if (!mOnce) { // 得到控件的宽和高 int width = getWidth(); int height = getHeight(); // 得到我们的图片,以及宽和高 Drawable drawable = getDrawable(); if (drawable == null) { return; } int dh = drawable.getIntrinsicHeight(); int dw = drawable.getIntrinsicWidth(); float scale = 0.6f; // 图片的宽度大于控件的宽度,图片的高度小于空间的高度,我们将其缩小 if (dw > width && dh < height) { scale = width * 1.0f / dw; } // 图片的宽度小于控件的宽度,图片的高度大于空间的高度,我们将其缩小 if (dh > height && dw < width) { scale = height * 1.0f / dh; } // 缩小值 if (dw > width && dh > height) { scale = Math.min(width * 1.0f / dw, height * 1.0f / dh); } // 放大值 if (dw < width && dh < height) { scale = Math.min(width * 1.0f / dw, height * 1.0f / dh); } /** * 得到了初始化时缩放的比例 */ mInitScale = scale; mMaxScale = mInitScale * 4; mMidScale = mInitScale * 2; // 将图片移动至控件的中间 int dx = getWidth() / 2 - dw / 2; int dy = getHeight() / 2 - dh / 2; mScaleMatrix.postTranslate(dx, dy); mScaleMatrix.postScale(mInitScale, mInitScale, width / 2, height / 2); setImageMatrix(mScaleMatrix); mOnce = true; } } /** * 注册OnGlobalLayoutListener这个接口 */ @Override protected void onAttachedToWindow() { super.onAttachedToWindow(); getViewTreeObserver().addOnGlobalLayoutListener(this); } /** * 取消OnGlobalLayoutListener这个接口 */ @SuppressWarnings("deprecation") @Override protected void onDetachedFromWindow() { super.onDetachedFromWindow(); getViewTreeObserver().removeGlobalOnLayoutListener(this); } /** * 获取当前图片的缩放值 * * @return */ public float getScale() { float[] values = new float[9]; mScaleMatrix.getValues(values); return values[Matrix.MSCALE_X]; } // 缩放区间时initScale maxScale @Override public boolean onScale(ScaleGestureDetector detector) { float scale = getScale(); float scaleFactor = detector.getScaleFactor(); 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; } // 缩放 mScaleMatrix.postScale(scaleFactor, scaleFactor, detector.getFocusX(), detector.getFocusY()); checkBorderAndCenterWhenScale(); setImageMatrix(mScaleMatrix); } return true; } /** * 获得图片放大缩小以后的宽和高,以及left,right,top,bottom * * @return */ private RectF getMatrixRectF() { Matrix matrix = mScaleMatrix; RectF rectF = new RectF(); Drawable d = getDrawable(); if (d != null) { rectF.set(0, 0, d.getIntrinsicWidth(), d.getIntrinsicHeight()); matrix.mapRect(rectF); } return rectF; } /** * 在缩放的时候进行边界以及我们的位置的控制 */ private void checkBorderAndCenterWhenScale() { 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 < height) { 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; } 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; } mScaleGestureDetector.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) { isCanDrag = false; mLastX = x; mLastY = y; } mLastPointerCount = pointerCount; RectF rectF = getMatrixRectF(); switch (event.getAction()) { case MotionEvent.ACTION_DOWN: if (rectF.width()>getWidth() +0.01|| rectF.height()>getHeight()+0.01) { if(getParent() instanceof ViewPager) getParent().requestDisallowInterceptTouchEvent(true); } break; case MotionEvent.ACTION_MOVE: if (rectF.width()>getWidth()+0.01 || rectF.height()>getHeight()+0.01) { if(getParent() instanceof ViewPager) getParent().requestDisallowInterceptTouchEvent(true); } float dx = x - mLastX; float dy = y - mLastY; if (!isCanDrag) { isCanDrag = isMoveAction(dx, dy); } if (isCanDrag) { 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; default: break; } return true; } /** * 当移动时进行边界检查 */ private void checkBorderWhenTranslate() { RectF rectF = getMatrixRectF(); float deltaX = 0; float deltaY = 0; int width = getWidth(); int heigth = getHeight(); if (rectF.top > 0 && isCheckTopAndBottom) { deltaY = -rectF.top; } if (rectF.bottom < heigth && isCheckTopAndBottom) { deltaY = heigth - rectF.bottom; } if (rectF.left > 0 && isCheckLeftAndRight) { deltaX = -rectF.left; } if (rectF.right < width && isCheckLeftAndRight) { deltaX = width - rectF.right; } mScaleMatrix.postTranslate(deltaX, deltaY); } /** * 判断是否是move * * @param dx * @param dy * @return */ private boolean isMoveAction(float dx, float dy) { return Math.sqrt(dx * dx + dy * dy) > mTouchSlop; } }

二、在布局中进行引用创建的那个类

<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical" tools:context="com.xwj.lenovo.xuwenjuan20180505.view.PhotoIconActivity"> <com.xwj.lenovo.xuwenjuan20180505.application.ZoomImageView android:id="@+id/po" android:src="@mipmap/ic_launcher" android:layout_width="match_parent" android:layout_height="match_parent"/> </LinearLayout>

三、adpter传递过来的图片路径

holder.icon.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { Intent intent = new Intent(context, PhotoIconActivity.class); intent.putExtra("icon",list.get(position).getUrl()); context.startActivity(intent); } });

四、在Activity中调用

package com.xwj.lenovo.xuwenjuan20180505.view; import android.os.Bundle; import android.support.v7.app.AppCompatActivity; import com.bumptech.glide.Glide; import com.xwj.lenovo.xuwenjuan20180505.R; import com.xwj.lenovo.xuwenjuan20180505.application.ZoomImageView; import butterknife.BindView; import butterknife.ButterKnife; public class PhotoIconActivity extends AppCompatActivity { @BindView(R.id.po) ZoomImageView po; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_photo_icon); ButterKnife.bind(this); //获取adapter传过来的图片路径 String icon = getIntent().getStringExtra("icon"); //判断图片不为空 if (icon != null) { Glide.with(this).load(icon).into(po); } } }
转载请注明原文地址: https://www.6miu.com/read-2799978.html

最新回复(0)