上一章,我们学习了手势 GestureDecetor 的基本使用 Android 手势学习 GestureDetector,这一次,我们来学习使用 ScaleGestureDetector 来实现一个图片缩放的效果,如下:

文章参考鸿洋大大的图片缩放


代码 ScaleImageview

使用

allprojects {repositories {...maven { url 'https://jitpack.io' }}
}

然后在你的 module 中添加:

 implementation 'com.github.LillteZheng:ScaleImageview:1.0'

然后添加控件即可:

<com.zhengsr.mylibrary.ScaleImageViewandroid:layout_width="match_parent"android:layout_height="200dp"android:layout_margin="10dp"app:scale_limit_board="false"app:scale_max_factor="5"app:scale_auto_time="5"app:scale_double_factor="2"android:src="@mipmap/a1"/>

一、分析:

  1. 通过 ScaleGestureDetector 拿到缩放中心和缩放因子
  2. 通过 matrix 进行图片的缩放和平移
  3. 双击进行放大和缩小
  4. 结合 GestureDetector 进行平移
  5. 使用 getParent().requestDisallowInterceptTouchEvent(true); 进行事件发发截取

二、讲解

2.1 平移与缩放

首先,当加载一张图片的时候,并不清楚图片的大小,如果想要它居中且全部显示出来,则需要通过平移和缩放的形式,这里可以通过 Imageview 的 scaleTyle 设置成 matrix 的形式;比如,在初始化中:

setScaleType(ScaleType.MATRIX);

这样,则保证了图片的缩放模式是以 matrix 的。假设需要加载的图片比较小,在左上角,这时,需要移动到屏幕中心,如下图:

此时,需要将它先移动到屏幕中心,只需要屏幕的中心点减去图片的中心点坐标即可,dw 和dh 为图片的宽高:

mMatrix = new Matrix();
float dx = width * 1.0f / 2 - dw * 1.0f / 2;
float dy = height * 1.0f / 2 - dh * 1.0f / 2;
mMatrix.postTranslate(dx,dy);

接着进行比例缩放,目前来说,有两种方式,假如整个屏幕只填放一张图片,那么,缩放只需要保证宽或者高一个比例缩放即可,只要保证了其中一个,以适配最小宽高来,那么另一个宽或者高也能适配,如下:

//控件宽高都比图片大,即放大了多少倍,拿到宽高的最小放大比例if (width > dw && height > dh){scale = Math.min((width * 1.0f / dw),(height * 1.0f / dh));}//图片宽高比控件大,即缩小了多少倍,,拿到宽高的最大放小比例if (dw > width && dh > height){scale = Math.max((width * 1.0f / dw),(height * 1.0f / dh));}//图片高比控件的高大,即应该缩放多少if (dw < width && dh > height){scale =  height * 1.0f / dh;}//图片宽比控件的宽大,即应该缩放多少if (dw > width && dh < height){scale = width * 1.0f / dw;}

这样拿到缩放比例后,直接用 matrix 即可:

mMatrix.postScale(scale,scale,width * 1.0f / 2, height * 1.0f / 2);

但如果你想效果图中,指定了宽高呢?这样如果只缩放其中一个宽或高,则另一个,就有可能存在不能完全适配的问题,所以,需要拿到宽和高的缩放比例,如:

scale = width * 1.0f / dw;
scaley = height * 1.0f / dh;

然后调用 matrix:

mMatrix.postScale(scale, scaley, width * 1.0f / 2, height * 1.0f / 2);

接着调用 imageview 自带的方法,即可完成移动中心点和缩放问题:

setImageMatrix(mMatrix);

可以使用

 app:scale_autofit="true"

来使用哪种比例,一个随便指定高度为200dp 的张方形图片不同效果如下:



所以,如果你是指定高度,且图片是长方形的,建议 scale_autofit true,如果是 match_parent 且正方形的则 false 即可。

2.2 使用 ScaleGestureDetector 进行缩放

在进行平移缩放之后,可以使用 ScaleGestureDetector 进行缩放即可,它的三个方法如下:

    @Overridepublic boolean onScale(ScaleGestureDetector detector) {//拿到缩放比例float scale = getScale();float scaleFactor = detector.getScaleFactor();//拿到缩放中心float focusX = detector.getFocusX();float focusY = detector.getFocusY();return true;}@Overridepublic boolean onScaleBegin(ScaleGestureDetector detector) {return true;}@Overridepublic void onScaleEnd(ScaleGestureDetector detector) {}

需要注意的是 onScaleBegin return true,这样事件才能继续传递下去。接着在 onScale 拿到缩放比例中心和当前的缩放比例因子;整体代码如下:

 //拿到缩放比例float scale = getScale();float scaleFactor = detector.getScaleFactor();//拿到缩放中心float focusX = detector.getFocusX();float focusY = detector.getFocusY();//默认不能缩放至屏幕控件大小if (mIsLimitBroad) {//重新复制,让它逼近于最小值if (scale * scaleFactor < mDeflautScale) {scaleFactor = mDeflautScale / scale;}if (scale * scaleFactor > mMaxScale) {scaleFactor = mMaxScale / scale;}}mMatrix.postScale(scaleFactor,scaleFactor,focusX,focusY);checkBroad();setImageMatrix(mMatrix);

mIsLimitBroad 即 app:scale_limit_board 表示是否缩放能否能小于控件,如果为 true,则表示不能缩小到控件大小,可以通过比例换算去是实现,如果 scale * scaleFactor < mDeflautScale ,则让 scaleFactor = mDeflautScale / scale 即可。
其中 getScale()方法表示拿到当前的缩放比例:

 /*** 拿到缩放比例,默认拿到 x 即可* @return*/private float getScale(){float[] floats = new float[9];mMatrix.getValues(floats);return floats[Matrix.MSCALE_X];}

checkBroad() 则是,在缩放时,如果不对中心点进行校正,不对图片进行平移校正,则会出现缩小时,图片跑到屏幕外侧或者中心点不对的问题,如下图这样:

所以,需要修正一下:

/*** 检查边界,让它不能有空白和让它一直保在屏幕中心*/private void checkBroad() {RectF rectF = getMatrixRectF();float dx = 0;float dy = 0;//检测边界,不能让它留空白if (rectF.width() >= getWidth()) {if (rectF.right < getWidth()) {dx = getWidth() - rectF.right;}if (rectF.left > 0) {dx = -rectF.left;}}else {//保证在屏幕中心dx = getWidth() * 1.0f /2 - rectF.right + rectF.width() * 1.0f / 2;}//检测边界,不能让它留空白if (rectF.height() >= getHeight()){if (rectF.top > 0){dy = -rectF.top;}if (rectF.bottom < getHeight()){dy = getHeight() - rectF.bottom;}}else{//保证在屏幕中心dy = getHeight() * 1.0f /2 - rectF.bottom + rectF.height() * 1.0f / 2;}mMatrix.postTranslate(dx,dy);}

getMatrixRectF() 为拿到当前缩放后的图片大小:

    /*** 拿到缩放后的图片大小* @return*/private RectF getMatrixRectF(){Matrix matrix = new 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;}

2.3 移动放大的图片

图片移动,在 onTouchEvent 中进行处理,需要考虑的是,当用两个手指拖动,然后其中一个手指抬起,此时中心点是有变动的,这时需要改变中心点的坐标,不然会出现一下子跳动的现象,具体代码如下:

 //防止多指变动,中心点改变,而出现拖动问题int pointerCount = event.getPointerCount();float x = 0;float y = 0;for (int i = 0; i < pointerCount; i++) {x += event.getX(i);y += event.getY(i);}x = x / pointerCount;y = y / pointerCount;if (mLastPointCount != pointerCount){mLastx = x;mLasty = y;}//记录上一次的手指个数mLastPointCount = pointerCount;switch (event.getActionMasked()){case MotionEvent.ACTION_MOVE:requestFocusViewpager();float dx = x - mLastx;float dy = y - mLasty;mMatrix.postTranslate(dx,dy);checkBroad();setImageMatrix(mMatrix);mLastx = x;mLasty = y;break;case MotionEvent.ACTION_UP:mLastPointCount = 0;break;default:break;}

三、双击放大

双击的方法,我们也可以通过 GestureDetector 手势这个类拿到双击的方法:

    /*** 指监听 双击的方法*/class SimpleGesture extends GestureDetector.SimpleOnGestureListener{@Overridepublic boolean onDoubleTap(MotionEvent e) {float x = e.getX();float y = e.getY();if (isCanDoubleScale) {//放大if (getScale() < mDoubleScale) {post(new AutoScale(mDoubleScale, x, y));} else { //缩放到自身大小post(new AutoScale(mDeflautScale, x, y));}}return true;}}

而AutoScale就是表示 缩放的类:

    /*** 双击缩放比例*/class AutoScale implements Runnable {private final float LARGE = 1.07f;private final float SMALL = 0.93f;float targetScale;float x;float y;float tempScale;public AutoScale(float targetScale,float x, float y) {this.targetScale = targetScale;this.x = x;this.y = y;isCanDoubleScale = false;//放大if (targetScale > getScale()){tempScale = LARGE;}else{tempScale = SMALL;}}@Overridepublic void run() {mMatrix.postScale(tempScale, tempScale , x, y);checkBroad();setImageMatrix(mMatrix);float currentScale = getScale();boolean isCanLarge = currentScale < targetScale && tempScale > 1.0f;boolean isCanSmall = currentScale > targetScale && tempScale < 1.0f;if (isCanLarge || isCanSmall) {//若还未到达缩放的目标值,则继续缩放postDelayed(this, mDoubleAutoTime);}else{//达到表示了,但可能有偏差,还需要调整一下mMatrix.postScale(targetScale/currentScale, targetScale/currentScale , x, y);checkBroad();setImageMatrix(mMatrix);isCanDoubleScale = true;}}}

这样,关键知识点就讲解完了,自定义属性如下:

缩放控件 ScaleImageView

名称 类型 说明
scale_auto_time reference,integer 双击时,达到放大的时间
scale_limit_board boolean 是否限制边界,即不能缩放到比控件小
scale_autofit boolean 自动适配缩放值,有些图片是正方形,如果你的高度没设定好,建议设置为false,不能会变形
scale_double_factor integer 双击时放大倍数
scale_max_factor integer 可放大的最大倍数
scale_interrupt_parent_touch boolean 是否截获父控件触摸事件,放大时,需要截取,不然无法移动

Android 多点触控与图片缩放相关推荐

  1. android 多点触控缩放,Android多点触控(图片的缩放Demo)

    本文主要介绍Android的多点触控,使用了一个图片缩放的实例,来更好的说明其原理.需要实现OnTouchListener接口,重写其中的onTouch方法. 实现效果图: 源代码: 布局文件: ac ...

  2. android多点触控,图片的拖拽与放大缩小

    //直接复制粘贴就可以使用 public class MainActivity extends AppCompatActivity {private ImageView MyImageView;pri ...

  3. Android多点触控详解

    本文转载自GcsSloop的 安卓自定义View进阶-多点触控详解 的文章 Android 多点触控详解,在前面的几篇文章中我们大致了解了 Android 中的事件处理流程和一些简单的处理方案,本次带 ...

  4. Android多点触控揭秘

    本文原创,转载请注明:http://blog.csdn.net/cloudzfy1/article/details/6582707 Google 暑期大学生博客分享大赛 - 2011 Android ...

  5. Android多点触控技术

    1 简介 Android多点触控在本质上需要LCD驱动和程序本身设计上支持,目前市面上HTC.Motorola和Samsung等知名厂商只要使用电容屏触控原理的手机均可以支持多点触控Multitouc ...

  6. Android 多点触控消息捕获与处理

    1 简介 Android多点触控在本质上需要LCD驱动和程序本身设计上支持,目前市面上HTC.Motorola和Samsung等知名厂商只要使用电容屏触控原理的手机均可以支持多点触控Multitouc ...

  7. 模拟Android多点触控

    Android多点触控 Android多点触控 多点触控实现思路 第一种adb shell input方式 第二种adb shell sendevent方式 多点触控实现思路   经过资料的查询,要在 ...

  8. Android 多点触控(放大、缩小、旋转、位移)

    通过多点触控实现图片的放大.缩小.旋转.位移效果. private float oldX1 = 0;private float oldX2 = 0;private float oldY1 = 0;pr ...

  9. Android自定义控件ImageViwe(四)——多点触控实现图片的自由移动

    效果图: 功能 : 可以随手指进行自由移动图片 按照适当的比例设置图片的显示 首先将图片按照适当的比例显示在自定义控件中(当图片的宽度或者高度大于控件的宽度或者高度的时候,会对图片进行适当的缩放,当图 ...

最新文章

  1. ARM QT实现多点触摸【转】
  2. dso_loader.cc:55] Could not load dynamic library ‘cudart64_100.dll‘
  3. 安装pr_PR 一键转场插件 安装教程
  4. Leetcode题库 6.Z字形变换(C实现)
  5. Shell-8--数值运算及处理
  6. [骗分技巧——随机化Ⅱ] [Poi2014]Couriers,CodeChef - TKCONVEX
  7. 巧用windows xp远程桌面web连接
  8. python制作点亮图片_MicroPython拼插编程实例:点亮心形8x8点阵
  9. tablesorter,jquery
  10. php 安装mysql扩展注意事项
  11. mysql binlog 日志
  12. JUC锁框架——ReadWriteLock
  13. 注册表清理工具PC Performer
  14. plsql developer 64位oracle,手把手教你Plsql developer连接64位Oracle
  15. linux通过ip查询域名,无法通过ip地址查找对应的域名
  16. HTML和css页眉制作,静态网页制作(Dreamweaver) 设计和制作网站首页 0203-静态网页制作(Dreamweaver)-设计制作网站首页页眉、导航栏.doc...
  17. Eclipse,STS系列IDE 启动阻塞,启动一直加载问题
  18. Unity通过鼠标或者手势实现拉进拉远,旋转等操作的常用方法
  19. 囚徒健身(中文完整版)(保罗·威德)
  20. linux memwatch的内存检测-double-free

热门文章

  1. 边缘计算导论——中山大学程旭老师课程总结
  2. VUE对数组进行深度监听无法改变值解决办法(全网最详细)
  3. FMC高速NVME存储子卡
  4. 【sdp】抓包查看RTP头扩展id
  5. centos8安装python3.6_CentOS安装python3.6
  6. 校园点餐系统:点餐、食堂管理、商户管理和菜品管理(Java和MySQL)
  7. 【7 查找】二叉排序树查找关键字。
  8. 红蓝对抗之常见网络安全事件研判、了解网络安全设备、Webshell入侵检测
  9. 功能测试和自动化测试的优缺点
  10. Win7双网卡共享上网