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的第一步:寻找漏洞并 ...
随机推荐
- String 对象是不动态改变长度的
在java里 String 对象是不动态改变长度的,只有先转化成StringBuffer,插入处理后在转回. 如 StringBuffer str = new StringBuffer("T ...
- JProfiler学习笔记
JProfiler学习笔记 一.安装JProfiler 从http://www.ej-technologies.com/下载5.1.2并申请试用序列号 二.主要功能简介 1.内存 ...
- iOS RunTime运行时(1):类与对象
Objective-C语言是一门动态语言,他将很多静态语言在编译和链接期做的事放到了运行时来处理.这种动态语言的优势在于:我们写代码更具有灵活性,如我们可以把消息转发给我们想要的对象,或者随意交换一下 ...
- BZOJ 1251: 序列终结者
1251: 序列终结者 Time Limit: 20 Sec Memory Limit: 162 MB Submit: 3773 Solved: 1579 [Submit][Status][Dis ...
- DEDECMS之四 栏目调用
一.内容页调用 {dede:type} <a href=" [field:typelink /] "> [field:typename/] </a> {/d ...
- CSS3中的Rem值与Px之间的换算
bootstrap默认 html{font-size: 10px;} rem是一个相对大小的值,它相对于根元素<html>, 比如假设,我们设置html的字体大小的值为html{font- ...
- .NET MVC控制器分离到类库的方法
在.ASP.NET MVC的开发中,我们创建完项目之后,ASP.NET MVC是已Model-Controller-View的形式存在的,在创建项目自动生成的内容上Model我们很容易分离成类库,所以 ...
- 读书摘要,一种新的黑客文化:programming is forgetting
http://opentranscripts.org/transcript/programming-forgetting-new-hacker-ethic/ 这篇文章非常有意思,作者是一个计算机教师, ...
- Qt学习笔记 线程(一)
Qt中的线程是与平台无关的 QThread 提供了创建一个新线程的方法 新建一个线程,继承QThread并重写它的run()当调用 start()函数时会调用重载的run()函数 例: #ifndef ...
- HoloLens开发手记 - 应用程序模型 App model
HoloLens使用Universal Windows Platform (UWP)提供的应用模型.UWP应用模型定义了应用如何被安全和完全地安装.更新.版本控制和移除.它管理了应用生命周期 - 应用 ...