Android开发——自定义准备工作以及绘制

2020.8.20

一.引言

自定义控件分为自定义View和ViewGroup两种,一个控件的创建都会经历onMeasure、onLayout、onDraw三个阶段,但View和ViewGroup各有特色

  • 自定义View
    1.onMeasure
    2.onDraw
  • 自定义ViewGroup
    1.onMeasure
    2.onLayout

对于View,不需要重写onLayout方法,ViewGroup不需要重写onDraw

二.以自定义View为例重写构造方法

此处以自定义View为例,首先我们需要创建一个类,让它继承View,并添加构造方法,通常添加一下三种构造方法

class testView:View {
    //在代码中创建
    constructor(context: Context):super(context){}
    //在xml中创建
    constructor(context: Context,attr: AttributeSet):super(context,attr){}
    //需要使用到style
    constructor(context: Context,attr: AttributeSet,style:Int):super(context,attr,style){}
}

三.重写onDraw进行绘制主体内容

按照流程,应先重写onMeasure方法,但本片文章主要介绍自定义绘制,onMeasure将在另外一篇文章中详写

绘画的4个基础内容

  1. Bitmap 图片
  2. Canvas 绘制类->可以理解成一块画板
        提供了各种绘制方法
  3. Paint 画笔->设置画笔的样式
  4. Path 用于设置绘制的路径
1.绘制背景颜色
override fun onDraw(canvas: Canvas?) {
        setBackgroundColor(Color.MAGENTA)
    }

除了使用系统提供的颜色外,还可以使用自己手动创建的颜色
通过Color.parseColor("#B990E7")来实现
具体使用实例:setBackgroundColor(Color.parseColor("#B990E7"))

2.画圆

drawCircle(圆心x,圆心y,raduis,paint)
需要提前准备好圆心坐标以及半径和画笔
注:onDraw方法会被多次调用,所以尽量不要在这个方法里面创建对象(变量),最好设置为属性

  • onSizeChanged()->此方法是在onMeasure之后调用,也就是说,我们可以在此获取控件的宽高,这点很重要,比如我们需要绘制一个图形,该图形的大小以空间的宽高为参考,所以我们在此方法中对图形绘制所需要的尺寸进行赋值
var cx = 0f
    var cy = 0f
    var radius = 0f
    var mWidth = 0
    var mHeight = 0
    val mPaint = Paint().apply { 
        color = Color.MAGENTA
        style = Paint.Style.STROKE
        strokeWidth=3f
    }
    override fun onSizeChanged(w: Int, h: Int, oldw: Int, oldh: Int) {
        mWidth = measuredWidth
        mHeight = measuredHeight
        //获取半径大小
        radius = if (mWidth>mHeight) mHeight/2f else mWidth/2f
        //设置圆心
        cx = mWidth/2f
        cy = mHeight/2f
    }
    override fun onDraw(canvas: Canvas?) {
        canvas?.drawCircle(cx,cy,radius,mPaint)
    }
  • 画笔-Paint
    color 设置颜色
    style 设置填充方式
       Paint.Style.STROKE 描边
       Paint.Style.FILL 全填充
       Paint.Style.FILL_AND_STROKE 填充+描边
    strokeWidth 设置画笔粗细(float类型)
  • 设置画笔颜色
    1.除了使用系统提供的和前面写到的Color.parseColor("#B990E7")来设置颜色外,还可以使用setARGB()来设置,四个参数,A代表透明度(255不透明,0全透明),RGB即对应了红绿蓝三原色的深度,范围都是0-255
    setARGB(100,175,202,253)
    2.着色器shader
    子类1:LinearGradient-线性渐变
       起始点(x0,y0),终点(x1,y1),color0-color1渐变色
       tile:Shader.TileMode->CLAMP 边缘色拉伸
                 REPEAT 重复
                 MIRROR 倒影
    子类2:BitmapShader-用一张图片作为颜色进行绘制
    子类3:RadialGradient-发射式
    子类3:SweepGradient-扫射式

使用示例

shader=LinearGradient(
            mWidth/2f,0f,mWidth/2f,mHeight.toFloat(),
            Color.GREEN,Color.MAGENTA,Shader.TileMode.CLAMP
        )
----------------------------------------------------------------------------------------
 val img = BitmapFactory.decodeResource(resources,R.drawable.wiwi)
  shader=BitmapShader(img,Shader.TileMode.CLAMP,Shader.TileMode.CLAMP)

小贴士:将画笔颜色设置为图片搭配画圆可以实现圆形头像

3.drawBitmap

将一张图片绘制到控件中,这和上面的画笔以图片为颜色是不相同的,画笔以图片为颜色绘制是平铺的,不可设置位置,不够灵活,并且依赖于你选择绘制的形状,而drawBitmap是独立的元素将图片添加到控件中,各有各的好处

private val pic:Bitmap by lazy {
        BitmapFactory.decodeResource(resources,R.drawable.alipay)
    }
 canvas?.drawBitmap(pic,0f,0f,mPaint)

通过设置左边和上边与控件的距离来控制绘制的区域

4.drawPath与drawLine

画一条线只需要起点和终点的坐标即可
drawLine(startX,startY,endX,endY,paint),但如果需要连续画线的话,drawLine就显得太笨拙了,让代码更加冗杂,此时就需要用到drawPath

  • drawPath(path,paint)
    绘制路径只需要设置path,并且path还可动态修改
  • Path() 路径
    moveTo(x,y) 移动到某一点,并作为下一条线的起点
    lineTo(x,y) 画到某点,作为终点
5.绘制贝塞尔曲线

drawPath不仅可以画直线,还可画曲线,只需要设置路径即可

  • quadTo(x1,y1,x2,y2)
    (x1,y1)为控制点,(x2,y2)是终点,这是2阶贝塞尔,该方法同moveTo一样在path内部设置
  • cubicTo(x1,y1,x2,y2,x3,y3)
    中间过程多一个控制点的坐标,就会多一个阶数


    贝塞尔图解.png

绘制曲线可以设计出很多新奇的图案,只需计算好控制点的坐标即可

6.画圆弧

画圆弧有两种方式,一是使用path路径中的arcTo,二是drawArc()
两者都需要确定绘制圆弧的矩形区域以及扫过的角度(圆弧对应的角度)
不同之处,arcTo在path内部,不需要设置画笔,圆心的确定使用moveTo,因此arcTo依赖于drawPath,而drawArc是独立的


arcTo.png

drawArc.png

可以看到drawArc画出来的效果更好,绘制圆弧有个前提,你给出的区域必须是一个正方形区域rect

  • arcTo
val path = Path().apply {
        moveTo(500f,400f)
        val rect = RectF(100f,10f,900f,800f)
        arcTo(rect,0f,-90f)
    }
  • drawArc(left,top,right,bottom,startAngle,sweepAngle,是否使用中心点,paint)
    下图是使用中心点的效果


    useCenter.png

可以根据自己的需求来设置是否使用中心点
同理画圆也可以通过path路径来设置

  • addCircle(x,y,radius,方向)
    CW 顺时针
    CCW 逆时针
    addCircle(600f,400f,100f,Path.Direction.CW)
7.画圆角矩形

为了给后面的小Demo做铺垫,这里介绍一下绘制圆角矩形
drawRoundRect(left,top,right,bottom,rx,ry)
这里重点说明rx,ry两个参数,它们是用来控制四角的弧度


roundRect.png
rx图解.png

小结:基本的绘制如上文所示,自定义动画是建立在自定义控件的基础上的,可以说自定义控件就是用来自定义动画,手动实现系统没有的控件以及动画效果,所以接下来会将两者融合详讲,并以项目来巩固知识点

你可能感兴趣的:(Android开发——自定义准备工作以及绘制)