1.通过坐标变换矩阵 去改变图像的形状大小位置等 (9位 float)
A B C
D E F
G H I --> AE控制缩放,CF控制平移, BD控制错切
2. android API操作
matrix.setRote(); -- 旋转
matrix.setTranslate() -- 平移
matrix.setScale() -- 缩放
matrix.setSkew() -- 错切
post -- 矩阵组合
3. 通过画笔风格实现不同图形特效 -Xfermode
PorterDuff.Mode为枚举类,一共有16个枚举值:
1.PorterDuff.Mode.CLEAR
所绘制不会提交到画布上。
2.PorterDuff.Mode.SRC
显示上层绘制图片
3.PorterDuff.Mode.DST
显示下层绘制图片
4.PorterDuff.Mode.SRC_OVER
正常绘制显示,上下层绘制叠盖。
5.PorterDuff.Mode.DST_OVER
上下层都显示。下层居上显示。
6.PorterDuff.Mode.SRC_IN
取两层绘制交集。显示上层。
7.PorterDuff.Mode.DST_IN
取两层绘制交集。显示下层。
8.PorterDuff.Mode.SRC_OUT
取上层绘制非交集部分。
9.PorterDuff.Mode.DST_OUT
取下层绘制非交集部分。
10.PorterDuff.Mode.SRC_ATOP
取下层非交集部分与上层交集部分
11.PorterDuff.Mode.DST_ATOP
取上层非交集部分与下层交集部分
12.PorterDuff.Mode.XOR
异或:去除两图层交集部分
13.PorterDuff.Mode.DARKEN
取两图层全部区域,交集部分颜色加深
14.PorterDuff.Mode.LIGHTEN
取两图层全部,点亮交集部分颜色
15.PorterDuff.Mode.MULTIPLY
取两图层交集部分叠加后颜色
16.PorterDuff.Mode.SCREEN
取两图层全部区域,交集部分变为透明色
事例 做一个四周有圆角的图形:
public class RoundRectXfermodeView extends View {
private Bitmap mBitmap;
private Bitmap mOut;
private Paint mPaint;
public RoundRectXfermodeView(Context context) {
super(context);
initView();
}
public RoundRectXfermodeView(Context context, AttributeSet attrs) {
super(context, attrs);
initView();
}
public RoundRectXfermodeView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
initView();
}
private void initView() {
setLayerType(LAYER_TYPE_SOFTWARE, null); // 要禁用 硬件加速
mBitmap = BitmapFactory.decodeResource(getResources(), R.drawable.test1);
mOut = Bitmap.createBitmap(mBitmap.getWidth(),
mBitmap.getHeight(),
Bitmap.Config.ARGB_8888);
Canvas canvas = new Canvas(mOut);
mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
// Dst 遮罩层
canvas.drawRoundRect(0, 0, mBitmap.getWidth(), mBitmap.getHeight(),
50, 50, mPaint);
mPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_IN)); // 设置画笔的 xfermode属性为 src_in
// Src
canvas.drawBitmap(mBitmap, 0, 0, mPaint);
mPaint.setXfermode(null);
}
@Override
protected void onDraw(Canvas canvas) {
canvas.drawBitmap(mOut, 0, 0, null);
}
}
4. 画笔风格- shader 着色器/渲染器
图像渐变: BitmapShader
public BitmapShader(Bitmap bitmap,Shader.TileMode tileX,Shader.TileMode tileY)
调用这个方法来产生一个画有一个位图的渲染器(Shader)。
bitmap 在渲染器内使用的位图
tileX The tiling mode for x to draw the bitmap in. 在位图上X方向渲染器平铺模式
tileY The tiling mode for y to draw the bitmap in. 在位图上Y方向渲染器平铺模式
TileMode:
CLAMP :如果渲染器超出原始边界范围,会复制范围内边缘染色。
REPEAT :横向和纵向的重复渲染器图片,平铺。
MIRROR :横向和纵向的重复渲染器图片,这个和REPEAT重复方式不一样,他是以镜像方式平铺。
示例:
package com.tony.shader;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapShader;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.Shader;
import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.ShapeDrawable;
import android.graphics.drawable.shapes.OvalShape;
import android.util.AttributeSet;
import android.view.View;
public class BitmapShaderView extends View {
private BitmapShader bitmapShader = null;
private Bitmap bitmap = null;
private Paint paint = null;
private ShapeDrawable shapeDrawable = null;
private int BitmapWidth = 0;
private int BitmapHeight = 0;
public BitmapShaderView(Context context) {
super(context);
// 得到图像
bitmap = ((BitmapDrawable) getResources().getDrawable(R.drawable.cat))
.getBitmap();
BitmapWidth = bitmap.getWidth();
BitmapHeight = bitmap.getHeight();
// 构造渲染器BitmapShader
bitmapShader = new BitmapShader(bitmap, Shader.TileMode.MIRROR,Shader.TileMode.REPEAT);
}
public BitmapShaderView(Context context,AttributeSet set) {
super(context, set);
}
@Override
protected void onDraw(Canvas canvas) {
// TODO Auto-generated method stub
super.onDraw(canvas);
//将图片裁剪为椭圆形
//构建ShapeDrawable对象并定义形状为椭圆
shapeDrawable = new ShapeDrawable(new OvalShape());
//得到画笔并设置渲染器
shapeDrawable.getPaint().setShader(bitmapShader);
//设置显示区域
shapeDrawable.setBounds(20, 20,BitmapWidth-140,BitmapHeight);
//绘制shapeDrawable
shapeDrawable.draw(canvas);
}
}
5. 像素块 drawBitmapMesh
public class MeshView extends View {
private int WIDTH = 200;
private int HEIGHT = 200;
private int COUNT = (WIDTH + 1) * (HEIGHT + 1);
private float[] verts = new float[COUNT * 2];
private float[] orig = new float[COUNT * 2];
private Bitmap mBitmap;
private float K = 1;
public MeshView(Context context) {
super(context);
initView();
}
public MeshView(Context context, AttributeSet attrs) {
super(context, attrs);
initView();
}
public MeshView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
initView();
}
private void initView() {
int index = 0;
mBitmap = BitmapFactory.decodeResource(getResources(), R.drawable.test);
float bmWidth = mBitmap.getWidth();
float bmHeight = mBitmap.getHeight();
for (int i = 0; i < HEIGHT + 1; i++) {
float fy = bmHeight * i / HEIGHT;
for (int j = 0; j < WIDTH + 1; j++) {
float fx = bmWidth * j / WIDTH;
orig[index * 2 + 0] = verts[index * 2 + 0] = fx;
orig[index * 2 + 1] = verts[index * 2 + 1] = fy + 200;
index += 1;
}
}
}
@Override
protected void onDraw(Canvas canvas) {
for (int i = 0; i < HEIGHT + 1; i++) {
for (int j = 0; j < WIDTH + 1; j++) {
verts[(i * (WIDTH + 1) + j) * 2 + 0] += 0;
float offsetY = (float) Math.sin((float) j / WIDTH * 2 * Math.PI + K * 2 * Math.PI);
verts[(i * (WIDTH + 1) + j) * 2 + 1] =
orig[(i * (WIDTH + 1) + j) * 2 + 1] + offsetY * 50;
}
}
K += 0.1F;
canvas.drawBitmapMesh(mBitmap, WIDTH, HEIGHT,
verts, 0, null, 0, null);
invalidate();
}
}