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
|
旋转
void | setRotate(float degrees)
Set the matrix to rotate about (0,0) by the specified number of degrees.
|
void | setRotate(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);
缩放,翻转
void | setScale(float sx, float sy)
Set the matrix to scale by sx and sy.
|
void | setScale(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); //左右翻转并缩放到一半大小
倾斜
void | setSkew(float kx, float ky, float px, float py)
Set the matrix to skew by sx and sy, with a pivot point at (px, py).
|
void | setSkew(float kx, float ky)
Set the matrix to skew by sx and sy.
|
以点px,py为原点倾斜如果没有设置原点,则以0,0点为原点.
例子:setSkew(0, 1, 180, 120); //Y 方向拉伸
坐标
void | setTranslate(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);
这就要考虑到矩阵的前乘和后乘了,不然的话你会发现可能坐标位置不是你想要的,可能图像都不见了.
如果在复杂一些,需要选择,缩放,倾斜同时起作用,并且还要设置坐标到屏幕指定位置你会发现很麻烦,需要自己计算出各个方法的参数,然后考虑调用的先后顺序.
但这里有一种更简便的方法,叫系统帮我们计算
boolean | setConcat(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)的地方,那么可以这样做:
- Matrix m = new Matrix();
- m.postRotate(30);
- m.postTranslate(100, 100);
这样就达到了想要的效果。
pre是前乘,参数给出的矩阵乘以当前的矩阵。所以操作是在当前矩阵的最前面发生的。例如上面的例子,如果用pre的话
,就要这样:
- Matrix m = new Matrix();
- m.setTranslate(100, 100);
- m.preRotate(30);
旋转、缩放和倾斜都可以围绕一个中心点来进行,如果不指定,默认情况下,是围绕(0,0)点来进行。
下面给出一个例子。
- package chroya.demo.graphics;
- import android.content.Context;
- import android.graphics.Bitmap;
- import android.graphics.Canvas;
- import android.graphics.Matrix;
- import android.graphics.Rect;
- import android.graphics.drawable.BitmapDrawable;
- import android.util.DisplayMetrics;
- import android.view.MotionEvent;
- import android.view.View;
- public class MyView extends View {
- private Bitmap mBitmap;
- private Matrix mMatrix = new Matrix();
- public MyView(Context context) {
- super(context);
- initialize();
- }
- private void initialize() {
- Bitmap bmp = ((BitmapDrawable)getResources().getDrawable(R.drawable.show)).getBitmap();
- mBitmap = bmp;
- /*首先,将缩放为100*100。这里scale的参数是比例。有一点要注意,如果直接用100/
- bmp.getWidth()的话,会得到0,因为是整型相除,所以必须其中有一个是float型的,直接用100f就好。*/
- mMatrix.setScale(100f/bmp.getWidth(), 100f/bmp.getHeight());
- //平移到(100,100)处
- mMatrix.postTranslate(100, 100);
- //倾斜x和y轴,以(100,100)为中心。
- mMatrix.postSkew(0.2f, 0.2f, 100, 100);
- }
- @Override protected void onDraw(Canvas canvas) {
- // super.onDraw(canvas); //如果界面上还有其他元素需要绘制,只需要将这句话写上就行了。
- canvas.drawBitmap(mBitmap, mMatrix, null);
- }
- }
运行效果如下:
红色的x和y表示倾斜的角度,下面是x,上面是y。看到了没,Matrix就这么简单 。
原文地址:http://chroya.iteye.com/blog/713869
1. 旋转
内置的方法之一是setRotate方法。它采用一个浮点数表示旋转的角度。围绕默认点(0,0),正数将顺时针旋转图像,而负数将逆时针旋转图像,其中默认点是图像的左上角,如图3-8所示。
- Matrix matrix = new Matrix();
- matrix.setRotate(15);
- canvas.drawBitmap(bmp, matrix, paint);
另外,也可以使用旋转的角度及围绕的旋转点作为参数调用setRotate方法。选择图像的中心点作为旋转点所产生的结果可能更符合我们的需要,如图3-9所示。
- matrix.setRotate(15,bmp.getWidth()/2,bmp.getHeight()/2);
![]() |
图3-8 围绕默认点(0,0)旋转 |
![]() |
图3-9 围绕图像的中心点旋转 |
2. 缩放
Matrix类中另一个有用的方法是setScale方法。它采用两个浮点数作为参数,分别表示在每个轴上所产生的缩放量。第一个参数是x轴的缩放比例,而第二个参数是y轴的缩放比例。图3-10显示了下列setScale方法调用的结果。
- matrix.setScale(1.5f,1);
![]() |
图3-10 在x轴上应用1.5的缩放比例 |
3. 平移
Matrix类中最有用的方法之一是setTranslate方法。平移意味着在x轴和y轴上简单地移动图像。setTranslate方法采用两个浮点数作为参数,表示在每个轴上移动的数量。第一个参数是图像将在x轴上移动的数量,而第二个参数是图像将在y轴上移动的数量。在x轴上使用正数进行平移将向右移动图像,而使用负数将向左移动图像。在y轴上使用正数进行平移将向下移动图像,而使用负数将向上移动图像。
- setTranslate(1.5f,-10);.
4. 之前和之后的版本
当然,以上这些方法仅是冰山一角。还有几个方法可能会证明有用。前面介绍的方法也都有之前和之后的版本,这使得我们能够每次按顺序完成一个以上的转换。例如,可以先执行preScale,然后执行setRotate或setScale,最后执行postRotate。取决于执行的操作,更改它们发生的顺序会产生具有巨大差异的结果。图3-11显示了下列两个方法调用的结果。
- matrix.setScale(1.5f, 1);
- matrix.postRotate(15,bmp.getWidth()/2,bmp.getHeight()/2);
![]() |
图3-11 先缩放,后旋转 |
5. 镜像
一个特别有用的方法对是setScale和postTranslate,它们允许跨单个轴(或者两个轴)翻转图像。如果以一个负数缩放,那么会将该图像绘制到坐标系统的负值空间。由于(0,0)点位于左上角,使用x轴上的负数会导致向左绘制图像。因此我们需要使用postTranslate方法,将图像向右移动,如图3-12所示。
- matrix.setScale(-1, 1);
- matrix.postTranslate(bmp.getWidth(),0);
![]() |
图3-12 镜像 |
6. 翻转
可以在y轴上做同样的事情,翻转图像以使其倒置。通过将图像围绕两个轴上的中心点旋转180°,可以实现相同的效果,如图3-13所示。
- matrix.setScale(1, -1);
- matrix.postTranslate(0, bmp.getHeight());
![]() |
图3-13 翻转 |
7. 绘制替代图像
在之前的小节中,所使用方法的缺点之一是图像会被截断,因为没有计算转换后的结果大小,仅仅以预先确定的大小绘制到一个位图对象中。
解决这个问题的方法之一是:当初次创建位图对象时,应用Matrix对象而不是绘制到一个空的位图对象中。
通过这种方式,将无须再获得Canvas和Paint对象。缺点是不能继续更改位图对象,因为如果想要对其进行任何转换,那么都需要重新创建它。
在Bitmap类中存在一个静态方法createBitmap能够实现以上功能。第一个参数是源位图对象,接下来的参数分别是来自源图像的初始的x、y、宽度和高度值,随后是所应用的Matrix对象,最后是一个布尔值,表示是否在图像上应用某种过滤器。由于没有应用包含过滤器的矩阵(将在本章后面讨论),将其设置为false。
- Matrix matrix = new Matrix();
- matrix.setRotate(15,bmp.getWidth()/2,bmp.getHeight()/2);
- alteredBitmap = Bitmap.createBitmap(bmp, 0, 0, bmp.getWidth(),
- bmp.getHeight(), matrix, false);
- alteredImageView.setImageBitmap(alteredBitmap);
我们以相同的方式处理矩阵,但是使用初始的位图对象(bmp)作为源图像,并将它传入Matrix对象,对第二个位图对象(alteredBitmap)进行实例化。这将以指定的平移从源图像创建一个位图对象,并对该位图对象的大小进行缩放,如图3-14所示。
![]() |
图3-14 在创建位图对象时 应用Matrix对象;调整位图 对象的尺寸以匹配实际的图像数据 |
三、首先介绍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谢谢那些无私分享的网页