第三部分 应用

在这一部分,我们会将前面两部分所了解到的内容和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. HTML5 WebSocket 技术介绍

    WebSocket是html5规范新引入的功能,用于解决浏览器与后台服务器双向通讯的问题,使用WebSocket技术,后台可以随时向前端推送消息,以保证前后台状态统一,在传统的无状态HTTP协议中,这 ...

  2. 使用mx:Repeater在删除和添加item时列表闪烁

    使用mx:Repeater在删除和添加item时列表闪烁 不可能在用户界面上闪闪的吧,recycleChildren属性可帮助我们 recycleChildren属性==缓存,设为true就可以了 本 ...

  3. BZOJ 4034 【HAOI2015】 T2

    Description 有一棵点数为 N 的树,以点 1 为根,且树点有边权.然后有 M 个操作,分为三种: 操作 1 :把某个节点 x 的点权增加 a . 操作 2 :把某个节点 x 为根的子树中所 ...

  4. swift 集合类型(一)

    基本的数组结构Array: var shoppingList: String[] = ["Eggs", "Milk"] 这个shoppingList和传统意义上 ...

  5. Elasticsearch-2.3.x填坑之路

    使用版本说明:2.3.2 强制不能使用root用户启动?因为在2.x版本强调了安全性,防止attracker侵入root用户,所以建议使用者创建其他用户启动.当然,可以通过配置来实现root用户启动. ...

  6. Ztree 随笔记

    Ztree方法是一个单体对象方法,假如一个页面有多个的话,每申明一个新对象前面的Ztree对象就要被覆盖. 解决:在生成tree控件的时候就要设置其控件ID,然后通过$.fn.zTree.getZTr ...

  7. 数据库mark

    LOAD DATA INFILE 'I:\QQpwd\\1.txt' IGNORE INTO TABLE sgk.top1 FIELDS TERMINATED BY '----' OPTIONALLY ...

  8. PRML读书会第六章 Kernel Methods(核函数,线性回归的Dual Representations,高斯过程 ,Gaussian Processes)

    主讲人 网络上的尼采 (新浪微博:@Nietzsche_复杂网络机器学习) 网络上的尼采(813394698) 9:16:05 今天的主要内容:Kernel的基本知识,高斯过程.边思考边打字,有点慢, ...

  9. node 学习笔记 - path 处理

    本文同步自我的个人博客:http://www.52cik.com/2015/12/04/learn-node-path.html path 模块是 node 用于整理.转换.合并路径的神器,只要是路径 ...

  10. .NET基于Redis缓存实现单点登录SSO的解决方案

    一.基本概念 最近公司的多个业务系统要统一整合使用同一个登录,这就是我们耳熟能详的单点登录,现在就NET基于Redis缓存实现单点登录做一个简单的分享. 单点登录(Single Sign On),简称 ...