Android(安卓)自定义View之View的绘制
相关文章:Android自定义View之View的测量
之前讲了自定义View View的测量一部分,很好掌握吧?
但是View的测量只能控制View的大小,如果想定制外观,就要靠View的绘制。
View的绘制是要重写View 的 OnDraw方法
public class MyView extends View{public MyView(Context context) {super(context);}@Overrideprotected void onDraw(Canvas canvas){}}
我们再看一下View类中 onDraw的源码
/** * Implement this to do your drawing. * * @param canvas the canvas on which the background will be drawn */ protected void onDraw(Canvas canvas) { }
是空的~ 也就是什么也没绘制 所以我们上一篇文章测试时候的View,就是一个没有图形的View。
可能有人会说,上一篇文章,最后明明显示是一个矩形!
但是实际上,呢只是因为View的边界包裹起来本身是个矩形,这和View的绘制是两码事
绘制,就是好像,View是一张矩形的纸,我们在这个纸上画画
View的绘制,我们使用Canvas ,Paint ,Path三个类就可以基本完成各种图形了
Canvas:
我直接先把Canvas提供的绘制方法放出来,大家看一下
方法签名 | 简要说明 |
---|---|
drawLine(float startX, float startY, float stopX, float stopY, Paint paint) | 绘制一条直线 |
drawLines(float[] pts, int offset, int count, Paint paint) | 绘制多条直线 |
drawCircle(float cx, float cy, float radius, Paint paint) | 绘制一个圆 |
drawOval(RectF oval, Paint paint) | 绘制一个椭圆 |
drawPath(Path path, Paint paint) | 根据路径绘制任意形状 |
drawPoint(float x, float y, Paint paint) | 绘制一个点 |
drawPoints(float[] pts, int offset, int count, Paint paint) | 绘制多个点 |
drawRect(float left, float top, float right, float bottom, Paint paint) | 绘制矩形 |
drawRoundRect(RectF rect, float rx, float ry, Paint paint) | 绘制圆角矩形 |
drawText(String text, int start, int end, Paint paint) | 绘制字符串 |
drawTextOnPath(参数太多,表格放不下了,需要自己查吧...) | 沿着路径绘制字符串 |
clipRect(float left, float top, float right, float bottom) | 剪切一个矩形区域 |
clipRegion(Region region) | 剪切制定区域 |
drawArc(参数太多,表格放不下了,需要自己查吧...) | 绘制弧 |
drawBitmap(Bitmap bitmap, rect src, Rect dst, Paint paint) | 绘制从源位图"挖取“的一块 |
drawBitmap(Bitmap bitmap, float left, float top, Paint paint) | 绘制位图 |
上表的各种方法具体使用不一一赘述了,大家看参数和简要说明应该就明白了,实在不懂可以搜索一下,具体用法我可能以后再开一篇总结吧~
我们上表就可以看出,Canvas就是提供给我们绘制基本图形的方法,复杂的图形也就是靠这些组合起来的~
此外,Canvas还提供了坐标变换的方法(Canvas的坐标原点在View的左上角,坐标轴方向遵循Android坐标系)
方法签名 | 简要说明 |
---|---|
rotate(float degrees, float px, float py) | 旋转变换 |
scale(float sx, float sy, float px, float py) | 缩放变换 |
skew(float sx, float sy) | 倾斜变换 |
translate(float dx, float dy) | 移动坐标原点 |
我们也可以看出,Canvas的使用,离不开 Paint,下面我们看一下Pait的方法
Paint
Paint 就好像生活中的画笔一样
setARGB(int a, int r, int g, int b) | 设置颜色 |
setAlpha(int a) | 设置透明度 |
setAntiAlias(boolean aa) | 设置是否抗锯齿 |
setColor(int color) | 设置颜色 |
setPathEffect(PathEffect effect) | 设置绘制路径时的路径效果 |
setShader(Shader shader) | 设置画笔的填充效果 |
setShadowLayer(float radius, float dx, float dy, int color) | 设置阴影 |
setStrokeWidth(float width) | 设置画笔的笔尖宽度 |
setStrokeJoin(Paint.Join join) | 设置画笔转弯处的连接风格 |
setStyle(Paint.Style style) | 设置Pain的填充风格 |
setTextAlign(Paint.Align align) | 设置绘制文本时的文字对齐方式 |
setTextSize(float textSize) | 设置绘制文本时的文字大小 |
根据方法的简要说明,很清晰明了吧~
具体使用,自己试一试就更清楚啦~
下面我们直接上手做一个复合图形吧
效果图如下
就是一个常见的钟表盘(你会发现这个钟表盘的数字有点问题,接下来我们来看看实现代码就明白这个问题是怎么回事啦)
import android.content.Context;import android.graphics.Canvas;import android.graphics.Paint;import android.util.AttributeSet;import android.view.View;public class Clock extends View{public Clock(Context context, AttributeSet attrs) {super(context, attrs);}public Clock(Context context) {super(context);}@Overrideprotected void onDraw(Canvas canvas){// 画外圆Paint paintCircle = new Paint();paintCircle.setStyle(Paint.Style.STROKE);//设置抗锯齿,防止缩放变换后图片出现锯齿边缘paintCircle.setAntiAlias(true);paintCircle.setStrokeWidth(5);//getWidth() 和 getHeight()是View自己的方法 获取View的宽和高//我们画一个以View中心点为圆心,半径为View宽度一半的圆//从这个函数参数的传递,我们也可以看出,Canvas的坐标原点在View左上角canvas.drawCircle(this.getWidth()/2, this.getHeight()/2, this.getWidth()/2, paintCircle);//画刻度的画笔Paint paintDegree = new Paint();paintDegree.setTextAlign(Paint.Align.CENTER);//从0点(12点)开始画刻度for(int i = 0; i < 12; i ++){//区分特殊点if(i == 0 || i == 3 || i == 6 || i == 9){//特殊的刻度,线更长,笔尖宽度更大paintDegree.setStrokeWidth(5);paintDegree.setTextSize(30);//大家自己琢磨一下这个线的起点和终点吧canvas.drawLine(this.getWidth()/2, this.getHeight()/2 - this.getWidth()/2, this.getWidth()/2, this.getHeight()/2 - this.getWidth()/2 + 60, paintDegree);String clockTime = null;//表盘上一般都把0点显示为12点if(i == 0)clockTime = String.valueOf(i + 12);elseclockTime = String.valueOf(i);canvas.drawText(clockTime, this.getWidth()/2, this.getHeight()/2 - this.getWidth()/2 + 90, paintDegree);}else{paintDegree.setStrokeWidth(3);paintDegree.setTextSize(15);canvas.drawLine(this.getWidth()/2, this.getHeight()/2 - this.getWidth()/2, this.getWidth()/2, this.getHeight()/2 - this.getWidth()/2 + 30, paintDegree);String clockTime = String.valueOf(i);canvas.drawText(clockTime, this.getWidth()/2, this.getHeight()/2 - this.getWidth()/2 + 60, paintDegree);}//这个地方,我们就用到了旋转坐标系的方法来达到每30度角画一个刻度//注意,这个是旋转坐标系!并不是旋转画布,也就是说,单独执行这个方法,你看不到任何效果的!canvas.rotate(30, this.getWidth()/2,this.getHeight()/2);}}//这里我们没有重写onMeasureprotected void onMeasure(int widthMeasureSpec, int heightMeasureSpec){super.onMeasure(widthMeasureSpec, heightMeasureSpec);}}
代码注释的比较清楚,唯一就是旋转坐标系这个我想还是再强调一下。 因为当时自己开始以为是旋转画布,调用后,并没有变化。
而就是因为坐标系旋转了,所以我们呢个6点,就倒过来了,像9一样。
最后在xml文件中引用这个布局就可以了
项目源码AndroidOnDraw
更多相关文章
- 一起学android openg 纹理
- Android实例练习-可爱的小闹钟
- Linux设置qt-android开发环境
- Android39_Clock和TimePicker
- Android(安卓)Material Design之CardView(卡片式布局)
- Android自学——ListView
- Android(安卓)Kotlin项目集成阿里ARouter
- Android:保存图片到Sqlite数据库
- Android官方提供的支持不同屏幕大小的全部方法