效果图:

放大前:

放大后:

ZoomImageView.java

@SuppressLint("AppCompatCustomView")
public class ZoomImageView extends ImageView implements ScaleGestureDetector.OnScaleGestureListener, View.OnTouchListener, ViewTreeObserver.OnGlobalLayoutListener {private static final String TAG = ZoomImageView.class.getSimpleName();public static final float SCALE_MAX = 3.0f;private static final float SCALE_MID = 1.5f;/*** 初始化时的缩放比例,如果图片宽或高大于屏幕,此值将小于0*/private float initScale = 1.0f;private boolean once = true;/*** 用于存放矩阵的9个值*/private final float[] matrixValues = new float[9];/*** 缩放的手势检测*/private ScaleGestureDetector mScaleGestureDetector = null;private final Matrix mScaleMatrix = new Matrix();/*** 用于双击检测*/private GestureDetector mGestureDetector;private boolean isAutoScale;private int mTouchSlop;private float mLastX;private float mLastY;private boolean isCanDrag;private int lastPointerCount;private boolean isCheckTopAndBottom = true;private boolean isCheckLeftAndRight = true;public ZoomImageView(Context context) {this(context, null);}public ZoomImageView(Context context, AttributeSet attrs) {super(context, attrs);super.setScaleType(ScaleType.MATRIX);mGestureDetector = new GestureDetector(context, new GestureDetector.SimpleOnGestureListener() {@Overridepublic boolean onDoubleTap(MotionEvent e) {if (isAutoScale == true)return true;float x = e.getX();float y = e.getY();Log.e("DoubleTap", getScale() + " , " + initScale);if (getScale() < SCALE_MID) {//postDelayed(); 16 :多久实现一次的定时器操作ZoomImageView.this.postDelayed(new AutoScaleRunnable(SCALE_MID, x, y), 16);isAutoScale = true;} /*else if (getScale() >= SCALE_MID  //连续双击放大 可放开&& getScale() < SCALE_MAX) {ZoomImageView.this.postDelayed(new AutoScaleRunnable(SCALE_MAX, x, y), 16);isAutoScale = true;}*/ else {ZoomImageView.this.postDelayed(new AutoScaleRunnable(initScale, x, y), 16);isAutoScale = true;}return true;}});mScaleGestureDetector = new ScaleGestureDetector(context, this);this.setOnTouchListener(this);}/*** 自动缩放的任务* @author zhy*/private class AutoScaleRunnable implements Runnable {static final float BIGGER = 1.07f;static final float SMALLER = 0.93f;private float mTargetScale;private float tmpScale;/*** 缩放的中心*/private float x;private float y;/*** 传入目标缩放值,根据目标值与当前值,判断应该放大还是缩小* @param targetScale*/public AutoScaleRunnable(float targetScale, float x, float y) {this.mTargetScale = targetScale;this.x = x;this.y = y;if (getScale() < mTargetScale) {tmpScale = BIGGER;} else {tmpScale = SMALLER;}}@Overridepublic void run() {// 进行缩放mScaleMatrix.postScale(tmpScale, tmpScale, x, y);checkBorderAndCenterWhenScale();setImageMatrix(mScaleMatrix);final float currentScale = getScale();// 如果值在合法范围内,继续缩放if (((tmpScale > 1f) && (currentScale < mTargetScale)) || ((tmpScale < 1f) && (mTargetScale < currentScale))) {ZoomImageView.this.postDelayed(this, 16);} else {// 设置为目标的缩放比例final float deltaScale = mTargetScale / currentScale;mScaleMatrix.postScale(deltaScale, deltaScale, x, y);checkBorderAndCenterWhenScale();setImageMatrix(mScaleMatrix);isAutoScale = false;}}}/*** 对图片进行缩放的控制,首先进行缩放范围的判断,然后设置mScaleMatrix的scale值* @param detector* @return*/@SuppressLint("NewApi")@Overridepublic boolean onScale(ScaleGestureDetector detector) {float scale = getScale();float scaleFactor = detector.getScaleFactor();if (getDrawable() == null)return true;/*** 缩放的范围控制*/if ((scale < SCALE_MAX && scaleFactor > 1.0f) || (scale > initScale && scaleFactor < 1.0f)) {/*** 最大值最小值判断*/if (scaleFactor * scale < initScale) {scaleFactor = initScale / scale;}if (scaleFactor * scale > SCALE_MAX) {scaleFactor = SCALE_MAX / scale;}/*** 设置缩放比例*/mScaleMatrix.postScale(scaleFactor, scaleFactor, detector.getFocusX(), detector.getFocusY());checkBorderAndCenterWhenScale();setImageMatrix(mScaleMatrix);}return true;}/*** 在缩放时,进行图片显示范围的控制*/private void checkBorderAndCenterWhenScale() {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();}Log.e(TAG, "deltaX = " + deltaX + " , deltaY = " + deltaY);mScaleMatrix.postTranslate(deltaX, deltaY);}/*** 根据当前图片的Matrix获得图片的范围* @return*/private RectF getMatrixRectF() {Matrix matrix = mScaleMatrix;RectF rect = new RectF();Drawable d = getDrawable();if (null != d) {rect.set(0, 0, d.getIntrinsicWidth(), d.getIntrinsicHeight());matrix.mapRect(rect);}return rect;}@Overridepublic boolean onScaleBegin(ScaleGestureDetector detector) {return true;}@Overridepublic void onScaleEnd(ScaleGestureDetector detector) {}/*** 我们让OnTouchListener的MotionEvent交给ScaleGestureDetector进行处理* public boolean onTouch(View v, MotionEvent event){* return mScaleGestureDetector.onTouchEvent(event);* }*/@Overridepublic boolean onTouch(View v, MotionEvent event) {if (mGestureDetector.onTouchEvent(event))return true;mScaleGestureDetector.onTouchEvent(event);float x = 0, y = 0;// 拿到触摸点的个数final int pointerCount = event.getPointerCount();// 得到多个触摸点的x与y均值for (int i = 0; i < pointerCount; i++) {x += event.getX(i);y += event.getY(i);}x = x / pointerCount;y = y / pointerCount;/*** 每当触摸点发生变化时,重置mLasX , mLastY*/if (pointerCount != lastPointerCount) {isCanDrag = false;mLastX = x;mLastY = y;}lastPointerCount = pointerCount;RectF rectF = getMatrixRectF();switch (event.getAction()) {case MotionEvent.ACTION_DOWN:if (rectF.width() > getWidth() || rectF.height() > getHeight()) {getParent().requestDisallowInterceptTouchEvent(true);}break;case MotionEvent.ACTION_MOVE:if (rectF.width() > getWidth() || rectF.height() > getHeight()) {getParent().requestDisallowInterceptTouchEvent(true);}Log.e(TAG, "ACTION_MOVE");float dx = x - mLastX;float dy = y - mLastY;if (!isCanDrag) {isCanDrag = isCanDrag(dx, dy);}if (isCanDrag) {if (getDrawable() != null) {// if (getMatrixRectF().left == 0 && dx > 0)// {// getParent().requestDisallowInterceptTouchEvent(false);// }//// if (getMatrixRectF().right == getWidth() && dx < 0)// {// getParent().requestDisallowInterceptTouchEvent(false);// }isCheckLeftAndRight = isCheckTopAndBottom = true;// 如果宽度小于屏幕宽度,则禁止左右移动if (rectF.width() < getWidth()) {dx = 0;isCheckLeftAndRight = false;}// 如果高度小雨屏幕高度,则禁止上下移动if (rectF.height() < getHeight()) {dy = 0;isCheckTopAndBottom = false;}//设置偏移量mScaleMatrix.postTranslate(dx, dy);//再次校验checkMatrixBounds();setImageMatrix(mScaleMatrix);}}mLastX = x;mLastY = y;break;case MotionEvent.ACTION_UP:case MotionEvent.ACTION_CANCEL:Log.e(TAG, "ACTION_UP");lastPointerCount = 0;break;}return true;}/*** 获得当前的缩放比例* @return*/public final float getScale() {mScaleMatrix.getValues(matrixValues);return matrixValues[Matrix.MSCALE_X];}@Overrideprotected void onAttachedToWindow() {super.onAttachedToWindow();getViewTreeObserver().addOnGlobalLayoutListener(this);}@SuppressWarnings("deprecation")@Overrideprotected void onDetachedFromWindow() {super.onDetachedFromWindow();getViewTreeObserver().removeGlobalOnLayoutListener(this);}/*** 根据图片的宽和高以及屏幕的宽和高,对图片进行缩放以及移动至屏幕的中心。* 如果图片很小,那就正常显示,不放大了~*/@Overridepublic void onGlobalLayout() {if (once) {Drawable d = getDrawable();if (d == null)return;Log.e(TAG, d.getIntrinsicWidth() + " , " + d.getIntrinsicHeight());int width = getWidth();int height = getHeight();// 拿到图片的宽和高int dw = d.getIntrinsicWidth();int dh = d.getIntrinsicHeight();float scale = 1.0f;// 如果图片的宽或者高大于屏幕,则缩放至屏幕的宽或者高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);}initScale = scale;Log.e(TAG, "initScale = " + initScale);mScaleMatrix.postTranslate((width - dw) / 2, (height - dh) / 2);mScaleMatrix.postScale(scale, scale, getWidth() / 2, getHeight() / 2);// 图片移动至屏幕中心setImageMatrix(mScaleMatrix);once = false;}}/*** 移动时,进行边界判断,主要判断宽或高大于屏幕的*/private void checkMatrixBounds() {RectF rect = getMatrixRectF();float deltaX = 0, deltaY = 0;final float viewWidth = getWidth();final float viewHeight = getHeight();// 判断移动或缩放后,图片显示是否超出屏幕边界if (rect.top > 0 && isCheckTopAndBottom) {deltaY = -rect.top;}if (rect.bottom < viewHeight && isCheckTopAndBottom) {deltaY = viewHeight - rect.bottom;}if (rect.left > 0 && isCheckLeftAndRight) {deltaX = -rect.left;}if (rect.right < viewWidth && isCheckLeftAndRight) {deltaX = viewWidth - rect.right;}mScaleMatrix.postTranslate(deltaX, deltaY);}/*** 是否是推动行为** @param dx* @param dy* @return*/private boolean isCanDrag(float dx, float dy) {return Math.sqrt((dx * dx) + (dy * dy)) >= mTouchSlop;}}

MainActivity.java

public class MainActivity extends AppCompatActivity {@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);}
}

activity_main.xml

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout 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"tools:context=".MainActivity"><com.turbosnail.android_app02.ZoomImageViewandroid:layout_width="300dp"android:layout_height="300dp"android:layout_centerInParent="true"android:src="@drawable/img_activity04_1"tools:ignore="MissingConstraints" /></RelativeLayout>

Android 手势放大图片相关推荐

  1. android 手势缩放图片框架

    //图片手势放大 第一个ImageViewTouch 只支持图片放大和缩小位置不会变动 compile 'it.sephiroth.android.library.imagezoom:imagezoo ...

  2. uni-app 手势放大图片

    手势缩放图片 <movable-area><movable-view direction="all" :scale="true" scale- ...

  3. android手势放大自动还原,ImageView通过matrix实现手势缩放,放大,缩小 ,移动

    转载自:http://www.jcodecraeer.com/a/anzhuokaifa/androidkaifa/2013/1023/1579.html 测试有效 关于ImageView的手势缩放, ...

  4. Android 高仿微信朋友圈动态, 支持双击手势放大并滑动查看图片。

    转载请注明出处: http://blog.csdn.net/sk719887916/article/details/40348873 作者skay: 最近参与了开发一款旅行APP,其中包含实时聊天和动 ...

  5. android+放大缩小图片+有jar嘛,Android相册支持点击放大图片,滑动切换图片,手势放大缩小...

    [实例简介] 项目使用了开源框架Universal-Image-Loader 显示本地图库所有照片 点击放大,单击退出 双击放大缩小 支持左右滑动查看图片 支持手势放大缩小图片 [实例截图] [核心代 ...

  6. android 手势事件 重写,Android实现通过手势控制图片大小缩放的方法

    本文实例讲述了Android实现通过手势控制图片大小缩放的方法.分享给大家供大家参考,具体如下: 该程序实现的是通过手势来缩放图片,从左向右挥动图片时图片被放大,从右向左挥动图片时图片被缩小,挥动速度 ...

  7. android 4.2 camera gallery2,Android Gallery2 修改双击、手势放大的最大倍数

    Gallery2,android原生的图库 图库中图片缩放有两种方式:1.双击放大,2.双指手势放大. 下面说一下修改这里的最大放大倍数. 例子是:修改放大倍数为3倍,照片放到最大后的伸缩范围0.5. ...

  8. Android 手势检测实战 打造支持缩放平移的图片预览效果(下)

    转载请标明出处:http://blog.csdn.net/lmj623565791/article/details/39480503,本文出自:[张鸿洋的博客] 上一篇已经带大家实现了自由的放大缩小图 ...

  9. android 手势放缩_手把手教你打造支持手势放大缩小的ImageView

    写在前面 最近有了新的任务,学习的时间比以前少了不少,Java回炉的文估计是得缓缓了,不过每周一篇尽量保质保量.最近感觉我文写的有点不好,因为我写东西除非必要,不然概念性的东西我基本上都是一笔带过-- ...

  10. android 手势放缩_Android应用中实现手势控制图片缩放的完全攻略

    一.概述现在app中,图片预览功能肯定是少不了的,用户基本已经形成条件反射,看到小图,点击看大图,看到大图两个手指开始进行放大,放大后,开始移动到指定部位~~~ 我相信看图的整个步骤,大家或者说用户应 ...

最新文章

  1. Python语言的有限状态机实现样例
  2. envi5.2中文版
  3. 剑指offer--剪绳子
  4. 基于javaweb(springboot+mybatis)网站建设服务管理系统设计和实现以及文档报告设计
  5. Jzzhu and Chocolate(CF-449A)
  6. js 加载图片无法加载成功,提示:net::ERR_BLOCKED_BY_CLIENT
  7. linux监控脚本是否运行状态,Linux Shell脚本之通过json判断应用程序内部运行状态...
  8. XReport报表工具技术白皮书
  9. Tomcat配置多个端口号或多个应用
  10. 使用ESXi-Customizer为esxi注入第三方驱动
  11. 小学生python趣味编程-小学生C++趣味编程 PDF 全资料版
  12. 基于Opencv实现车牌图片识别系统
  13. Ubuntu 18.04 究极美化教程
  14. 第五章 项目范围管理
  15. php泥浆护壁,扩孔泥浆护壁式集束式潜孔锤技术
  16. mysql opened tables_MySQL_MySQL性能优化之Open_Table配置参数的合理配置建议,在MySQL数据库中,Opened_tables表 - phpStudy...
  17. 简单解决Edge浏览器被sb360篡改的方法
  18. keras简单的实际入门教程
  19. DAP可视化组件升级开发说明
  20. 重启网卡提示Bringing up interface eth0

热门文章

  1. Android 服务
  2. 面向对象程序设计 作业一
  3. BZOJ-3226 校门外的区间 线段数+拆点(类似的思想)
  4. FATA[0000] (省略) Are you trying to connect to a TLS-enabled daemon without TLS?
  5. Codeforces Round #224 (Div. 2)
  6. HDOJ 2147 HDU 2147 kiki's game ACM 2147 IN HDU
  7. MTOM以及在WCF中的应用
  8. 句子表示学习前沿技术分享
  9. 【知识图谱】BERT meet KG 第二弹:新训练方式,新问题视角
  10. 我读研期间通过实习和比赛收入五十万