自定义控件初学篇——onDraw()方法

简介: 许多APP上都会有一些比较酷炫美观的动画效果和自定义控件,所以最近研究了一下,又遇到一些疑惑和问题,所以这里记录一下。 自定义控件经常会要提到三个方法,也就是onLayout(),onMeasure()和onDraw()。

许多APP上都会有一些比较酷炫美观的动画效果和自定义控件,所以最近研究了一下,又遇到一些疑惑和问题,所以这里记录一下。

自定义控件经常会要提到三个方法,也就是onLayout(),onMeasure()和onDraw()。今天我暂时先讲一下自己对onDraw()方法的学习。

首先我们自定义一个MyView1继承于View类,然后会自动提示我们添加一些方法,这些就不细说了。

在这些提示的方法里面有一个方法:

public MyView1(Context context, AttributeSet attrs, int defStyleAttr) {}
首先我在这个方法里面新建了一个TypeArray对象,通过它来获得MyView1的一些自定义属性。这里我们要新建一个xml格式的文件。
里面的代码如下:
 
<declare-styleable name="MyView1">
    <attr name="left_circle_radius" format="dimension" />
    <attr name="left_circle_color" format="color" />
    <attr name="top_circle_radius" format="dimension" />
    <attr name="top_circle_color" format="color" />
    <attr name="right_circle_radius" format="dimension" />
    <attr name="right_circle_color" format="color" />
    <attr name="bottom_circle_radius" format="dimension" />
    <attr name="bottom_circle_color" format="color" />
</declare-styleable>
其实也就是定义这个View中需要用到的一些属性,需要注意的是记得写上format的类型,至于为什么,后面我会讲到。在这个View里面我定义了四个圆的半径和颜色。
然后在代码里面我们要获得它们,这里要注意的是获得它们必须是“declare-styleable的name+ attr的name”,例如上面的“MyView1_left_circle_radius",这应该是他们固定的一种格式,不这么写的话会报错的。
除了获得这些属性外,我们还要实例化Paint类的对象。
 
mPaint = new Paint();
mPaint.setAlpha(180); // 透明度
mPaint.setStrokeWidth(2); // 画笔宽度
mPaint.setAntiAlias(true); // 消除锯齿
mPaint.setTextAlign(Paint.Align.CENTER); // 文字居中
上面是Paint类比较常用的几种方法,注释写的很仔细了,所以就不再赘述了。

接下来说onDraw()方法,看到这个方法,大家就知道它跟绘画有关。

onDraw()方法中有一个Canvas类,也就是画布的意思。Canvas类有许多绘画的方法,比如
画圆调用canvas的
drawCircle(left, top, radius, paint);
方法中的属性分别对应要绘制的这个圆最左侧的横坐标,最上侧的纵坐标,半径,和画笔。
画直线调用canvas的             
drawLine(left, top, right, bottom, paint)
方法中的属性也就是这条直线左上右下的四个坐标点,因为宽度已经被paint的setStrokeWidth()方法给固定了。
 画虚线稍微比他们复杂一些,要用到PathEffect类,下面有具体的注释。
PathEffect effects = new DashPathEffect(new float[]{1,2,4,8},1); // 绘制长度1的实线,再绘制长度2的空白,再绘制长度4的实线,再绘制长度8的空白
 

接下来附上本人写的demo的部分代码:

 
mPaint.setColor(Color.CYAN);
canvas.drawLine(getWidth() - getWidth() / 5 * 4 + 40, getHeight() / 2, getWidth() - getWidth() / 5 - 40, getHeight() / 2, mPaint); // 划线,左,上,右,下,画笔
mPaint.setColor(leftCircleColor);
/**
 * 1.Paint.Style.STROKE:描边
 * 2.Paint.Style.FILL_AND_STROKE:描边并填充
 * 3.Paint.Style.FILL:填充
 * 默认FILL
 */
mPaint.setStyle(Paint.Style.FILL_AND_STROKE);
canvas.drawCircle(getWidth() - getWidth() / 5 * 4, getHeight() / 2, leftCircleRadius, mPaint); // 画圆,左,上,半径,画笔
PathEffect effects = new DashPathEffect(new float[]{1,2,4,8},1); // 绘制长度1的实线,再绘制长度2的空白,再绘制长度4的实线,再绘制长度8的空白
mPaint.setPathEffect(effects);
mPaint.setColor(topCircleColor);
mPaint.setStyle(Paint.Style.STROKE);
canvas.drawCircle(getWidth() / 2, getHeight() - getHeight() / 5 * 4, topCircleRadius, mPaint);
canvas.drawCircle();
最后就是在Activity里面使用这个MyView1了,首先自然是像那些普通控件一样在activity_main.xml中定义,代码如下:

 
<com.xue.myview1.MyView1
    android:id="@+id/myview1_main"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    xue:left_circle_color="#00FF00"
    xue:left_circle_radius="30dp"
    xue:top_circle_color="#303F9F"
    xue:top_circle_radius="30dp"
    xue:right_circle_color="#FF4081"
    xue:right_circle_radius="30dp"
    xue:bottom_circle_color="#FFFF00"
    xue:bottom_circle_radius="30dp"/>
,然后在Activity定义MyView1的对象并找到就好了。

然而,在开发完成的时候遇到了下面这个问题:

Error:Execution failed for task ':app:processDebugResources'.
> com.android.ide.common.process.ProcessException: org.gradle.process.internal.ExecException: Process 'command 'D:\adt-bundle-windows-x86_64-20140624\sdk\build-tools\23.0.1\aapt.exe'' finished with non-zero exit value 1
这个问题困扰了我几个小时,刚开始的时候以为是

xmlns:xue="http://schemas.android.com/apk/res-auto"这条语句的问题,可是把res-auto换成对应的包名还是没有用,也仔细查看过语句,可是由于报错的信息中没有定位到错误的地方。最后还是解决了,我发现是导致这个报错的原因如下:
1、xml文件中"xue:"后面定义的属性和attrs中的属性有出入;
2、"30dp"和”#000000"和属性的类型有出入,开始的时候没有写format="color"和format="dimension",而代码中定义的是

private int leftCircleColor = Color.WHITE;
private float leftCircleRadius = 40.0f;

leftCircleColor = a.getColor(attr, leftCircleColor);
leftCircleRadius = a.getDimension(attr, leftCircleRadius);

这就是我初次学习自定义View的一些小知识的理解和使用。

目录
相关文章
|
7月前
|
XML Android开发 数据格式
自定义View之重写onMeasure
自定义View之重写onMeasure
64 0
|
XML Android开发 数据格式
进入Activity时,为何页面布局内View#onMeasure会被调用两次?
进入Activity时,为何页面布局内View#onMeasure会被调用两次?
|
7月前
自定义View实现点击事件
自定义View实现点击事件
49 2
|
7月前
|
前端开发
自定义View绘制基础之Canvas
自定义View绘制基础之Canvas
67 0
|
Windows
C#-利用自定义控件绘制一个箭头控件
利用自定义控件绘制一个箭头控件
698 0
|
Android开发
【RecyclerView】 八、RecyclerView.ItemDecoration 条目装饰 ( onDraw 和 onDrawOver 绘制要点 )(二)
【RecyclerView】 八、RecyclerView.ItemDecoration 条目装饰 ( onDraw 和 onDrawOver 绘制要点 )(二)
159 0
【RecyclerView】 八、RecyclerView.ItemDecoration 条目装饰 ( onDraw 和 onDrawOver 绘制要点 )(二)
|
前端开发 容器
【RecyclerView】 八、RecyclerView.ItemDecoration 条目装饰 ( onDraw 和 onDrawOver 绘制要点 )(一)
【RecyclerView】 八、RecyclerView.ItemDecoration 条目装饰 ( onDraw 和 onDrawOver 绘制要点 )(一)
402 0
【RecyclerView】 八、RecyclerView.ItemDecoration 条目装饰 ( onDraw 和 onDrawOver 绘制要点 )(一)
|
前端开发 Android开发
【RecyclerView】 六、RecyclerView.ItemDecoration 条目装饰 ( 简介 | onDraw | onDrawOver | getItemOffsets )
【RecyclerView】 六、RecyclerView.ItemDecoration 条目装饰 ( 简介 | onDraw | onDrawOver | getItemOffsets )
189 0
|
前端开发 API Android开发
3.3 自定义控件基础 之 View的绘制
当测量好了一个View之后,我们就可以简单地重写onDraw()方法,并在Canvas对象上来绘制所需要的图形。首先我们来了解一下利用系统2D绘图API所必须要使用到的Canvas对象。
679 0
自定义控件基础 之 3.4 ViewGroup的测量 & 3.5 ViewGroup的绘制
ViewGroup的测量 之前分析中说了,ViewGroup会去管理其子View,其中一个管理项目就是负责子View的显示大小。当ViewGroup的大小为wrap_content时,ViewGroup就需要对子View进行遍历,以便获得所有子View的大小,从而来决定自己的大小。
708 0