Android自定义View【实战教程】5⃣️---Canvas详解及代码绘制安卓机器人
2017-05-13 15:56
681 查看
友情链接:
Canvas API
Android自定义View【实战教程】3⃣️—-Paint类、Path类以及PathEffect类详解
View:是普通画图,适合处理量比较小,帧率比较小的动画,比如说象棋游戏之类的。
SurfaceView:主要用在游戏,高品质动画方面的画图。
区别:在SurfaceView中定义一个专门的线程来完成画图工作,应用程序不需要等待View的刷图,提高性能。
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坐标系。
我们看下面代码就可以明白:
每次绘制同样的(startX, startY,stopX,stopY, paint)线,
但是我们发现平移或者旋转之后画出的线坐标发生了变化
那么有童鞋问了,如果我不想让坐标发生变化,或者再回去原点怎么搞?
别担心,只需要执行canvas.restore(),下面详细讲解。
Canvas保存和还原
canvas.save()
保存当前坐标
canvas.restore()
回复上一次坐标,如果有保存,回到最后一次保存的坐标,如果没保存,则会报错
restoreToCount(int saveCount)
回到第几次的保存坐标状态
样例:
样例:
样例:
样例:
样例:
样例:
样例:
样例:
样例:
还有问题可以查看Canvas API
到这里基本属性就讲完了,接下来是一个练习。
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
扫码关注公众号“伟大程序猿的诞生“,更多干货等着你~
扫码关注公众号“伟大程序猿的诞生“,更多干货等着你~
扫码关注公众号“伟大程序猿的诞生“,更多干货等着你~
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自定义View【实战教程】4⃣️----BitmapShader详解及圆形、圆角、多边形实现
- Android自定义View【实战教程】1⃣️----attrs.xml详解
- android-自定义ImageView-圆形图片绘制代码详解
- Android 绘图基础:Canvas画布——自定义View基础(绘制表盘、矩形、圆形、弧、渐变)
- Android实战简易教程<十八>(ViewPager组件详解)
- Android 自定义View之Canvas详解
- Android自定义view系列之99.99%实现QQ侧滑删除效果实例代码详解
- 【Android实战】记录自学自定义GifView过程,详解属性那些事!【学习篇】
- Android实战简易教程-第三十二枪(自定义View登录注册界面EditText-实现一键清空)
- Android实战简易教程-第十八枪(ViewPager组件详解)
- Android自定义View高级(二)-Canvas绘制图形
- Android自定义View(五)_Canvas之绘制基本形状
- Android实战简易教程<三十三>(自定义View实现控件晃动提示效果)
- Android自定义View-canvas.drawRect()用法详解
- android自定义View:纯canvas绘制的体重刻度尺
- Android自定义View【实战教程】6⃣️---深入理解 Android 中的 Matrix
- Android简易实战教程--第二十七话《自定义View入门案例之开关按钮详细分析》
- Android入门教程 自定义View详解 真实案例
- Android简易实战教程--第二十七话《自定义View入门案例之开关按钮详细分析》
- Android实战简易教程<三十二>(自定义View登录注册界面EditText-实现一键清空)