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的第一步:寻找漏洞并 ...
随机推荐
- Windows英文版GitHub客户端使用操作流程图文攻略教程现没中文版
Git是一个分布式的版本控制系统,最初由Linus Torvalds编写,用作Linux内核代码的管理.作为一个程序员,我们需要掌握其用法. 作为开源代码库以及版本控制系统,Github目前拥有140 ...
- CSS中的常用属性
一 CSS文字属性:color : #999999; /*文字颜色*/font-family : 宋体,sans-serif; /*文字字体*/font-size : 9pt; /*文字大小*/fon ...
- lca入门———树上倍增法(博文内含例题)
倍增求LCA: father[i][j]表示节点i往上跳2^j次后的节点 可以转移为 father[i][j]=father[father[i][j-1]][j-1] 整体思路: 先比较两个点的深度, ...
- 一个App需要的东西
1.短信申请平台 (发送验证码需要的短信) http://www.yuntongxun.com/api/sms?nl=sy_cp 容联云通讯
- HTML 学习笔记 CSS样式(相对定位 绝对定位)
CSS相对定位 设置为相对定位(relative)的元素会偏移某个距离.元素仍保持其未定位前的形状,他原本所占的空间仍然保留 CSS相对定位 相对定位是一个非常容易掌握的概念,如果对一个元素进行相对定 ...
- Java的jar文件安装成windows 服务
Java的jar文件安装成windows 服务: 1.下载:nssm,复制到jar文件目录下 2. jar文件目录下创建bat文件[run.bat],内容为[java -jar 文件名.jar] 3. ...
- nginx应用总结(1)--基础认识和应用配置
在linux系统下使用nginx作为web应用服务,用来提升网站访问速度的经验已五年多了,今天在此对nginx的使用做一简单总结. 一.nginx服务简介Nginx是一个高性能的HTTP和反向代理服务 ...
- 迭代器和for-of循环 顺便带一下Es5中的.map遍历
let set = new Set(); //set方法去除重复的数据 [1, 2, 3, 4, 2, 8, 4].map(function (elem) { set.add(elem); //遍历完 ...
- mysql游标循环的使用
CREATE PROCEDURE `test`.`new_procedure` () BEGIN DECLARE done INT DEFAULT FALSE; -- 需要定义接收游标数据的变量 ); ...
- &12 二叉搜索树
#1,定义 二叉查找树(Binary Search Tree),(又:二叉搜索树,二叉排序树)它或者是一棵空树,或者是具有下列性质的二叉树: 若它的左子树不空,则左子树上所有结点的值均小于它的根结点的 ...