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

  • Post author:
  • Post category:其他



许多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的一些小知识的理解和使用。



版权声明:本文为shan286原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。