自定义控件之canvas变换和裁剪
1.平移
//构造两个画笔,一个红色,一个绿色 Paint paint_green = generatePaint(Color.GREEN, Paint.Style.STROKE, 3); Paint paint_red = generatePaint(Color.RED, Paint.Style.STROKE, 3); //构造一个矩形 Rect rect1 = new Rect(0,0,400,220); //在平移画布前用绿色画下边框 canvas.drawRect(rect1, paint_green); //平移画布后,再用红色边框重新画下这个矩形 canvas.translate(100, 100); canvas.drawRect(rect1, paint_red);
2.旋转
Paint paint_green = generatePaint(Color.GREEN, Paint.Style.FILL, 5); Paint paint_red = generatePaint(Color.RED, Paint.Style.STROKE, 5); Rect rect1 = new Rect(300,10,500,100); canvas.drawRect(rect1, paint_red); //画出原轮廓 canvas.rotate(30);//顺时针旋转画布 canvas.drawRect(rect1, paint_green);//画出旋转后的矩形
3.缩放
Paint paint_green = generatePaint(Color.GREEN, Paint.Style.STROKE, 5); Paint paint_red = generatePaint(Color.RED, Paint.Style.STROKE, 5); Paint paint_yellow = generatePaint(Color.YELLOW, Paint.Style.STROKE, 5); Rect rect1 = new Rect(10,10,200,100); canvas.drawRect(rect1, paint_green); canvas.scale(0.5f, 1); canvas.drawRect(rect1, paint_red);
4.扭曲
Paint paint_green = generatePaint(Color.GREEN, Paint.Style.STROKE, 5); Paint paint_red = generatePaint(Color.RED, Paint.Style.STROKE, 5); Rect rect1 = new Rect(10,10,200,100); canvas.drawRect(rect1, paint_green); canvas.skew(1.732f,0);//X轴倾斜60度,Y轴不变 canvas.drawRect(rect1, paint_red);
5.裁剪
canvas.drawColor(Color.RED); //保存的画布大小为全屏幕大小 int c1 = canvas.save(); canvas.clipRect(new Rect(100, 100, 800, 800)); canvas.drawColor(Color.GREEN); //保存画布大小为Rect(100, 100, 800, 800) int c2 = canvas.save(); canvas.clipRect(new Rect(200, 200, 700, 700)); canvas.drawColor(Color.BLUE); //保存画布大小为Rect(200, 200, 700, 700) int c3 = canvas.save(); canvas.clipRect(new Rect(300, 300, 600, 600)); canvas.drawColor(Color.BLACK); //保存画布大小为Rect(300, 300, 600, 600) int c4 = canvas.save(); canvas.clipRect(new Rect(400, 400, 500, 500)); canvas.drawColor(Color.WHITE); //连续出栈三次,将最后一次出栈的Canvas状态作为当前画布,并画成黄色背景 canvas.restoreToCount(c2); canvas.drawColor(Color.YELLOW);
获取画笔方法
private Paint generatePaint(int color,Paint.Style style,int width){ Paint paint = new Paint(); paint.setColor(color); paint.setStyle(style); paint.setStrokeWidth(width); return paint; }
画布的保存和恢复
canvas.save()
canvas.restore();
save()每次调用save函数,都会先保存画布的状态,然后将其放入特定的栈中
restore()都会把栈中顶层的画布状态取出来,并按照这个状态恢复当前的画布,然后在这个画布上作画
restoreToCount函数
restoreToCount(int saveCount)
int c2 = canvas.save();//返回栈的索引 canvas.restoreToCount(c2);//根据索引返回当前画布
示例代码-圆形代码
public class BasisView extends View { private Bitmap mBmp; private Paint mPaint; private Path mPath; public BasisView(Context context) { super(context); init(); } public BasisView(Context context, @Nullable AttributeSet attrs) { super(context, attrs); init(); } public BasisView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); init(); } private void init(){ setLayerType(LAYER_TYPE_SOFTWARE,null); mBmp = BitmapFactory.decodeResource(getResources(), R.drawable.avator); mPaint = new Paint(); mPath = new Path(); int width = mBmp.getWidth(); int height = mBmp.getHeight(); mPath.addCircle(width/2,height/2,width/2, Path.Direction.CCW); } @Override protected void onDraw(Canvas canvas) { super.onDraw(canvas); canvas.save(); canvas.clipPath(mPath); canvas.drawBitmap(mBmp,0,0,mPaint); canvas.restore(); } }
裁剪动画
package com.loaderman.customviewdemo.paint; import android.content.Context; import android.graphics.Bitmap; import android.graphics.BitmapFactory; import android.graphics.Canvas; import android.graphics.Paint; import android.graphics.Path; import android.graphics.RectF; import android.graphics.Region; import android.support.annotation.Nullable; import android.util.AttributeSet; import android.view.View; import com.loaderman.customviewdemo.R; public class BasisView extends View { private Path mPath; private Bitmap mBitmap; private int clipWidth = 0; private int width; private int heigth; private static final int CLIP_HEIGHT = 30; private Region mRgn; public BasisView(Context context) { super(context); init(); } public BasisView(Context context, @Nullable AttributeSet attrs) { super(context, attrs); init(); } public BasisView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); init(); } private void init() { setLayerType(LAYER_TYPE_SOFTWARE, null); mBitmap = BitmapFactory.decodeResource(getResources(), R.drawable.avator); width = mBitmap.getWidth(); heigth = mBitmap.getHeight(); mRgn = new Region(); mPath=new Path(); } @Override protected void onDraw(Canvas canvas) { mRgn.setEmpty(); int i = 0; while (i * CLIP_HEIGHT <= heigth) { if (i % 2 == 0) { mPath.addRect(new RectF(0, i * CLIP_HEIGHT, clipWidth, (i + 1) * CLIP_HEIGHT),Path.Direction.CCW); } else { mPath.addRect(new RectF(width - clipWidth, i * CLIP_HEIGHT, width, (i + 1) * CLIP_HEIGHT),Path.Direction.CCW); } i++; } canvas.clipPath(mPath); canvas.drawBitmap(mBitmap, 0, 0, new Paint()); if (clipWidth > width) { return; } clipWidth += 5; invalidate(); } }
效果:
最后,关注【码上加油站】微信公众号后,有疑惑有问题想加油的小伙伴可以码上加入社群,让我们一起码上加油吧!!!