自定义ZoomImageView实现到这里,基本上完成一大半了。在上一篇又给它添加了自由移动的功能。如果你没读过,可以点击下面的链接:
http://www.cnblogs.com/fuly550871915/p/4940103.html

在这篇文章中,就来实现双击放大或者缩小图片。用到的知识点就是GestureDetector,用它来监测双击事件。至于双击后怎么缩放图片,相信在前面几篇文章中,你都已经很熟悉了。但是难点是,我们要求双击后缓慢的放大或者缩小,而不是一下子就放大到或者缩小到目标值。这里就要结合线程来处理了。其实处理的逻辑也很简单:比如说放大,我们每隔一段时间,就对图片进行放大一次,然后看看是不是达到要求的放大比例了,如果达到了就终止,否则继续放大,直到达到要求为止。

好了,然后就来写代码吧,依旧是修改ZoomImageView,其中的代码如下:

  1 package com.example.view;
  2
  3 import android.annotation.SuppressLint;
  4 import android.content.Context;
  5 import android.graphics.Matrix;
  6 import android.graphics.RectF;
  7 import android.graphics.drawable.Drawable;
  8 import android.util.AttributeSet;
  9 import android.util.Log;
 10 import android.view.GestureDetector;
 11 import android.view.MotionEvent;
 12 import android.view.ScaleGestureDetector;
 13 import android.view.ScaleGestureDetector.OnScaleGestureListener;
 14 import android.view.View;
 15 import android.view.ViewConfiguration;
 16 import android.view.ViewTreeObserver.OnGlobalLayoutListener;
 17 import android.view.View.OnTouchListener;
 18 import android.widget.ImageView;
 19
 20 public class ZoomImageView extends ImageView implements OnGlobalLayoutListener,
 21 OnScaleGestureListener, OnTouchListener
 22 {
 23     private boolean mOnce = false;//是否执行了一次
 24
 25     /**
 26      * 初始缩放的比例
 27      */
 28     private float initScale;
 29     /**
 30      * 缩放比例
 31      */
 32     private float midScale;
 33     /**
 34      * 可放大的最大比例
 35      */
 36     private float maxScale;
 37     /**
 38      * 缩放矩阵
 39      */
 40     private Matrix scaleMatrix;
 41
 42     /**
 43      * 缩放的手势监控类
 44      */
 45     private ScaleGestureDetector mScaleGestureDetector;
 46
 47     //==========================下面是自由移动的成员变量======================================
 48     /**
 49      * 上一次移动的手指个数,也可以说是多点个数
 50      */
 51     private int mLastPoint;
 52     /**
 53      * 上次的中心点的x位置
 54      */
 55     private float mLastX;
 56     /**
 57      * 上一次中心点的y位置
 58      */
 59     private float mLastY;
 60     /**
 61      * 一个临界值,即是否触发移动的临界值
 62      */
 63     private int mScaleSlop;
 64     /**
 65      * 是否可移动
 66      */
 67     private boolean isCanDrag = false;
 68
 69     //===================下面是双击放大与缩小功能的成员变量===============70     71     /**72      * 监测各种手势事件,例如双击73      */74     private GestureDetector mGestureDetector;75     /**76      * 是否正在执行双击缩放77      */78     private boolean isAutoScale ;79
 80
 81
 82     public ZoomImageView(Context context)
 83     {
 84         this(context,null);
 85     }
 86     public ZoomImageView(Context context, AttributeSet attrs)
 87     {
 88         this(context, attrs,0);
 89
 90     }
 91     public ZoomImageView(Context context, AttributeSet attrs, int defStyle)
 92     {
 93         super(context, attrs, defStyle);
 94
 95         scaleMatrix = new Matrix();
 96
 97         setScaleType(ScaleType.MATRIX);
 98
 99         mScaleGestureDetector = new ScaleGestureDetector(context, this);
100         //触摸回调
101         setOnTouchListener(this);
102         //获得系统给定的触发移动效果的临界值
103         mScaleSlop = ViewConfiguration.get(context).getScaledTouchSlop();
104
105         mGestureDetector = new GestureDetector(context,new GestureDetector.SimpleOnGestureListener()
106         {
107             public boolean onDoubleTap(MotionEvent e)
108             {
109                 if(isAutoScale)//如果正在执行双击缩放,直接跳过
110                 {
111                     return true;
112                 }
113
114                 float x = e.getX();
115                 float y = e.getY();
116                 //获得当前的缩放比例
117                 float scale = getDrawableScale();
118
119                 if(scale<midScale)//如果比midScale小,一律放大,否则一律缩小为initScale
120                 {
121 //                    scaleMatrix.postScale(midScale/scale,midScale/scale, x, y);
122 //                    setImageMatrix(scaleMatrix);
123                     postDelayed(new AutoScaleRunnable(midScale, x, y), 16);
124
125                     isAutoScale = true;
126
127                 }else
128                 {
129 //                    scaleMatrix.postScale(initScale/scale,initScale/scale, x, y);
130 //                    setImageMatrix(scaleMatrix);
131                     postDelayed(new AutoScaleRunnable(initScale, x, y), 16);
132
133                     isAutoScale = true;
134                 }
135
136
137
138                 return true;
139
140             };
141         }
142         );
143     }
144     /**
145      *将 双击缩放使用梯度
146      * @author fuly1314
147      *
148      */
149     private class AutoScaleRunnable implements Runnable
150     {
151
152         private float targetScale;//缩放的目标值
153         private float x;
154         private float y;//缩放的中心点
155
156         private float tempScale;
157
158         private float BIGGER = 1.07F;
159         private float SMALL = 0.93F;//缩放的梯度
160
161         public AutoScaleRunnable(float targetScale, float x, float y) {
162             super();
163             this.targetScale = targetScale;
164             this.x = x;
165             this.y = y;
166
167             if(getDrawableScale()<targetScale)
168             {
169                 tempScale = BIGGER;
170             }
171             if(getDrawableScale()>targetScale)
172             {
173                 tempScale = SMALL;
174             }
175         }
176
177         public void run()
178         {
179
180             scaleMatrix.postScale(tempScale, tempScale, x, y);
181             checkBoderAndCenter();
182             setImageMatrix(scaleMatrix);
183
184             float scale = getDrawableScale();
185
186             if((scale<targetScale&&tempScale>1.0f)||(scale>targetScale&&tempScale<1.0f))
187             {
188                 postDelayed(this, 16);
189             }else
190             {
191                 scaleMatrix.postScale(targetScale/scale, targetScale/scale, x, y);
192                 checkBoderAndCenter();
193                 setImageMatrix(scaleMatrix);
194
195                 isAutoScale = false;
196             }
197
198         }
199
200     }
201
202
203     /**
204      * 该方法在view与window绑定时被调用,且只会被调用一次,其在view的onDraw方法之前调用
205      */
206     protected void onAttachedToWindow()
207     {
208         super.onAttachedToWindow();
209         //注册监听器
210         getViewTreeObserver().addOnGlobalLayoutListener(this);
211     }
212
213     /**
214      * 该方法在view被销毁时被调用
215      */
216     @SuppressLint("NewApi") protected void onDetachedFromWindow()
217     {
218         super.onDetachedFromWindow();
219         //取消监听器
220         getViewTreeObserver().removeOnGlobalLayoutListener(this);
221     }
222
223     /**
224      * 当一个view的布局加载完成或者布局发生改变时,OnGlobalLayoutListener会监听到,调用该方法
225      * 因此该方法可能会被多次调用,需要在合适的地方注册和取消监听器
226      */
227     public void onGlobalLayout()
228     {
229         if(!mOnce)
230         {
231             //获得当前view的Drawable
232             Drawable d = getDrawable();
233
234             if(d == null)
235             {
236                 return;
237             }
238
239             //获得Drawable的宽和高
240             int dw = d.getIntrinsicWidth();
241             int dh = d.getIntrinsicHeight();
242
243             //获取当前view的宽和高
244             int width = getWidth();
245             int height = getHeight();
246
247             //缩放的比例,scale可能是缩小的比例也可能是放大的比例,看它的值是大于1还是小于1
248             float scale = 1.0f;
249
250             //如果仅仅是图片宽度比view宽度大,则应该将图片按宽度缩小
251             if(dw>width&&dh<height)
252             {
253                 scale = width*1.0f/dw;
254             }
255             //如果图片和高度都比view的大,则应该按最小的比例缩小图片
256             if(dw>width&&dh>height)
257             {
258                 scale = Math.min(width*1.0f/dw, height*1.0f/dh);
259             }
260             //如果图片宽度和高度都比view的要小,则应该按最小的比例放大图片
261             if(dw<width&&dh<height)
262             {
263                 scale = Math.min(width*1.0f/dw, height*1.0f/dh);
264             }
265             //如果仅仅是高度比view的大,则按照高度缩小图片即可
266             if(dw<width&&dh>height)
267             {
268                 scale = height*1.0f/dh;
269             }
270
271             //初始化缩放的比例
272             initScale = scale;
273             midScale = initScale*2;
274             maxScale = initScale*4;
275
276             //移动图片到达view的中心
277             int dx = width/2 - dw/2;
278             int dy = height/2 - dh/2;
279             scaleMatrix.postTranslate(dx, dy);
280
281             //缩放图片
282             scaleMatrix.postScale(initScale, initScale, width/2, height/2);
283
284             setImageMatrix(scaleMatrix);
285             mOnce = true;
286         }
287
288     }
289     /**
290      * 获取当前已经缩放的比例
291      * @return  因为x方向和y方向比例相同,所以只返回x方向的缩放比例即可
292      */
293     private float getDrawableScale()
294     {
295
296         float[] values = new float[9];
297         scaleMatrix.getValues(values);
298
299         return values[Matrix.MSCALE_X];
300
301     }
302
303     /**
304      * 缩放手势进行时调用该方法
305      *
306      * 缩放范围:initScale~maxScale
307      */
308     public boolean onScale(ScaleGestureDetector detector)
309     {
310
311         if(getDrawable() == null)
312         {
313             return true;//如果没有图片,下面的代码没有必要运行
314         }
315
316         float scale = getDrawableScale();
317         //获取当前缩放因子
318         float scaleFactor = detector.getScaleFactor();
319
320         if((scale<maxScale&&scaleFactor>1.0f)||(scale>initScale&&scaleFactor<1.0f))
321         {
322             //如果缩小的范围比允许的最小范围还要小,就重置缩放因子为当前的状态的因子
323             if(scale*scaleFactor<initScale)
324             {
325                 scaleFactor = initScale/scale;
326             }
327             //如果缩小的范围比允许的最小范围还要小,就重置缩放因子为当前的状态的因子
328             if(scale*scaleFactor>maxScale)
329             {
330                 scaleFactor = maxScale/scale;
331             }
332
333 //            scaleMatrix.postScale(scaleFactor, scaleFactor, getWidth()/2, getHeight()/2);
334             scaleMatrix.postScale(scaleFactor, scaleFactor,detector.getFocusX(),
335                     detector.getFocusY());
336
337             checkBoderAndCenter();//处理缩放后图片边界与屏幕有间隙或者不居中的问题
338
339
340             setImageMatrix(scaleMatrix);//千万不要忘记设置这个,我总是忘记
341         }
342
343
344
345         return true;
346     }
347     /**
348      * 处理缩放后图片边界与屏幕有间隙或者不居中的问题
349      */
350     private void checkBoderAndCenter()
351     {
352        RectF rectf = getDrawableRectF();
353
354        int width = getWidth();
355        int height = getHeight();
356
357        float delaX =0;
358        float delaY = 0;
359
360        if(rectf.width()>=width)
361        {
362            if(rectf.left>0)
363            {
364              delaX = - rectf.left;
365            }
366
367            if(rectf.right<width)
368            {
369                delaX = width - rectf.right;
370            }
371        }
372
373        if(rectf.height()>=height)
374        {
375            if(rectf.top>0)
376            {
377                delaY = -rectf.top;
378            }
379            if(rectf.bottom<height)
380            {
381                delaY = height - rectf.bottom;
382            }
383        }
384
385        if(rectf.width()<width)
386        {
387            delaX = width/2 - rectf.right+ rectf.width()/2;
388        }
389
390        if(rectf.height()<height)
391        {
392            delaY =  height/2 - rectf.bottom+ rectf.height()/2;
393        }
394
395        scaleMatrix.postTranslate(delaX, delaY);
396     }
397     /**
398      * 获取图片根据矩阵变换后的四个角的坐标,即left,top,right,bottom
399      * @return
400      */
401     private RectF getDrawableRectF()
402     {
403         Matrix matrix = scaleMatrix;
404         RectF rectf = new RectF();
405         Drawable d = getDrawable();
406         if(d != null)
407         {
408
409             rectf.set(0, 0, d.getIntrinsicWidth(), d.getIntrinsicHeight());
410         }
411
412         matrix.mapRect(rectf);
413         return  rectf;
414     }
415     /**
416      * 缩放手势开始时调用该方法
417      */
418     public boolean onScaleBegin(ScaleGestureDetector detector)
419     {
420         //返回为true,则缩放手势事件往下进行,否则到此为止,即不会执行onScale和onScaleEnd方法
421         return true;
422     }
423     /**
424      * 缩放手势完成后调用该方法
425      */
426     public void onScaleEnd(ScaleGestureDetector detector)
427     {
428
429
430     }
431
432     /**
433      * 监听触摸事件
434      */
435     public boolean onTouch(View v, MotionEvent event)
436     {
437
438         if(mGestureDetector.onTouchEvent(event))
439         {
440             return true;
441         }
442
443         if(mScaleGestureDetector != null)
444         {
445             //将触摸事件传递给手势缩放这个类
446             mScaleGestureDetector.onTouchEvent(event);
447         }
448
449
450         //获得多点个数,也叫屏幕上手指的个数
451         int pointCount = event.getPointerCount();
452
453         float x =0;
454         float y =0;//中心点的x和y
455
456         for(int i=0;i<pointCount;i++)
457         {
458             x+=event.getX(i);
459             y+=event.getY(i);
460         }
461
462         //求出中心点的位置
463         x/= pointCount;
464         y/= pointCount;
465
466         //如果手指的数量发生了改变,则不移动
467         if(mLastPoint != pointCount)
468         {
469             isCanDrag = false;
470             mLastX = x;
471             mLastY = y;
472
473         }
474         mLastPoint = pointCount;
475
476
477         switch(event.getAction())
478         {
479         case MotionEvent.ACTION_MOVE:
480
481             //求出移动的距离
482             float dx = x - mLastX;
483             float dy = y- mLastY;
484
485             if(!isCanDrag)
486             {
487                 isCanDrag = isCanDrag(dx,dy);
488             }
489
490             if(isCanDrag)
491             {
492                 //如果图片能正常显示,就不需要移动了
493                 RectF rectf = getDrawableRectF();
494                 if(rectf.width()<=getWidth())
495                 {
496                     dx = 0;
497                 }
498                 if(rectf.height()<=getHeight())
499                 {
500                     dy = 0;
501                 }
502
503
504                 //开始移动
505                 scaleMatrix.postTranslate(dx, dy);
506                 //处理移动后图片边界与屏幕有间隙或者不居中的问题
507                 checkBoderAndCenterWhenMove();
508                 setImageMatrix(scaleMatrix);
509             }
510
511             mLastX = x;
512             mLastY = y;
513
514
515             break;
516         case MotionEvent.ACTION_UP:
517         case MotionEvent.ACTION_CANCEL:
518                     mLastPoint = 0;
519             break;
520
521         }
522
523         return true;
524     }
525     /**
526      * 处理移动后图片边界与屏幕有间隙或者不居中的问题
527      * 这跟我们前面写的代码很像
528      */
529     private void checkBoderAndCenterWhenMove() {
530
531         RectF rectf = getDrawableRectF();
532
533         float delaX = 0;
534         float delaY = 0;
535         int width = getWidth();
536         int height = getHeight();
537
538         if(rectf.width()>width&&rectf.left>0)
539         {
540             delaX = - rectf.left;
541         }
542         if(rectf.width()>width&&rectf.right<width)
543         {
544             delaX = width - rectf.right;
545         }
546         if(rectf.height()>height&&rectf.top>0)
547         {
548             delaY = - rectf.top;
549         }
550         if(rectf.height()>height&&rectf.bottom<height)
551         {
552             delaY = height - rectf.bottom;
553         }
554
555         scaleMatrix.postTranslate(delaX, delaY);
556     }
557     /**
558      * 判断是否触发移动效果
559      * @param dx
560      * @param dy
561      * @return
562      */
563     private boolean isCanDrag(float dx, float dy) {
564
565         return Math.sqrt(dx*dx+dy*dy)>mScaleSlop;
566     }
567
568
569
570
571 }

红色部分是新加的代码。在第438行,首先要将触摸事件传递给mGestureDetector。然后在第105行开始监听双击事件。因为双击后将缩放比例直接设置给图片,那么图片会猛然放大,不是很好的用户体验。因此在这里,采用了post一个Runnable方式,不断的去调整缩放比例,直到达到要求为止。具体的逻辑代码中很详细了,仔细看看。大体逻辑很简单。注意在这里,我们将双击的缩放临界点设置为midScale,即如果当前缩放比例比它小,那么久放大到midScale,否则就缩小到initScale。

然后运行下程序,效果如下:

实现的效果还不错吧。截止到目前,自定义的ZoomImageView已经实现了自由缩放,自由移动以及双击放大和缩小。功能齐全,可以使用了。在一篇文章中,将用它和ViewPager结合使用:《(五)多点触控兼容ViewPager》

转载于:https://www.cnblogs.com/fuly550871915/p/4940193.html

(四)双击放大与缩小图片相关推荐

  1. Android自定义ImageView(二)——实现双击放大与缩小图片

    效果图: 首先设置图片依据控件的大小来显示在ImageVeiw中 也就是当图片的宽与高小于控件的宽与高的时候,默认不进行对图片进行放大的操作,但是会将图片居中显示,当然使用的时候可以使用自定义的属性i ...

  2. 计算机画图工具怎么缩小图片,Win10如何放大或缩小图片?利用win10画图工具放大、缩小图片教程...

    在日常使用电脑过程中,我们经常会碰到需要放大或缩小照片(图片)的情况.那么,win10系统下该如何扩大或者缩小照片(图片)呢?其实,我们可以通过使用win10系统自带的画图工具来实现.下面小编就向大家 ...

  3. 如何快速在线压缩图片大小(包括放大、缩小图片,指定图片尺寸和压缩图片品质)

    在日常的学习和工作中,我们经常会遇到压缩和修改图片大小的问题,如果我们不是专业的设计人员,一般电脑上不会安装ps软件,那么我们如何通过网页,在线快速简单的来完成操作呢?下面小编和大家一块分享下具体如何 ...

  4. php 如何缩小一张图片,放大和缩小图片的技巧_PHP

    获得一幅原始的图片后,感觉尺寸不符合要求,这时就要想办法把图片放大或缩小了.当然你也可以用photoshop之类的软件来达到自己的要求,但是如果要经常做这种事情,就显的太繁琐了,所以还是编一个程序来的 ...

  5. html 页面缩放事件,使用HTML5实现通过鼠标滚轮事件放大和缩小图片的功能

    您和我都知道,向HTML5网页添加鼠标滚轮事件可以更好地允许用户与网页进行交互. 在HTML5中,鼠标滚轮不仅可以在网页上上下滑动,实际上,您还可以依靠它来完成更,例如放大和缩小视图平面. 看看实际的 ...

  6. android imageview点击图片放大缩小,Android实现ImageView图片双击放大及缩小

    病人肝癌肿瘤治疗前9.0*8.8cm,通过一疗程服药治疗缩小到8.0*7.3cm. 肝肿瘤9.0*8.8cm 肝肿瘤缩小到8.0*7.3cm 河南偃师任某某乙肝癌肿瘤治疗前6.7*9.3cm,通过一疗 ...

  7. C# 结合Halcon软件视觉窗体滚轮放大/双击放大/滚轮缩小/双击缩小/移动/自适应功能

    //窗体所需参数 private HTuple mouseDowmRowLT1, mouseDownColLT1, mouseDownRowLT2, mouseDownColLT2; private ...

  8. ios 根据手势放大或缩小图片

    1.在.h文件中加入一个变量用来记录当前的scale值, 让这个ViewController遵循 UIGestureRecognizerDelegate代理. 并在.h中加入下面这个变量 CGFloa ...

  9. css渲染图片时放大或缩小图片变模糊处理方式

    img{image-rendering -moz-crisp-edgesimage-rendering -o-crisp-edgesimage-rendering -webkit-optimize-c ...

最新文章

  1. 对异步脉冲信号的处理——不归0翻转电路
  2. 初识压缩感知 compressive sensing
  3. linux php安装memcached扩展
  4. 剑指offer之56-60题解
  5. 如何下载python2.7.16_CENTOS6.5 安装PYTHON2.7.16
  6. FTP相关命令(手机FTP服务启动应用)
  7. 用python画皮卡丘-实现童年宝可梦,教你用Python画一只属于自己的皮卡丘
  8. 支付宝弄了个“双12 ” 岛国民众都high了
  9. (转)2017 年最流行的 15 个数据科学 Python 库
  10. linux VIM 命令详解
  11. linux(Ubuntu)系统解决校园网锐捷客户端联网问题
  12. 【软件工程】——软件需求说明书
  13. 华为手机如何换成鸿蒙,如何将自己的华为手机升级成鸿蒙系统
  14. rpm -ivh安装mysql_rpm的用法 详解
  15. navicat 连接oracle的配置
  16. 用Python爬取英雄联盟(lol)全部皮肤
  17. 幼麟棋牌登录socket服务器分析
  18. 微信小程序开发——设置默认图片、错误加载图片
  19. IPU VPU GPU
  20. 【图书】前端工程化:体系设计与实践

热门文章

  1. 并发编程-初级之认识并发编程
  2. java 获取区间随机数_Java获取随机数
  3. 集成学习(含常用案列)
  4. 牛客巅峰训练赛S2钻石王者——补题
  5. lodop设置html字体大小无效,LODOP设置纸张无效问题
  6. 当年明月、袁腾飞、阎崇年三人的专业水平的比较以及由此想到的一些学习方法、品书原则
  7. MATLAB 2020a的参考安装教程
  8. HTML5基础:布局和标签
  9. FXS,FXO,EM区别
  10. 全国省份地区相关常量备忘