2014-11-8Android学习------Matrix使用方法--------动画Animation学习篇

来源:互联网 发布:windows dns 缓存 编辑:程序博客网 时间:2024/05/22 08:13
一.Matrix 基本使用方法(一)

 

java.lang.Object    ↳

 

android.graphics.Matrix

 

 

Public Constructors Matrix()
Create an identity matrix
 Matrix(Matrix src)
Create a matrix that is a (deep) copy of src

 

 

 

 

 

 


 

旋转

 

voidsetRotate(float degrees)
Set the matrix to rotate about (0,0) by the specified number of degrees.
voidsetRotate(float degrees, float px, float py)
Set the matrix to rotate by the specified number of degrees, with a pivot point at (px, py).

围绕点px, py 旋转 degrees度, 如果没设置坐标,默认以0,0点旋转.

例子: setRotate(45, 180, 120);


 

 

 

缩放,翻转

 

voidsetScale(float sx, float sy)
Set the matrix to scale by sx and sy.
voidsetScale(float sx, float sy, float px, float py)
Set the matrix to scale by sx and sy, with a pivot point at (px, py).

以点px,py为原点缩放 >=0   1为正常大小  

如果是负数,图形就会翻转

如果没设置原点坐标,默认以0,0点缩放(如果发现图片不见了,检查一下是不是翻转出了屏幕)

例子:setScale(-0.5f, 1,180, 120);  //左右翻转并缩放到一半大小


 

 

倾斜

 

voidsetSkew(float kx, float ky, float px, float py)
Set the matrix to skew by sx and sy, with a pivot point at (px, py).
voidsetSkew(float kx, float ky)
Set the matrix to skew by sx and sy.

以点px,py为原点倾斜如果没有设置原点,则以0,0点为原点.

例子:setSkew(0, 1, 180, 120); //Y 方向拉伸


 

坐标

voidsetTranslate(float dx, float dy)
Set the matrix to translate by (dx, dy).

是图片移动到某一个位置

 

 

 

注意

Matrix中带有pre, post的函数需要考虑先后顺序

例如:想要旋转45度,然后平移到100,100的位置需要

 

 

Matrix matrix = new Matrix();matrix.postRotate(45);matrix.postTranslate(100, 100);  

 

或者

 

Matrix matrix = new Matrix();matrix.setTranslate(100, 100);matrix.preRotate(45);

 

 

这就要考虑到矩阵的前乘和后乘了,不然的话你会发现可能坐标位置不是你想要的,可能图像都不见了.

如果在复杂一些,需要选择,缩放,倾斜同时起作用,并且还要设置坐标到屏幕指定位置你会发现很麻烦,需要自己计算出各个方法的参数,然后考虑调用的先后顺序.

 

但这里有一种更简便的方法,叫系统帮我们计算

 

booleansetConcat(Matrix a, Matrix b)
Set the matrix to the concatenation of the two specified matrices, returning true if the the result can be represented.

这个方法的意思是帮我们把两个 Matrix对象计算并连接起来.

这样的话我们就可以这样使用了

 

 

Matrix mRotateMatrix = new Matrix();//控制旋转Matrix mScaleMatrix = new Matrix();//控制缩放Matrix mSkewMatrix = new Matrix();//控制倾斜Matrix mPosMatrix = new Matrix();//控制坐标Matrix mMatrix = new Matrix();//合并mMatrix.setConcat(mRotateMatrix, mScaleMatrix);mMatrix.setConcat(mMatrix, mSkewMatrix);mMatrix.setConcat(mMatrix, mPosMatrix);canvas.drawBitmap(mBitmap, mMatrix, mPaint);
 

注意:合并的第一步不能直接用mMatrix自身去连接其他的Matrix,我试过几次结果图像又飞了,大家再试试

 

例子:

同时设置

setRotate(45, 180, 120);

setScale(-0.5f, 1,180, 120);  //左右翻转并缩放到一半大小

setSkew(0, 1, 180, 120);      //Y 方向拉伸


 

 

 原文地址:http://www.myexception.cn/mobile/750115.html


 二.

Matrix的操作,总共分为translate(平移),rotate(旋转),scale(缩放)和skew(倾斜)四种,每一种变换在

Android的API里都提供了set, post和pre三种操作方式,除了translate,其他三种操作都可以指定中心点。


    set是直接设置Matrix的值,每次set一次,整个Matrix的数组都会变掉。


    post是后乘,当前的矩阵乘以参数给出的矩阵。可以连续多次使用post,来完成所需的整个变换。例如,要将一个图片旋
转30度,然后平移到(100,100)的地方,那么可以这样做:

Java代码  收藏代码
  1. Matrix m = new Matrix();  
  2.   
  3. m.postRotate(30);  
  4.   
  5. m.postTranslate(100100);    
 

 

这样就达到了想要的效果。


    pre是前乘,参数给出的矩阵乘以当前的矩阵。所以操作是在当前矩阵的最前面发生的。例如上面的例子,如果用pre的话

,就要这样:

Java代码  收藏代码
  1. Matrix m = new Matrix();  
  2.   
  3. m.setTranslate(100100);  
  4.   
  5. m.preRotate(30);  

    旋转、缩放和倾斜都可以围绕一个中心点来进行,如果不指定,默认情况下,是围绕(0,0)点来进行。


    下面给出一个例子。

Java代码  收藏代码
  1. package chroya.demo.graphics;  
  2.   
  3. import android.content.Context;  
  4. import android.graphics.Bitmap;  
  5. import android.graphics.Canvas;  
  6. import android.graphics.Matrix;  
  7. import android.graphics.Rect;  
  8. import android.graphics.drawable.BitmapDrawable;  
  9. import android.util.DisplayMetrics;  
  10. import android.view.MotionEvent;  
  11. import android.view.View;  
  12.   
  13. public class MyView extends View {  
  14.       
  15.     private Bitmap mBitmap;  
  16.     private Matrix mMatrix = new Matrix();  
  17.       
  18.     public MyView(Context context) {  
  19.         super(context);  
  20.         initialize();  
  21.     }  
  22.   
  23.     private void initialize() {  
  24.           
  25.         Bitmap bmp = ((BitmapDrawable)getResources().getDrawable(R.drawable.show)).getBitmap();  
  26.         mBitmap = bmp;  
  27.         /*首先,将缩放为100*100。这里scale的参数是比例。有一点要注意,如果直接用100/ 
  28. bmp.getWidth()的话,会得到0,因为是整型相除,所以必须其中有一个是float型的,直接用100f就好。*/  
  29.         mMatrix.setScale(100f/bmp.getWidth(), 100f/bmp.getHeight());  
  30.                 //平移到(100,100)处  
  31.         mMatrix.postTranslate(100100);  
  32.                 //倾斜x和y轴,以(100,100)为中心。  
  33.         mMatrix.postSkew(0.2f, 0.2f, 100100);  
  34.     }  
  35.       
  36.     @Override protected void onDraw(Canvas canvas) {  
  37. //      super.onDraw(canvas);  //如果界面上还有其他元素需要绘制,只需要将这句话写上就行了。  
  38.           
  39.         canvas.drawBitmap(mBitmap, mMatrix, null);  
  40.     }  
  41. }  

 运行效果如下:

    红色的x和y表示倾斜的角度,下面是x,上面是y。看到了没,Matrix就这么简单 。

原文地址:http://chroya.iteye.com/blog/713869


1. 旋转

内置的方法之一是setRotate方法。它采用一个浮点数表示旋转的角度。围绕默认点(0,0),正数将顺时针旋转图像,而负数将逆时针旋转图像,其中默认点是图像的左上角,如图3-8所示。

  1. Matrix matrix = new Matrix();  
  2. matrix.setRotate(15);  
  3. canvas.drawBitmap(bmp, matrix, paint); 

另外,也可以使用旋转的角度及围绕的旋转点作为参数调用setRotate方法。选择图像的中心点作为旋转点所产生的结果可能更符合我们的需要,如图3-9所示。
  1. matrix.setRotate(15,bmp.getWidth()/2,bmp.getHeight()/2); 
 图3-8  围绕默认点(0,0)旋转 图3-9  围绕图像的中心点旋转

2. 缩放

Matrix类中另一个有用的方法是setScale方法。它采用两个浮点数作为参数,分别表示在每个轴上所产生的缩放量。第一个参数是x轴的缩放比例,而第二个参数是y轴的缩放比例。图3-10显示了下列setScale方法调用的结果。

  1. matrix.setScale(1.5f,1); 

 图3-10  在x轴上应用1.5的缩放比例

3. 平移

Matrix类中最有用的方法之一是setTranslate方法。平移意味着在x轴和y轴上简单地移动图像。setTranslate方法采用两个浮点数作为参数,表示在每个轴上移动的数量。第一个参数是图像将在x轴上移动的数量,而第二个参数是图像将在y轴上移动的数量。在x轴上使用正数进行平移将向右移动图像,而使用负数将向左移动图像。在y轴上使用正数进行平移将向下移动图像,而使用负数将向上移动图像。

  1. setTranslate(1.5f,-10);. 

4. 之前和之后的版本

当然,以上这些方法仅是冰山一角。还有几个方法可能会证明有用。前面介绍的方法也都有之前和之后的版本,这使得我们能够每次按顺序完成一个以上的转换。例如,可以先执行preScale,然后执行setRotate或setScale,最后执行postRotate。取决于执行的操作,更改它们发生的顺序会产生具有巨大差异的结果。图3-11显示了下列两个方法调用的结果。

  1. matrix.setScale(1.5f, 1);  
  2. matrix.postRotate(15,bmp.getWidth()/2,bmp.getHeight()/2); 

 图3-11  先缩放,后旋转

5. 镜像

一个特别有用的方法对是setScale和postTranslate,它们允许跨单个轴(或者两个轴)翻转图像。如果以一个负数缩放,那么会将该图像绘制到坐标系统的负值空间。由于(0,0)点位于左上角,使用x轴上的负数会导致向左绘制图像。因此我们需要使用postTranslate方法,将图像向右移动,如图3-12所示。

  1. matrix.setScale(-1, 1);  
  2. matrix.postTranslate(bmp.getWidth(),0); 
 图3-12  镜像

6. 翻转

可以在y轴上做同样的事情,翻转图像以使其倒置。通过将图像围绕两个轴上的中心点旋转180°,可以实现相同的效果,如图3-13所示。

  1. matrix.setScale(1, -1);  
  2. matrix.postTranslate(0, bmp.getHeight()); 

 图3-13  翻转

7. 绘制替代图像

在之前的小节中,所使用方法的缺点之一是图像会被截断,因为没有计算转换后的结果大小,仅仅以预先确定的大小绘制到一个位图对象中。

解决这个问题的方法之一是:当初次创建位图对象时,应用Matrix对象而不是绘制到一个空的位图对象中。

通过这种方式,将无须再获得Canvas和Paint对象。缺点是不能继续更改位图对象,因为如果想要对其进行任何转换,那么都需要重新创建它。

在Bitmap类中存在一个静态方法createBitmap能够实现以上功能。第一个参数是源位图对象,接下来的参数分别是来自源图像的初始的x、y、宽度和高度值,随后是所应用的Matrix对象,最后是一个布尔值,表示是否在图像上应用某种过滤器。由于没有应用包含过滤器的矩阵(将在本章后面讨论),将其设置为false。

  1. Matrix matrix = new Matrix();  
  2. matrix.setRotate(15,bmp.getWidth()/2,bmp.getHeight()/2);  
  3. alteredBitmap = Bitmap.createBitmap(bmp, 0, 0, bmp.getWidth(),  
  4.   bmp.getHeight(), matrix, false);  
  5. alteredImageView.setImageBitmap(alteredBitmap); 

我们以相同的方式处理矩阵,但是使用初始的位图对象(bmp)作为源图像,并将它传入Matrix对象,对第二个位图对象(alteredBitmap)进行实例化。这将以指定的平移从源图像创建一个位图对象,并对该位图对象的大小进行缩放,如图3-14所示。 图3-14  在创建位图对象时
应用Matrix对象;调整位图
对象的尺寸以匹配实际的图像数据
原文地址:http://book.51cto.com/art/201203/325114.htm

 

三、首先介绍Scale缩放的控制

scale就是缩放,我们调用Matrix的setScale、preScale、postScale,实际在内部,就是通过修改MSCALE_X和MSCALE_Y来实现的。

下面就是一个简单的例子

public class MatrixTestActivity extends Activity {  private int screenWidth;  private int screenHeight;  private int bitmapWidth;  private int bitmapHeight;  private float baseScale;  private float originalScale;  @Override  public void onCreate(Bundle savedInstanceState) {    super.onCreate(savedInstanceState);    setContentView(R.layout.main);    // 获得屏幕的宽高    screenWidth = getWindow().getWindowManager().getDefaultDisplay().getWidth();    screenHeight = getWindow().getWindowManager().getDefaultDisplay().getHeight();    // 加载Imageview和获得图片的信息    final ImageView imageView = (ImageView) findViewById(R.id.imgView);    final Bitmap bitmap = BitmapFactory.decodeResource(getResources(), R.drawable.a);    bitmapWidth = bitmap.getWidth();    bitmapHeight = bitmap.getHeight();    // 计算缩放比,因为如果图片的尺寸超过屏幕,那么就会自动匹配到屏幕的尺寸去显示。    // 那么,我们就不知道图片实际上在屏幕上显示的宽高,所以先计算需要全部显示的缩放比,    // 在去计算图片显示时候的实际宽高,然后,才好进行下一步的缩放。    // 要不然,会导致缩小和放大没效果,或者内存泄漏等等    float scaleX = screenWidth / (float) bitmapWidth;    float scaleY = screenHeight / (float) bitmapHeight;    baseScale = Math.min(scaleX, scaleY);// 获得缩放比例最大的那个缩放比,即scaleX和scaleY中小的那个    originalScale = baseScale;    final Matrix matrix = new Matrix();    matrix.setScale(originalScale, originalScale);    // 关于setScale和preScale和postScale的区别以后再说    // matrix.preScale(originalScale, originalScale);    // matrix.postScale(originalScale, originalScale);    Bitmap bitmap2 = Bitmap        .createBitmap(bitmap, 0, 0, bitmapWidth, bitmapHeight, matrix, false);    imageView.setImageBitmap(bitmap2);    final Button scale_btn = (Button) findViewById(R.id.scale_btn);    final EditText scale_text = (EditText) findViewById(R.id.scale_editView);    scale_btn.setOnClickListener(new View.OnClickListener() {      public void onClick(View v) {        String scaleStr = scale_text.getText().toString();        if (scaleStr == null || "".equals(scaleStr))          return;        float scale = 0.0f;        try {          scale = Float.parseFloat(scaleStr);        } catch (NumberFormatException e) {          return;        }        matrix.reset();        originalScale = scale * originalScale;//看        if (originalScale < 0.05 ){          originalScale=0.05f;        }        if(originalScale > baseScale){          originalScale=baseScale;        }        matrix.setScale(originalScale, originalScale);        Bitmap bitmapChange = Bitmap.createBitmap(bitmap, 0, 0, bitmapWidth, bitmapHeight,            matrix, false);        imageView.setImageBitmap(bitmapChange);      }    });  }}

可以发现,对于Scale的设置,Matrix提供了3中不同的方式来设置。

setScale、preScale、postScale。

这三种方法之间有什么区别呢?看下面的。


二、set....、pre....、post...的区别 

1、setScale(sx,sy),首先会将该Matrix设置为对角矩阵,即相当于调用reset()方法,然后在设置该Matrix的MSCALE_X和MSCALE_Y直接设置为sx,sy的值 

2、preScale(sx,sy),不会重置Matrix,而是直接与Matrix之前的MSCALE_X和MSCALE_Y值结合起来(相乘),M' = M * S(sx, sy)。

3、postScale(sx,sy),不会重置Matrix,而是直接与Matrix之前的MSCALE_X和MSCALE_Y值结合起来(相乘),M' = S(sx, sy) * M。

preScale和post都是与之前的Matrix结合起来,那它们之间又有什么区别呢?

举几个例子测试下关于pre....和post....的区别:

对一个Matrix如下设置

1、pre....的执行顺序

Matrix matrix=new Matrix();        float[] points=new float[]{10.0f,10.0f};                matrix.preScale(2.0f, 3.0f);//        matrix.preTranslate(8.0f,7.0f);//        matrix.mapPoints(points);        Log.i("test", points[0]+"");        Log.i("test", points[1]+"");

结果为点坐标为(36.0,51.0)

可以得出结论,进行变换的顺序是先执行preTranslate(8.0f,7.0f),在执行的preScale(2.0f,3.0f)。这也是为什么有的人比喻为pre...是向后生长的,即对于一个Matrix的设置中,

所有pre....是倒着向后执行的。


2、post...的执行顺序 

Matrix matrix=new Matrix();        float[] points=new float[]{10.0f,10.0f};                matrix.postScale(2.0f, 3.0f);//        matrix.postTranslate(8.0f,7.0f);//        matrix.mapPoints(points);        Log.i("test", points[0]+"");        Log.i("test", points[1]+"");

结果为点坐标为(28.0,37.0)

可以得出结论,进行变换的顺序是先执行postScale(2.0f,3.0f),在执行的postTranslate(8.0f,7.0f)。这也是为什么有的人比喻为post...是向前生长的,即对于一个Matrix的设置中,所有post....是顺着向前执行的。


3、当pre和post交替出现的执行顺序 

Matrix matrix=new Matrix();        float[] points=new float[]{10.0f,10.0f};        matrix.postScale(2.0f, 3.0f);        matrix.preRotate(90);        matrix.mapPoints(points);        Log.i("test", points[0]+"");        Log.i("test", points[1]+"");
结果为点坐标为(-20.0,30.0) 

将pre...和post顺序换一下

Matrix matrix=new Matrix();        float[] points=new float[]{10.0f,10.0f};                matrix.preRotate(90);        matrix.postScale(2.0f, 3.0f);        matrix.mapPoints(points);        Log.i("test", points[0]+"");        Log.i("test", points[1]+"");
结果为点坐标依旧为为(-20.0,30.0) 

可见,总是pre先执行的。在看下面的:
Matrix matrix = new Matrix();    float[] points = new float[] { 10.0f, 10.0f };    matrix.postScale(2.0f, 3.0f);// 第1步    matrix.preRotate(90);// 第2步    matrix.postTranslate(8.0f, 7.0f);// 第3步    matrix.preScale(1.5f, 2.5f);// 第4步    matrix.mapPoints(points);    Log.i("test", points[0] + "");    Log.i("test", points[1] + "");
结果为点坐标依旧为为(-42.0,52.0) 
经过前面的结论和推算,可以发现执行的顺序是   4----2----1---3 


 在看下面的,增加了setScale的一段代码:

Matrix matrix = new Matrix();    float[] points = new float[] { 10.0f, 10.0f };    matrix.postScale(2.0f, 3.0f);// 第1步    matrix.preRotate(90);// 第2步    matrix.setScale(1.4f, 2.6f);// 第3步    matrix.postTranslate(8.0f, 7.0f);// 第4步    matrix.preScale(1.5f, 2.5f);// 第5步    matrix.mapPoints(points);    Log.i("test", points[0] + "");    Log.i("test", points[1] + "");
结果为点坐标依旧为为(29.0,72.0) 
经过计算,可以发现,在第3步setScale之前的第1、2步根本就没有用了,直接被第3步setScale覆盖,在从第3开始执行的。

顺序为2---1----3----5----4,因为2、1被覆盖了,所以没有效果,相当于直接执行3-----5----4


总结:最后可以得出结论,在对matrix该次变换之前的所有设置中,先检测有没有setScale,如果有,直接跳到setScale那一步开始执行变换,然后在倒着执行下面所有的pre...变换,在顺着执行所有post....的变换。所以在对Matrix变换设置的时候,一定要注意顺序,不同的顺序,会有不同的结果。 

 原文地址:http://www.tuicool.com/articles/emeMBr

谢谢那些无私分享的网页

 

 

 

 

 

 

 

 

 

0 0
原创粉丝点击
热门问题 老师的惩罚 人脸识别 我在镇武司摸鱼那些年 重生之率土为王 我在大康的咸鱼生活 盘龙之生命进化 天生仙种 凡人之先天五行 春回大明朝 姑娘不必设防,我是瞎子 孩子鼻炎睡不好怎么办 鼻炎清鼻涕不止怎么办 宝宝持续低烧流鼻涕怎么办 孩子鼻塞不通气怎么办 2月婴儿感冒怎么办 长期流黄鼻涕怎么办 孩子流清水鼻涕怎么办 小孩有点流鼻子怎么办 初生婴儿堵鼻子怎么办? 小孩反复发烧了怎么办 小孩突然发烧了怎么办 40天宝宝鼻塞怎么办 宝宝伤风鼻子不通怎么办 鼻子伤风不通气怎么办 宝宝伤风流鼻子怎么办 十个月婴儿上火怎么办 一个多月宝宝鼻子有鼻屎怎么办 三个月婴儿感冒发烧怎么办 小孩感冒发烧流鼻涕怎么办 小孩感冒发烧反反复复怎么办 宝宝反复发烧39怎么办 一岁婴儿流鼻涕怎么办 四岁宝宝发烧怎么办 小孩流清鼻涕怎么办? 5宝宝光流清鼻涕怎么办 孩子一直流鼻子怎么办 10岁天天流鼻涕怎么办 喉咙痛又痒咳嗽怎么办 60天宝宝流鼻涕怎么办 宝宝流鼻子严重怎么办 鼻炎鼻涕多鼻塞怎么办 夏天老人感冒流鼻涕怎么办 鼻窦炎流清鼻涕怎么办 鼻子有脓鼻涕怎么办 宝宝有脓鼻涕怎么办 小孩脓鼻涕咳嗽怎么办 哺乳期流黄鼻涕怎么办 宝宝鼻塞流脓涕怎么办 喉咙痛浓痰咳嗽怎么办 哺乳期留清鼻涕怎么办 哺乳期就清鼻涕怎么办