Android中图像变换Matrix的原理、代码验证和应用(三)
第三部分 应用
在这一部分,我们会将前面两部分所了解到的内容和Android手势结合起来,利用各种不同的手势对图像进行平移、缩放和旋转,前面两项都是在实践中经常需要用到的功能,后一项据说苹果也是最近才加上的,而实际上在Android中,咱们通过自己的双手,也可以很轻松地实现之。
首先创建一个Android项目PatImageView,同时创建一个Activity:PatImageViewActivity。完成这一步后, 记得在AndroidManifest.xml中增加如下许可:
<uses-permissionandroid:name="android.permission.VIBRATE"/>
因为我们将要通过短按还是长按,来确定将图片到底是缩放还是旋转。
现在来创建一个ImageView的派生类:PatImageView,其代码(PatImageView.java)如下(2011-11-22 revised):
- package com.pat.imageview;
- import android.app.Service;
- import android.content.Context;
- import android.graphics.Matrix;
- import android.graphics.PointF;
- import android.os.Vibrator;
- import android.util.FloatMath;
- import android.view.GestureDetector;
- import android.view.MotionEvent;
- import android.view.View;
- import android.widget.ImageView;
- public class PatImageView extends ImageView
- {
- private Matrix matrix;
- private Matrix savedMatrix;
- private boolean long_touch = false;
- private static int NONE = 0;
- private static int DRAG = 1; // 拖动
- private static int ZOOM = 2; // 缩放
- private static int ROTA = 3; // 旋转
- private int mode = NONE;
- private PointF startPoint;
- private PointF middlePoint;
- private float oldDistance;
- private float oldAngle;
- private Vibrator vibrator;
- private GestureDetector gdetector;
- public PatImageView(final Context context)
- {
- super(context);
- matrix = new Matrix();
- savedMatrix = new Matrix();
- matrix.setTranslate(0f, 0f);
- setScaleType(ScaleType.MATRIX);
- setImageMatrix(matrix);
- startPoint = new PointF();
- middlePoint = new PointF();
- oldDistance = 1f;
- gdetector = new GestureDetector(context, new GestureDetector.OnGestureListener()
- {
- @Override
- public boolean onSingleTapUp(MotionEvent e)
- {
- return true;
- }
- @Override
- public void onShowPress(MotionEvent e)
- {
- }
- @Override
- public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY)
- {
- return true;
- }
- @Override
- public void onLongPress(MotionEvent e)
- {
- long_touch = true;
- vibrator = (Vibrator) context.getSystemService(Service.VIBRATOR_SERVICE);
- // 振动50ms,提示后续的操作将是旋转图片,而非缩放图片
- vibrator.vibrate(50);
- }
- @Override
- public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY)
- {
- return true;
- }
- @Override
- public boolean onDown(MotionEvent e)
- {
- return true;
- }
- });
- setOnTouchListener(new OnTouchListener()
- {
- public boolean onTouch(View view, MotionEvent event)
- {
- switch(event.getAction() & MotionEvent.ACTION_MASK)
- {
- case MotionEvent.ACTION_DOWN: // 第一个手指touch
- savedMatrix.set(matrix);
- startPoint.set(event.getX(), event.getY());
- mode = DRAG;
- long_touch = false;
- break;
- case MotionEvent.ACTION_POINTER_DOWN: // 第二个手指touch
- oldDistance = getDistance(event); // 计算第二个手指touch时,两指之间的距离
- oldAngle = getDegree(event); // 计算第二个手指touch时,两指所形成的直线和x轴的角度
- if(oldDistance > 10f)
- {
- savedMatrix.set(matrix);
- middlePoint = midPoint(event);
- if(!long_touch)
- {
- mode = ZOOM;
- }
- else
- {
- mode = ROTA;
- }
- }
- break;
- case MotionEvent.ACTION_UP:
- mode = NONE;
- break;
- case MotionEvent.ACTION_POINTER_UP:
- mode = NONE;
- break;
- case MotionEvent.ACTION_MOVE:
- if(vibrator != null) vibrator.cancel();
- if(mode == DRAG)
- {
- matrix.set(savedMatrix);
- matrix.postTranslate(event.getX() - startPoint.x, event.getY() - startPoint.y);
- }
- if(mode == ZOOM)
- {
- float newDistance = getDistance(event);
- if(newDistance > 10f)
- {
- matrix.set(savedMatrix);
- float scale = newDistance / oldDistance;
- matrix.postScale(scale, scale, middlePoint.x, middlePoint.y);
- }
- }
- if(mode == ROTA)
- {
- float newAngle = getDegree(event);
- matrix.set(savedMatrix);
- float degrees = newAngle - oldAngle;
- matrix.postRotate(degrees, middlePoint.x, middlePoint.y);
- }
- break;
- }
- setImageMatrix(matrix);
- invalidate();
- gdetector.onTouchEvent(event);
- return true;
- }
- });
- }
- // 计算两个手指之间的距离
- private float getDistance(MotionEvent event)
- {
- float x = event.getX(0) - event.getX(1);
- float y = event.getY(0) - event.getY(1);
- return FloatMath.sqrt(x * x + y * y);
- }
- // 计算两个手指所形成的直线和x轴的角度
- private float getDegree(MotionEvent event)
- {
- return (float)(Math.atan((event.getY(1) - event.getY(0)) / (event.getX(1) - event.getX(0))) * 180f);
- }
- // 计算两个手指之间,中间点的坐标
- private PointF midPoint( MotionEvent event)
- {
- PointF point = new PointF();
- float x = event.getX(0) + event.getX(1);
- float y = event.getY(0) + event.getY(1);
- point.set(x / 2, y / 2);
- return point;
- }
- }
下面完善PatImageViewActivity.java的代码,使之如下:
- package com.pat.imageview;
- import android.app.Activity;
- import android.graphics.Bitmap;
- import android.graphics.BitmapFactory;
- import android.os.Bundle;
- import android.view.Window;
- import android.view.WindowManager;
- public class PatImageViewActivity extends Activity
- {
- @Override
- public void onCreate(Bundle savedInstanceState)
- {
- super.onCreate(savedInstanceState);
- requestWindowFeature(Window.FEATURE_NO_TITLE);
- this.getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,
- WindowManager.LayoutParams.FLAG_FULLSCREEN);
- PatImageView piv = new PatImageView(this);
- Bitmap bmp = BitmapFactory.decodeResource(getResources(), R.drawable.sophie);
- piv.setImageBitmap(bmp);
- setContentView(piv);
- }
- }
由于有些手势在模拟器上无法模拟,所以就不上运行结果的图片了。本人在真机上运行后(照片就不拍了,有点累啦),可以轻松做到:
1. 很方便地拖动图片(比如,单指按住屏幕进行拖动)
2. 很方便地缩放图片(比如,双指按住屏幕进行分开或者并拢操作,可分别实现放大或者缩小图片的功能)
3. 长按出现振动后,可以很方便地旋转图片(一个手指固定,另外一个手指围绕那个固定的手指运动)。
Android中图像变换Matrix的原理、代码验证和应用(三)的更多相关文章
- Android中图像变换Matrix的原理、代码验证和应用(一)
第一部分 Matrix的数学原理 在Android中,如果你用Matrix进行过图像处理,那么一定知道Matrix这个类.Android中的Matrix是一个3 x 3的矩阵,其内容如下: Matri ...
- Android中图像变换Matrix的原理、代码验证和应用(二)
第二部分 代码验证 在第一部分中讲到的各种图像变换的验证代码如下,一共列出了10种情况.如果要验证其中的某一种情况,只需将相应的代码反注释即可.试验中用到的图片: 其尺寸为162 x 251. 每种变 ...
- Android中的LruCache的原理和使用
Android中的LruCache的原理和使用 LruCache,虽然很多文章都把LRU翻译成"最近最少使用"缓存策略,但Android中的LruCache真的如此吗? 答案是No ...
- Android中SensorManager.getRotationMatrix函数原理解释
SensorManager是Android中的一个类,其有一个函数getRotationMatrix,可以计算出旋转矩阵,进而通过getOrientation求得设备的方向(航向角.俯仰角.横滚角). ...
- Android中的Matrix(矩阵)
写在前面 看这篇笔记之前先看一下参考文章,这篇笔记没有系统的讲述矩阵和代码的东西,参考文章写的也有错误的地方,要辨证的看. 如何计算矩阵乘法 android matrix 最全方法详解与进阶(完整篇) ...
- Android 中View的工作原理
Android中的View在Android的知识体系中扮演着重要的角色.简单来说,View就是Android在视觉的体现.我们所展现的页面就是Android提供的GUI库中控件的组合.但是当要求不能满 ...
- Android中微信抢红包插件原理解析和开发实现
一.前言 自从去年中微信添加抢红包的功能,微信的电商之旅算是正式开始正式火爆起来.但是作为Android开发者来说,我们在抢红包的同时意识到了很多问题,就是手动去抢红包的速度慢了,当然这些有很多原因导 ...
- 【转】Android 学习笔记——利用JNI技术在Android中调用、调试C++代码
原文网址:http://cherishlc.iteye.com/blog/1756762 在Android中调用C++其实就是在Java中调用C++代码,只是在windows下编译生成DLL,在And ...
- Android中典型的ROOT原理(5)
ROOT的作用 Customization 用户的个人定制,如删除一些预安装,定制开机动画等. 特权操作 所有需要特权操作的基本都是要通过ROOT,这也是ROOT的初衷. ROOT的第一步:寻找漏洞并 ...
随机推荐
- 利用T-Sql语句中的二重循环打印乘法口诀表
--定义三个初始化变量 declare @a int,@b int,@c varchar(200) --对@a进行赋值 set @a=1 --循环输出9次,@a为被乘数 while(@a<=9) ...
- linux安装jdk 不成功,找不到版本问题
http://www.linuxidc.com/Linux/2015-01/112030.htm 配置文件 export JAVA_HOMEexport JRE_HOMEexport CLASSPAT ...
- JavaScript继承与原型链
对于那些熟悉基于类的面向对象语言(Java 或者 C++)的开发者来说,JavaScript 的语法是比较怪异的,这是由于 JavaScript 是一门动态语言,而且它没有类的概念( ES6 新增了c ...
- jboss:在standalone.xml中设置系统属性(system-properties)
就象在.net的web应用中,可以在web.config中设置appSettings一样,jboss的standalone.xml中也可以由开发人员自行添加系统属性,用法如下: </extens ...
- 实现Linux与Windows下一致的命令行
这其实是个非常简单的东西. 我们会写一些命令行的工具,一般跨平台的话,会用python或者perl写,比如叫foo.py,然后在Windows和Linux下调用这个脚本: Linux: foo.py ...
- 2016年优秀的java网站分享
java中文网站 伯乐在线java版:http://www.importnew.com/ 码农网:http://www.codeceo.com/ infoq:http://www.infoq.com/ ...
- 快速备份和还原 MySQL 数据库的另一种方法
一直使用 SQL Server 作为公司产品的数据库来存储系统数据,所以备份还原一直都不是问题,因为 SQL Server 的备份还原非常迅速和易用.但今年公司改变策略,使用起 MySQL 数据库作为 ...
- Android 开发1000问笔记
11.android使用全局变量 定义Data类继承Application 在manifest.xml中声明 http://blog.csdn.net/feiyangxiaomi/article/de ...
- 怎样修改 Openstack Horizon(Dashboard)的显示界面 (一)
Openstack 有很多项目,比如 nova 是虚拟机管理,neutron 是虚拟网络管理, glance 是存储管理,而 horizon 是负责 Openstack 的统一界面.horizon 的 ...
- word-wrap,word-break和white-space总结
最近网页布局中遇到得比较多,所以打算总结总结. word-wrap: 1.normal(使用浏览器默认的换行规则) 2.break-word(内容将在边界内换行,但是英文换行会按词断句) word-b ...