第三部分 应用

在这一部分,我们会将前面两部分所了解到的内容和Android手势结合起来,利用各种不同的手势对图像进行平移、缩放和旋转,前面两项都是在实践中经常需要用到的功能,后一项据说苹果也是最近才加上的,而实际上在Android中,咱们通过自己的双手,也可以很轻松地实现之。

首先创建一个Android项目PatImageView,同时创建一个Activity:PatImageViewActivity。完成这一步后, 记得在AndroidManifest.xml中增加如下许可:

<uses-permissionandroid:name="android.permission.VIBRATE"/>

因为我们将要通过短按还是长按,来确定将图片到底是缩放还是旋转。

现在来创建一个ImageView的派生类:PatImageView,其代码(PatImageView.java)如下(2011-11-22 revised):

  1. package com.pat.imageview;
  2. import android.app.Service;
  3. import android.content.Context;
  4. import android.graphics.Matrix;
  5. import android.graphics.PointF;
  6. import android.os.Vibrator;
  7. import android.util.FloatMath;
  8. import android.view.GestureDetector;
  9. import android.view.MotionEvent;
  10. import android.view.View;
  11. import android.widget.ImageView;
  12. public class PatImageView extends ImageView
  13. {
  14. private Matrix matrix;
  15. private Matrix savedMatrix;
  16. private boolean long_touch = false;
  17. private static int NONE = 0;
  18. private static int DRAG = 1;    // 拖动
  19. private static int ZOOM = 2;    // 缩放
  20. private static int ROTA = 3;    // 旋转
  21. private int mode = NONE;
  22. private PointF startPoint;
  23. private PointF middlePoint;
  24. private float oldDistance;
  25. private float oldAngle;
  26. private Vibrator vibrator;
  27. private GestureDetector gdetector;
  28. public PatImageView(final Context context)
  29. {
  30. super(context);
  31. matrix = new Matrix();
  32. savedMatrix = new Matrix();
  33. matrix.setTranslate(0f, 0f);
  34. setScaleType(ScaleType.MATRIX);
  35. setImageMatrix(matrix);
  36. startPoint = new PointF();
  37. middlePoint = new PointF();
  38. oldDistance = 1f;
  39. gdetector = new GestureDetector(context, new GestureDetector.OnGestureListener()
  40. {
  41. @Override
  42. public boolean onSingleTapUp(MotionEvent e)
  43. {
  44. return true;
  45. }
  46. @Override
  47. public void onShowPress(MotionEvent e)
  48. {
  49. }
  50. @Override
  51. public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY)
  52. {
  53. return true;
  54. }
  55. @Override
  56. public void onLongPress(MotionEvent e)
  57. {
  58. long_touch = true;
  59. vibrator = (Vibrator) context.getSystemService(Service.VIBRATOR_SERVICE);
  60. // 振动50ms,提示后续的操作将是旋转图片,而非缩放图片
  61. vibrator.vibrate(50);
  62. }
  63. @Override
  64. public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY)
  65. {
  66. return true;
  67. }
  68. @Override
  69. public boolean onDown(MotionEvent e)
  70. {
  71. return true;
  72. }
  73. });
  74. setOnTouchListener(new OnTouchListener()
  75. {
  76. public boolean onTouch(View view, MotionEvent event)
  77. {
  78. switch(event.getAction() & MotionEvent.ACTION_MASK)
  79. {
  80. case MotionEvent.ACTION_DOWN:           // 第一个手指touch
  81. savedMatrix.set(matrix);
  82. startPoint.set(event.getX(), event.getY());
  83. mode = DRAG;
  84. long_touch = false;
  85. break;
  86. case MotionEvent.ACTION_POINTER_DOWN:   // 第二个手指touch
  87. oldDistance = getDistance(event);   // 计算第二个手指touch时,两指之间的距离
  88. oldAngle = getDegree(event);        // 计算第二个手指touch时,两指所形成的直线和x轴的角度
  89. if(oldDistance > 10f)
  90. {
  91. savedMatrix.set(matrix);
  92. middlePoint = midPoint(event);
  93. if(!long_touch)
  94. {
  95. mode = ZOOM;
  96. }
  97. else
  98. {
  99. mode = ROTA;
  100. }
  101. }
  102. break;
  103. case MotionEvent.ACTION_UP:
  104. mode = NONE;
  105. break;
  106. case MotionEvent.ACTION_POINTER_UP:
  107. mode = NONE;
  108. break;
  109. case MotionEvent.ACTION_MOVE:
  110. if(vibrator != null)    vibrator.cancel();
  111. if(mode == DRAG)
  112. {
  113. matrix.set(savedMatrix);
  114. matrix.postTranslate(event.getX() - startPoint.x, event.getY() - startPoint.y);
  115. }
  116. if(mode == ZOOM)
  117. {
  118. float newDistance = getDistance(event);
  119. if(newDistance > 10f)
  120. {
  121. matrix.set(savedMatrix);
  122. float scale = newDistance / oldDistance;
  123. matrix.postScale(scale, scale, middlePoint.x, middlePoint.y);
  124. }
  125. }
  126. if(mode == ROTA)
  127. {
  128. float newAngle = getDegree(event);
  129. matrix.set(savedMatrix);
  130. float degrees = newAngle - oldAngle;
  131. matrix.postRotate(degrees, middlePoint.x, middlePoint.y);
  132. }
  133. break;
  134. }
  135. setImageMatrix(matrix);
  136. invalidate();
  137. gdetector.onTouchEvent(event);
  138. return true;
  139. }
  140. });
  141. }
  142. // 计算两个手指之间的距离
  143. private float getDistance(MotionEvent event)
  144. {
  145. float x = event.getX(0) - event.getX(1);
  146. float y = event.getY(0) - event.getY(1);
  147. return FloatMath.sqrt(x * x + y * y);
  148. }
  149. // 计算两个手指所形成的直线和x轴的角度
  150. private float getDegree(MotionEvent event)
  151. {
  152. return (float)(Math.atan((event.getY(1) - event.getY(0)) / (event.getX(1) - event.getX(0))) * 180f);
  153. }
  154. // 计算两个手指之间,中间点的坐标
  155. private PointF midPoint( MotionEvent event)
  156. {
  157. PointF point = new PointF();
  158. float x = event.getX(0) + event.getX(1);
  159. float y = event.getY(0) + event.getY(1);
  160. point.set(x / 2, y / 2);
  161. return point;
  162. }
  163. }

下面完善PatImageViewActivity.java的代码,使之如下:

  1. package com.pat.imageview;
  2. import android.app.Activity;
  3. import android.graphics.Bitmap;
  4. import android.graphics.BitmapFactory;
  5. import android.os.Bundle;
  6. import android.view.Window;
  7. import android.view.WindowManager;
  8. public class PatImageViewActivity extends Activity
  9. {
  10. @Override
  11. public void onCreate(Bundle savedInstanceState)
  12. {
  13. super.onCreate(savedInstanceState);
  14. requestWindowFeature(Window.FEATURE_NO_TITLE);
  15. this.getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,
  16. WindowManager.LayoutParams.FLAG_FULLSCREEN);
  17. PatImageView piv = new PatImageView(this);
  18. Bitmap bmp = BitmapFactory.decodeResource(getResources(), R.drawable.sophie);
  19. piv.setImageBitmap(bmp);
  20. setContentView(piv);
  21. }
  22. }

由于有些手势在模拟器上无法模拟,所以就不上运行结果的图片了。本人在真机上运行后(照片就不拍了,有点累啦),可以轻松做到:

1.     很方便地拖动图片(比如,单指按住屏幕进行拖动)

2.     很方便地缩放图片(比如,双指按住屏幕进行分开或者并拢操作,可分别实现放大或者缩小图片的功能)

3.     长按出现振动后,可以很方便地旋转图片(一个手指固定,另外一个手指围绕那个固定的手指运动)。

Android中图像变换Matrix的原理、代码验证和应用(三)的更多相关文章

  1. Android中图像变换Matrix的原理、代码验证和应用(一)

    第一部分 Matrix的数学原理 在Android中,如果你用Matrix进行过图像处理,那么一定知道Matrix这个类.Android中的Matrix是一个3 x 3的矩阵,其内容如下: Matri ...

  2. Android中图像变换Matrix的原理、代码验证和应用(二)

    第二部分 代码验证 在第一部分中讲到的各种图像变换的验证代码如下,一共列出了10种情况.如果要验证其中的某一种情况,只需将相应的代码反注释即可.试验中用到的图片: 其尺寸为162 x 251. 每种变 ...

  3. Android中的LruCache的原理和使用

    Android中的LruCache的原理和使用 LruCache,虽然很多文章都把LRU翻译成"最近最少使用"缓存策略,但Android中的LruCache真的如此吗? 答案是No ...

  4. Android中SensorManager.getRotationMatrix函数原理解释

    SensorManager是Android中的一个类,其有一个函数getRotationMatrix,可以计算出旋转矩阵,进而通过getOrientation求得设备的方向(航向角.俯仰角.横滚角). ...

  5. Android中的Matrix(矩阵)

    写在前面 看这篇笔记之前先看一下参考文章,这篇笔记没有系统的讲述矩阵和代码的东西,参考文章写的也有错误的地方,要辨证的看. 如何计算矩阵乘法 android matrix 最全方法详解与进阶(完整篇) ...

  6. Android 中View的工作原理

    Android中的View在Android的知识体系中扮演着重要的角色.简单来说,View就是Android在视觉的体现.我们所展现的页面就是Android提供的GUI库中控件的组合.但是当要求不能满 ...

  7. Android中微信抢红包插件原理解析和开发实现

    一.前言 自从去年中微信添加抢红包的功能,微信的电商之旅算是正式开始正式火爆起来.但是作为Android开发者来说,我们在抢红包的同时意识到了很多问题,就是手动去抢红包的速度慢了,当然这些有很多原因导 ...

  8. 【转】Android 学习笔记——利用JNI技术在Android中调用、调试C++代码

    原文网址:http://cherishlc.iteye.com/blog/1756762 在Android中调用C++其实就是在Java中调用C++代码,只是在windows下编译生成DLL,在And ...

  9. Android中典型的ROOT原理(5)

    ROOT的作用 Customization 用户的个人定制,如删除一些预安装,定制开机动画等. 特权操作 所有需要特权操作的基本都是要通过ROOT,这也是ROOT的初衷. ROOT的第一步:寻找漏洞并 ...

随机推荐

  1. tiny6410在I2c用户态中的程序设计eeprom

    在读写的过程中,发现写数据成功但是读取数据却失败,猜测是因为iic的读写操作过快,故在写操作后给一定的延迟,进而读写成功. 代码如下: #include <stdio.h>#include ...

  2. ThreadLocal用法和实现原理

    如果你定义了一个单实例的java bean,它有若干属性,但是有一个属性不是线程安全的,比如说HashMap.并且碰巧你并不需要在不同的线程中共享这个属性,也就是说这个属性不存在跨线程的意义.那么你不 ...

  3. jQuery $.each用法

    以下内容非原创,来自百度文库http://wenku.baidu.com/view/4796b6145f0e7cd18425368e.html 好文要顶 关注我 收藏该文   mabel_on_lin ...

  4. 学习cocos code ide 的lua编程

    装上了cocos code ide,配了路径之后,建立一个默认lua工程,发现无法调试,报错. 问了别人,在cocos2dconstants.lua的613行插入cc.AsyncTaskPool  = ...

  5. Java读写文本文件

    1 字符输入(FileReader , char) import java.io.IOException; import java.io.FileReader; public class ep10_1 ...

  6. ESXi 5.5 解决 cannot edit the settings of virtual machines of version 10

    ESXi 5.5 是VMWare提供的免费虚拟服务器软件, 因为其优秀的性能, 对CPU, 内存和虚拟机数量都解除了限制, 成为很多个人或者小型公司的首选虚拟化工具. 在日常管理时常碰到的一个问题是, ...

  7. Android — Camera聚焦流程

    原文  http://www.cnphp6.com/archives/65098 主题 Android Camera.java autoFocus()聚焦回调函数 @Override public v ...

  8. NOI2018准备Day3

    noip2016成绩出来了,199,268名 noip2017需要考过6个女生才能进省队,不包括明年会突然跳出来的大神...... 今天晚上玩了一晚上,做了2道题. 这事儿只干今晚一次

  9. 【福吧资源网整理】老男孩-python运维6期 不加密

    老男孩-python运维6期 不加密,连夜整理出来分享给大家老男孩的python教程确实不错. 教程目录: 下载地址:http://www.fu83.cn/thread-204-1-1.html  

  10. 机械大楼电梯控制项目软件 -- github团队组建

    目前在Github网站上建立了机械大楼电梯控制项目软件的软件仓库(Repository),提供了软件功能需求说明文档和Automation Studio程序模板.地址为 https://github. ...