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的第一步:寻找漏洞并 ...
随机推荐
- cache缓存
缓存分为:数据缓存,页面缓存,内存缓存(memcache,redis) ob,输出缓冲区,是output buffering的简称 FileCache.php <?php //本文件用来存储和读 ...
- [No000013]在Office中关闭自动拼写检查和自动语法检查
大家知道有时候语法检查很麻烦,搞得文档里都是红线和绿线.解决办法就是关闭自动拼写检查.现在我们来介绍怎么关闭office包括Word .Outlook .PowerPoint .OneNote .Pu ...
- ExcelHelper
NPOI下载:http://pan.baidu.com/s/1JNAGm 最新封装类: 2016-03-14 1.添加对OleConn的读 private static string connstri ...
- jmeter(一)基础介绍
参考书籍:段念<软件性能测试与案例剖析>——第二版 推荐一本书<零成本实现web性能测试——基于Apache—jmeter>,主要内容是一些关于jmeter的实战使用,想学习的 ...
- 报错问题:InnoDB: Error: log file ./ib_logfile0 is of different size
InnoDB: Error: log file ./ib_logfile0 is of different size bytesInnoDB: than specified in the .cnf f ...
- Fastlane为iOS带来持续部署
Fastlane是一组工具套件,旨在实现iOS应用发布流程的自动化,并且提供一个运行良好的持续部署流程,只需要运行一个简单的命令就可以触发这个流程. Fastlane是一个ruby脚本集合,其中囊括了 ...
- PL/SQL Transaction Control
PL/SQL 基础 ( 下 ) 1. PL/SQL中的 SQL语句 - END语句与COMMIT等内容,没有任何关系. - PL/SQL does not directly support dat ...
- Java核心技术点之集合框架
1. 概述 Java集合框架由Java类库的一系列接口.抽象类以及具体实现类组成.我们这里所说的集合就是把一组对象组织到一起,然后再根据不同的需求操纵这些数据.集合类型就是容纳这些对象的一个容 ...
- swift——启动页国际化:一步一步动态加载启动页图片,启动的时候加载文字
由于公司的需求,要求做一个国际化的启动页,因为app我也弄国际化了,就剩下启动页国际化未完成,百度了呵谷歌了好多答案都不尽如人意,最后也是看见同事完成,我也问了具体的做法,决定分享给需要的人,免得和我 ...
- 海王星给你好看!FineUI v4.0公测版发布暨《你找BUG我送书》活动开始(活动已结束!)
<FineUI v4.0 你找BUG我送书>活动已结束,恭喜如下三位网友获得由 FineUI 作者亲自翻译的图书<jQuery实战 第二版>! 奋斗~ 吉吉﹑ purplebo ...