您的位置:首页 > 移动开发 > Android开发

Android自定义View【实战教程】5⃣️---Canvas详解及代码绘制安卓机器人

2017-05-13 15:56 681 查看
友情链接:

Canvas API

Android自定义View【实战教程】3⃣️—-Paint类、Path类以及PathEffect类详解

神马是Canvas

基本概念

Canvas:可以理解为是一个为我们提供了各种工具的画布,我们可以在上面尽情的绘制(旋转,平移,缩放等等)。可以理解为系统分配给我们一个一个内存空间,然后提供了一些对这个内存空间操作的方法(API), 实际存储是在下面的bitmap。

两种画布

这里canvas可以绘制两种类型的画图,分别是view和surfaceView。

View:是普通画图,适合处理量比较小,帧率比较小的动画,比如说象棋游戏之类的。

SurfaceView:主要用在游戏,高品质动画方面的画图。

区别:在SurfaceView中定义一个专门的线程来完成画图工作,应用程序不需要等待View的刷图,提高性能。

Canvas坐标系与绘图坐标系

Canvas绘图中牵扯到两种坐标系:Canvas坐标系与绘图坐标系。

Canvas坐标系

Canvas坐标系指的是Canvas本身的坐标系,Canvas坐标系有且只有一个,且是唯一不变的,其坐标原点在View的左上角,从坐标原点向右为x轴的正半轴,从坐标原点向下为y轴的正半轴。

绘图坐标系

Canvas的drawXXX方法中传入的各种坐标指的都是绘图坐标系中的坐标,而非Canvas坐标系中的坐标。默认情况下,绘图坐标系与Canvas坐标系完全重合,即初始状况下,绘图坐标系的坐标原点也在View的左上角,从原点向右为x轴正半轴,从原点向下为y轴正半轴。但不同于Canvas坐标系,绘图坐标系并不是一成不变的,可以通过调用Canvas的translate方法平移坐标系,可以通过Canvas的rotate方法旋转坐标系,还可以通过Canvas的scale方法缩放坐标系,而且需要注意的是,translate、rotate、scale的操作都是基于当前绘图坐标系的,而不是基于Canvas坐标系,一旦通过以上方法对坐标系进行了操作之后,当前绘图坐标系就变化了,以后绘图都是基于更新的绘图坐标系了。也就是说,真正对我们绘图有用的是绘图坐标系而非Canvas坐标系。

我们看下面代码就可以明白:

@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);

//未平移 在原点
canvas.drawLine(0, 0, width, 0, mPaint);//绘制x轴
canvas.drawLine(0, 0, 0, height, mPaint);//绘制y轴

//第一次移动
canvas.translate(200,200);
canvas.drawLine(0, 0, width, 0, mPaint);//绘制x轴
canvas.drawLine(0, 0, 0, height, mPaint);//绘制y轴

canvas.restore();

//第二次移动并旋转
canvas.translate(200,200);
canvas.rotate(30);
canvas.drawLine(0, 0, width, 0, mPaint);//绘制x轴
canvas.drawLine(0, 0, 0, height, mPaint);//绘制y轴

}


每次绘制同样的(startX, startY,stopX,stopY, paint)线,

但是我们发现平移或者旋转之后画出的线坐标发生了变化



那么有童鞋问了,如果我不想让坐标发生变化,或者再回去原点怎么搞?

别担心,只需要执行canvas.restore(),下面详细讲解。

Canvas保存和还原

canvas.save()

保存当前坐标

canvas.restore()

回复上一次坐标,如果有保存,回到最后一次保存的坐标,如果没保存,则会报错
java.lang.IllegalStateException: Underflow in restore - more restores than saves
,要先存再取。

restoreToCount(int saveCount)

回到第几次的保存坐标状态

对Canvas的操作 — 平移,旋转,缩放

Canvas平移

/**
* 画布向(dx,dy)方向平移
*
* 参数1: 向X轴方向移动dx距离
* 参数2: 向Y轴方向移动dy距离
*/
canvas.translate(float dx, float dy);


Canvas缩放

/**
* 在X轴方向放大为原来sx倍,Y轴方向方大为原来的sy倍
* 默认原点为左上角
* 参数1: X轴的放大倍数
* 参数2: Y轴的放大倍数
*/
canvas.scale(float sx, float sy);

/**
* 在X轴方向放大为原来sx倍,Y轴方向方大为原来的sy倍
* 参数1: X轴的放大倍数
* 参数2: Y轴的放大倍数
* 参数3: 原点X坐标
* 参数4: 原点Y坐标
*/
canvas.scale(float sx, float sy, float px, float py);


Canvas旋转

/**
* 原点为中心,旋转degrees度(顺时针方向为正方向 )
* 参数: 旋转角度
*/
canvas.rotate(float degrees);

/**
* 以(px,py)为中心,旋转30度,顺时针方向为正方向
* 参数1: 旋转角度
* 参数2: 原点X坐标
* 参数3: 原点Y坐标
*/
canvas.rotate(float degrees, float px, float py);


绘制

画文字

/**
* 参数1:输入的内容
* 参数2:文本x轴的位置
* 参数3:文本Y轴的位置
* 参数4:画笔对象
*/
drawText(String text, float x, float y,  Paint paint)

/**
* 参数1:输入的内容
* 参数2:要从第几个字开始绘制
* 参数3:要绘制到第几个文字
* 参数4:文本x轴的位置
* 参数5:文本Y轴的位置
* 参数6:画笔对象
*/
drawText(String text, int start, int end, float x, float y,Paint paint)


样例:

canvas.drawText("开始写字啦!", 200,200,mPaint);
canvas.drawText("开始写字啦!",2,3, 200,400,mPaint);




画圆

/**
* 参数1:圆心X
* 参数2:圆心Y
* 参数3:半径R
* 参数4:画笔对象
*/
drawCircle(float cx, float cy, float radius, Paint paint)


样例:

mPaint.setStyle(Paint.Style.STROKE);
canvas.drawCircle(300,300,80,mPaint);

mPaint.setStyle(Paint.Style.FILL);
canvas.drawCircle(300,500,80,mPaint);

mPaint.setStyle(Paint.Style.FILL_AND_STROKE);
canvas.drawCircle(300,700,80,mPaint);




画线

/*
* 参数1:startX
* 参数2:startY
* 参数3:stopX
* 参数4:stopY
* 参数5:画笔对象
*/
canvas.drawLine(float startX, float startY, float stopX, float stopY,Paint paint);

/*
* 同时绘制多条线。
* 参数1:float数组:每四个一组为一条线。
* 参数2:画笔对象
*/
canvas.drawLines(@Size(multiple=4)float[] pts, Paint paint);


样例:

mPaint.setColor(getResources().getColor(android.R.color.holo_red_dark));
canvas.drawLine(50,50,200,50,mPaint);

mPaint.setColor(getResources().getColor(android.R.color.darker_gray));
canvas.drawLines(new float[]{200,200,300,200,300,300,300,400},mPaint);




画椭圆

/**
* 参数1: 矩形
* 参数2: 画笔
* /
canvas.drawOval(RectF oval, Paint paint);

/**
*  参数1:float left
*  参数2:float top
*  参数3:float right
*  参数4:float bottom
*  参数5:画笔
*/
canvas.drawOval(float left, float top, float right, float bottom, @NonNull Paint paint);


样例:

mPaint.setColor(getResources().getColor(android.R.color.holo_red_dark));
canvas.drawOval(new RectF(50,50,400,400),mPaint);

mPaint.setColor(getResources().getColor(android.R.color.darker_gray));
mPaint.setStyle(Paint.Style.FILL_AND_STROKE);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
canvas.drawOval(50,500,700,700,mPaint);
}




画弧度

/**
*  参数1:RectF对象。
*  参数2:开始的角度。(水平向右为0度顺时针反向为正方向)
*  参数3:扫过的角度
*  参数4:是否和中心连线
*  参数5:画笔对象
*/
canvas.drawArc(RectF oval, float startAngle, float sweepAngle, boolean useCenter,Paint paint);

/**
*  参数1:float left
*  参数2:float top
*  参数3:float right
*  参数4:float bottom
*  参数5:开始的角度。(水平向右为0度顺时针反向为正方向)
*  参数6:扫过的角度
*  参数7:是否和中心连线
*  参数8:画笔对象
*/
canvas.drawArc(float left, float top, float right, float bottom,float startAngle, float sweepAngle, boolean useCenter,Paint paint);


样例:

mPaint.setColor(getResources().getColor(android.R.color.holo_red_dark));
canvas.drawArc(new RectF(50,50,400,400),45,135,true,mPaint);

mPaint.setColor(getResources().getColor(android.R.color.darker_gray));
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
canvas.drawArc(50,500,700,700,45,135,false,mPaint);
}




矩形

/**
*  矩形
*  参数1:float left
*  参数2:float top
*  参数3:float right
*  参数4:float bottom
*  参数5:画笔
*/
canvas.drawRect(float left, float top, float right, float bottom,Paint paint);

/**
*  参数1:矩形
*  参数2:画笔
*/
canvas.drawRectRect r,Paint paint);


样例:

mPaint.setColor(getResources().getColor(android.R.color.darker_gray));
canvas.drawRect(new RectF(50,50,400,400),mPaint);

mPaint.setColor(getResources().getColor(android.R.color.holo_red_dark));
canvas.drawRect(50,500,700,700,mPaint);




圆角矩形

/**
*  参数1:矩形
*  参数2:x半径
*  参数3:y半径
*  参数4: 画笔
*/
drawRoundRect(@NonNull RectF rect, float rx, float ry, @NonNull Paint paint)

/**
*  参数1:float left
*  参数2:float top
*  参数3:float right
*  参数4:float bottom
*  参数5:x半径
*  参数6:y半径
*  参数4: 画笔
*/
drawRoundRect(float left, float top, float right, float bottom, float rx, float ry, @NonNull Paint paint)


样例:

mPaint.setColor(getResources().getColor(android.R.color.darker_gray));
canvas.drawRoundRect(new RectF(50,50,400,400),20,20,mPaint);
mPaint.setColor(getResources().getColor(android.R.color.holo_red_dark));
mPaint.setStyle(Paint.Style.FILL_AND_STROKE);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
canvas.drawRoundRect(50,500,700,700,30,50,mPaint);
}




画点

/**
* 参数1、2:点的x、y坐标
*/
canvas.drawPoint(60, 390, p);//画一个点

/**
* 参数1:多个点,每两个值为一个点。最后个数不够两个的值,忽略。
*/
canvas.drawPoints(new float[]{60,400,65,400,70,400}, p);//画多个点


样例:

mPaint.setColor(getResources().getColor(android.R.color.darker_gray));
canvas.drawPoint(50,50,mPaint);

mPaint.setColor(getResources().getColor(android.R.color.holo_red_dark));
canvas.drawPoints(new float[]{100,100,200,200,300, 300, 400,400,500,500,600,600},mPaint);




画图片

Bitmap bitmap = BitmapFactory.decodeResource(getResources(), R.drawable.ic_launcher);
/**
* 参数1:bitmap对象
* 参数2:图像左边坐标点
* 参数3:图像上边坐标点
*/
canvas.drawBitmap(Bitmap bitmap, float left, float top, Paint paint);


样例:

Bitmap bitmap = BitmapFactory.decodeResource(getResources(), R.mipmap.ic_launcher);
canvas.drawBitmap(bitmap, 200,300, mPaint);




还有问题可以查看Canvas API

到这里基本属性就讲完了,接下来是一个练习。

代码绘制安卓小机器人

下面是代码 , 相当简单,就是计算一下坐标,就不详细讲了,有问题可以留言。

public class AndroidView extends View {

private float bodyWidth;
private float bodyHeigh;

private float armWidth;
private float armHeight;

private float legWidth;
private float legHeight;

private static final int INTERSPACE = 20;

private Paint mPaint;

private RectF bodyRect;
private RectF legRect;
private RectF armRect;

public AndroidView(Context context) {
this(context, null);
}

public AndroidView(Context context, @Nullable AttributeSet attrs) {
this(context, attrs, 0);
}

public AndroidView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);

init();
}

private void init() {
mPaint = new Paint();
mPaint.setColor(getResources().getColor(android.R.color.holo_green_dark));
}

@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);

setBodyParams();

setArmParams();

setLegParams();
}

@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);

canvas.save();

//画身体
canvas.drawRoundRect(bodyRect, 20, 20, mPaint);

//画头
canvas.translate(0, -(bodyWidth / 2 + INTERSPACE));
canvas.drawArc(bodyRect, 0, -180, true, mPaint);

//画左胳膊
canvas.drawRoundRect(armRect, 30, 30, mPaint);

//画右胳膊
canvas.translate(bodyWidth + 5 * INTERSPACE, 0);
canvas.drawRoundRect(armRect, 30, 30, mPaint);

//画左腿
canvas.translate(-(bodyWidth + 7 * INTERSPACE),bodyWidth*11/10);
canvas.drawRoundRect(legRect, 30, 30, mPaint);

//画右腿
canvas.translate(2*INTERSPACE+legWidth,0);
canvas.drawRoundRect(legRect, 30, 30, mPaint);

//画左眼
canvas.translate(0,-bodyHeigh-5*INTERSPACE);
mPaint.setColor(getResources().getColor(android.R.color.white));
canvas.drawCircle(getWidth()/2,getHeight()/2,INTERSPACE/2,mPaint);

//画右眼
canvas.translate(-(2*INTERSPACE+legWidth),0);
mPaint.setColor(getResources().getColor(android.R.color.white));
canvas.drawCircle(getWidth()/2,getHeight()/2,INTERSPACE/2,mPaint);

canvas.restore();
mPaint.setTextSize(60);
mPaint.setColor(getResources().getColor(android.R.color.holo_red_dark));
canvas.drawText("我是安卓小机器人",150,100,mPaint);
}

private void setBodyParams() {
bodyWidth = getWidth() * 2 / 5;
bodyHeigh = bodyWidth;

bodyRect = new RectF();
bodyRect.left = (getWidth() - bodyWidth) / 2;
bodyRect.top = (getHeight() - bodyHeigh) / 2;
bodyRect.right = bodyRect.left + bodyWidth;
bodyRect.bottom = bodyRect.top + bodyHeigh;

}

private void setLegParams() {
legWidth = getWidth() * 1 / 13;
legHeight = getHeight() * 1 / 7;

legRect = new RectF();
legRect.left = (getWidth() - legWidth) / 2;
legRect.top = (getHeight() - legHeight) / 2;
legRect.right = legRect.left + legWidth;
legRect.bottom = legRect.top + legHeight;
}

private void setArmParams() {
armWidth = getWidth() * 1 / 13;
armHeight = getHeight() * 1 / 6;

armRect = new RectF();
armRect.left = (getWidth() - bodyWidth) / 2 - INTERSPACE * 4;
armRect.top = getHeight() / 2 + INTERSPACE * 2;
armRect.right = armRect.left + armWidth;
armRect.bottom = armRect.top + armHeight;
}
}




DEMO下载地址:

http://download.csdn.net/detail/github_33304260/9841552

http://img.blog.csdn.net/20170625220855322?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvZ2l0aHViXzMzMzA0MjYw/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast

扫码关注公众号“伟大程序猿的诞生“,更多干货等着你~

扫码关注公众号“伟大程序猿的诞生“,更多干货等着你~

扫码关注公众号“伟大程序猿的诞生“,更多干货等着你~

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  android api view canvas paint
相关文章推荐