今天和大家分享一下Android中Matrix的简单用法,Matrix其实就是一个3*3的矩阵,利用这个矩阵对图像操作。在Android中,为我们提供一些封装好的方法可以进行一些简单的图像操作,总共分为rotate(旋转),scale(缩放),translate(平移)和skew(倾斜)四种,每一种变换都提供了set, post和pre三种操作方式,除了translate,其他三种操作都可以指定中心点。其中post的方式是对原矩阵进行后乘,pre方式是对原矩阵进行前乘,另外,每一次通过set的方式调用就会进行一次reset重置,之前的操作就会被销毁,在组合变化中需要注意。
旋转操作
Matrix中与旋转操作相关的方法一共有6个,
public boolean preRotate (float degrees)
public boolean preRotate (float degrees, float px, float py)
public boolean postRotate (float degrees)
public boolean postRotate (float degrees, float px, float py)
public void setRotate (float degrees)
public void setRotate (float degrees, float px, float py)
其中参数degrees指明了旋转的角度,如果大于零则为顺时针,小于零为逆时针;参数px,py用于指定旋转的中心,默认为(0,0)即左上角。
缩放操作
Matrix中与缩放操作相关的方法一共有6个,
public boolean postScale (float sx, float sy)
public boolean postScale (float sx, float sy, float px, float py)
public boolean preScale (float sx, float sy)
public boolean preScale (float sx, float sy, float px, float py)
public void setScale (float sx, float sy)
public void setScale (float sx, float sy, float px, float py)
其中参数sx,sy分别表示x轴和y轴的拉伸变化,如果大于1,为放大,小于1为缩小,为负值则表示对称的变化(在之后的组合变化中我们会用到它来实现镜子和倒影的效果);参数px,py用于指定缩放的中心(就是当缩放变化后该点的位置坐标不会变),默认为(0,0)即左上角。
平移操作
Matrix中关于平移的方法有3个
public boolean postTranslate (float dx, float dy)
public boolean preTranslate (float dx, float dy)
public void setTranslate (float dx, float dy)
其中参数dx,dy表示平移的距离,dx大于零表示向右,小于零表示向左;dy大于零表示向下,小于零表示向上。
倾斜操作
Matrix中关于倾斜操作的方法有6个
public boolean postSkew (float kx, float ky)
public boolean postSkew (float kx, float ky, float px, float py)
public boolean preSkew (float kx, float ky)
public boolean preSkew (float kx, float ky, float px, float py)
public void setSkew (float kx, float ky)
public void setSkew (float kx, float ky, float px, float py)
点(x,y)经过skew(kx,ky,px,py)变换之后,坐标为(kx*(y-py)+px,ky*(x-px)+py),如果,px和py没有,则默认为都为0。
组合变化
1.镜像变化:对于scale变化,如果以一个负数缩放,那么会将该 图像绘制到坐标系统的负值空间。由于(0,0)点位于左上角,使用x轴上的负数会导致向左绘制图像。因此我们需要使用postTranslate方法,将图像向右移动即可实现镜像变化。
matrix.setScale(-1, 1);
matrix.postTranslate(mBitmap.getWidth(),0);
2.倒影变化:同镜像变化,我们可以在y轴上做相同的事情,就会得到倒影的效果。
matrix.postScale(1, -1);
matrix.postTranslate(0, mBitmap.getHeight());
代码样例
根据以上的Matrix的操作,自己做了一个小的实验,效果如下:
MainActivity类:
package com.example.matrixtest;
import android.app.Activity;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.os.Bundle;
import android.view.Menu;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
public class MainActivity extends Activity {
private TestView testView;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
testView = (TestView) findViewById(R.id.testview);
Bitmap bitmap = BitmapFactory.decodeResource(getResources(),
R.drawable.ttt);
testView.setmBitmap(bitmap);
((Button) findViewById(R.id.button_rotate))
.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
// TODO Auto-generated method stub
testView.rotate(15);
}
});
((Button) findViewById(R.id.button_scale))
.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
// TODO Auto-generated method stub
testView.scale(0.8f, 0.8f);
}
});
((Button) findViewById(R.id.button_translate))
.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
// TODO Auto-generated method stub
testView.translate(1, 1);
}
});
((Button) findViewById(R.id.button_skew))
.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
// TODO Auto-generated method stub
testView.skew(-0.3f, 0.3f);
}
});
((Button) findViewById(R.id.button_mirror))
.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
// TODO Auto-generated method stub
testView.mirror();
}
});
((Button) findViewById(R.id.button_shadow))
.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
// TODO Auto-generated method stub
testView.shadow();
}
});
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.main, menu);
return true;
}
}
TestView类,我重新写了一个View来绘制图片:
package com.example.matrixtest;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Matrix;
import android.util.AttributeSet;
import android.view.View;
public class TestView extends View {
private Bitmap mBitmap;
private Matrix matrix;
public TestView(Context context) {
super(context);
// TODO Auto-generated constructor stub
matrix = new Matrix();
}
public TestView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
// TODO Auto-generated constructor stub
matrix = new Matrix();
}
public TestView(Context context, AttributeSet attrs) {
super(context, attrs);
// TODO Auto-generated constructor stub
matrix = new Matrix();
}
public Bitmap getmBitmap() {
return mBitmap;
}
public void setmBitmap(Bitmap mBitmap) {
this.mBitmap = mBitmap;
invalidate();
}
@Override
protected void onDraw(Canvas canvas) {
// TODO Auto-generated method stub
super.onDraw(canvas);
if (mBitmap != null) {
canvas.drawBitmap(mBitmap, matrix, null);
}
}
public void rotate(float degree) {
if (mBitmap != null) {
matrix.preRotate(degree, mBitmap.getWidth() / 2,
mBitmap.getHeight() / 2);
invalidate();
}
}
public void translate(float dx, float dy) {
if (mBitmap != null) {
matrix.postTranslate(dx, dy);
invalidate();
}
}
public void scale(float sx, float sy) {
if (mBitmap != null) {
matrix.postScale(sx, sy);
invalidate();
}
}
public void mirror() {
if (mBitmap != null) {
matrix.postScale(-1, 1);
matrix.postTranslate(mBitmap.getWidth(), 0);
invalidate();
}
}
public void shadow() {
if (mBitmap != null) {
matrix.postScale(1, -1);
matrix.postTranslate(0, mBitmap.getHeight());
invalidate();
}
}
public void skew(float kx, float ky){
if (mBitmap != null) {
matrix.postSkew(kx, ky);
invalidate();
}
}
}