自定义控件绘制(Paint函数汇总)篇五

2018-04-06  本文已影响136人  zhaoyubetter

参考:

  1. https://blog.csdn.net/harvic880925/article/details/51010839

基本用法

基本设置函数

以上函数,我们基本上都用过了;

其他设置函数

setStrokeCap

设置线帽样式,什么叫做线帽,看下面图示:

val paint = Paint(Paint.ANTI_ALIAS_FLAG).apply {
    strokeWidth = 80f
    color = Color.GREEN
    style = Paint.Style.STROKE
}

paint.strokeCap = Paint.Cap.BUTT        // 无线帽
canvas.drawLine(100f, 200f, 400f, 200f, paint)

paint.strokeCap = Paint.Cap.SQUARE      // 方形
canvas.drawLine(100f, 400f, 400f, 400f, paint)

paint.strokeCap = Paint.Cap.ROUND       // 圆形
canvas.drawLine(100f, 600f, 400f, 600f, paint)

paint.strokeWidth = 2f
paint.color = Color.RED
canvas.drawLine(100f, 0f, 100f, height.toFloat(), paint)
图片来自源博客

从无线冒出来的那块区域就是线帽!就相当于给原来的直线加上一个帽子一样,所以叫线帽;

Android 目前只有3种线帽子;

setStrokeJoin(Paint.Join join)

设置线段连接处样式;

val paint = Paint(Paint.ANTI_ALIAS_FLAG).apply {
    strokeWidth = 40f
    color = Color.GREEN
    style = Paint.Style.STROKE
}

Path().let {
    it.moveTo(100f, 100f)
    it.lineTo(200f, 100f)
    it.lineTo(100f, 200f)
    paint.strokeJoin = Paint.Join.MITER     // 锐角
    canvas.drawPath(it, paint)

    it.moveTo(100f, 300f)
    it.lineTo(200f, 300f)
    it.lineTo(100f, 400f)
    paint.strokeJoin = Paint.Join.BEVEL     // 结合处为直线
    canvas.drawPath(it, paint)

    it.moveTo(100f, 500f)
    it.lineTo(200f, 500f)
    it.lineTo(100f, 600f)
    paint.strokeJoin = Paint.Join.ROUND     // 结合处为圆弧
    canvas.drawPath(it, paint)
}
效果图

从图上看,BEVELROUND并没有明显区别;

setPathEffect

设置路径样式;取值类型是所有派生自PathEffect的子类;

1. CornerPathEffect-圆形拐角效果
将原来Path生硬的直线拐角,变成圆形拐角,从下图示

图片来自源博客

CornerPathEffect构造:

// radius 当前连接两条直线所使用的圆的半径
public CornerPathEffect(float radius)  
来自源博客,说明radius

上图为利用半径R=50的圆来代替原来两条直线间的夹角;

示例代码:

val paint = Paint(Paint.ANTI_ALIAS_FLAG).apply {
    strokeWidth = 2f
    color = Color.GREEN
    style = Paint.Style.STROKE
}

Path().let {
    it.moveTo(100f,600f)
    it.lineTo(400f,100f)
    it.lineTo(700f,900f)
    canvas.drawPath(it, paint)

    paint.pathEffect = CornerPathEffect(100f)       // radius = 100f
    canvas.drawPath(it, paint.apply { color = Color.BLACK })

    paint.pathEffect = CornerPathEffect(200f)
    canvas.drawPath(it, paint.apply { color = Color.RED })
}
不同radius的CornerPathEffect效果

2. DashPathEffect——虚线效果

功能能够实现虚线段的效果,如下图:


图片来自源博客

DashPathEffect构造

public DashPathEffect(float intervals[], float phase)  

参数:

intervals 的 长度必须大于等于2;必须有一个实线段和一个空线段来组成虚线,个数必须为偶数,如果是基数,最后一个数字将被忽略;

Path().let {
    it.moveTo(100f, 600f)
    it.lineTo(400f, 100f)
    it.lineTo(700f, 900f)
    canvas.drawPath(it, paint)

    // 第一条实线长度为20,第二个空线长度为10,第三个实线长为100,第四条空线长充为100
    paint.pathEffect = DashPathEffect(floatArrayOf(20f, 10f, 100f, 100f), 0f)
    canvas.translate(0f, 100f)
    canvas.drawPath(it, paint.apply { color = Color.BLACK })

    // 设置偏移值
    paint.pathEffect = DashPathEffect(floatArrayOf(20f, 10f, 50f, 100f), 15f)
    canvas.translate(0f, 100f)
    canvas.drawPath(it, paint.apply { color = Color.RED })
}
效果图

注意上面蓝色箭头,因为第二条,开始偏移了15f,所以开始是5了,明显缩短了;

让线动起来(不断改变 偏离量 phase);

// 20f, 10f, 100f, 100f 和为 230
val valueAnim1 = ValueAnimator.ofFloat(0f, 230f).apply {
    duration = 1000
    repeatMode = ValueAnimator.RESTART
    repeatCount = ValueAnimator.INFINITE
    interpolator = LinearInterpolator()
    addUpdateListener {
        path1Phase = it.animatedValue as Float
        postInvalidate()
    }
}

// 区间为(15, -165), 15 + 165 = 180
val valueAnim2 = ValueAnimator.ofFloat(15f, -165f).apply {
    duration = 2000
    repeatMode = ValueAnimator.RESTART
    repeatCount = ValueAnimator.INFINITE
    interpolator = LinearInterpolator()
    addUpdateListener {
        e("size: ${path2Phase}")
        path2Phase = it.animatedValue as Float
        postInvalidate()
    }
}

// 联合动画
AnimatorSet().apply {
    play(valueAnim1).with(valueAnim2)
}.start()

3.DiscretePathEffect——离散路径效果
如下图,图中第一条线是原生的,第二条线加上离散路径效果后的样式;
DiscretePathEffect就是将原来路径分隔成定长的线段,然后将每条线段随机偏移一段位置; Discrete 离散的;

图片来自源博客

DiscretePathEffect构造:

public DiscretePathEffect(float segmentLength, float deviation) 

参数说明:

示例代码:

override fun onDraw(canvas: Canvas) {
    super.onDraw(canvas)
    val paint = Paint(Paint.ANTI_ALIAS_FLAG).apply {
        strokeWidth = 2f
        color = Color.GREEN
        style = Paint.Style.STROKE
    }

    val path = getPath()
    // 原始
    canvas.drawPath(path,paint)

    canvas.translate(0f, 200f)
    paint.pathEffect = DiscretePathEffect(2f, 5f)
    canvas.drawPath(path,paint)

    canvas.translate(0f, 200f)
    paint.pathEffect = DiscretePathEffect(6f, 5f)
    canvas.drawPath(path,paint)

    canvas.translate(0f, 200f)
    paint.pathEffect = DiscretePathEffect(6f, 15f)
    canvas.drawPath(path,paint)
}

private fun getPath(): Path {
    return Path().apply {
        moveTo(0f, 0f)
        for (i in 0..40) {
            lineTo(i * 35f, (Math.random() * 150).toFloat())
        }
    }
}
效果

4. PathDashPathEffect——印章路径效果
用另一个路径图案做为印章,沿着指定路径一个个盖上去;

构造函数:

public PathDashPathEffect(Path shape, float advance, float phase,Style style)  

参数说明:

示例代码:

override fun onDraw(canvas: Canvas) {
        super.onDraw(canvas)
        val paint = Paint(Paint.ANTI_ALIAS_FLAG).apply {
            strokeWidth = 2f
            color = Color.GREEN
            style = Paint.Style.STROKE
        }

        val path = getPath()
        canvas.drawPath(path, paint)

        canvas.translate(0f, 200f)
        paint.pathEffect = PathDashPathEffect(getDashPath(), 30f, 0f, PathDashPathEffect.Style.MORPH)
        canvas.drawPath(path, paint.apply { color = Color.RED })

        canvas.translate(0f, 200f)
        paint.pathEffect = PathDashPathEffect(getDashPath(), 30f, 0f, PathDashPathEffect.Style.TRANSLATE)
        canvas.drawPath(path, paint.apply { color = Color.RED })

        canvas.translate(0f, 200f)
        paint.pathEffect = PathDashPathEffect(getDashPath(), 30f, 0f, PathDashPathEffect.Style.ROTATE)
        canvas.drawPath(path, paint.apply { color = Color.RED })
    }
    // 三角形
    private fun getDashPath(): Path {
        return Path().apply {
            moveTo(10f, 10f)
            lineTo(20f, 10f)
            lineTo(15f, 20f)
            close()
        }
    }
效果

注意转弯处,的变型

5. ComposePathEffect与SumPathEffect
用来合并两个特效的,但有区别;

// 有先后顺序的,将第二个参数的innerpe的特效作用于路径上
// 然后再在此加了特效的路径上,再加第一个参数dashEffect特效。
public ComposePathEffect(PathEffect outerpe, PathEffect innerpe) 

// 对原始路径分别作用第一个特效和第二个特效。然后再将这两条路径合并,做为最终结果。 
public SumPathEffect(PathEffect first, PathEffect second)  

示例代码:

// 原始
val path = getPath()
canvas.drawPath(path, paint)

// 圆角特效
canvas.translate(0f, 150f)
val cornerEffect = CornerPathEffect(100f)
paint.pathEffect = cornerEffect
canvas.drawPath(path, paint.apply { color = Color.RED })

// 虚线特效
canvas.translate(0f, 150f)
val dashEffect = DashPathEffect(floatArrayOf(2f, 5f, 10f, 10f), 0f)
paint.pathEffect = dashEffect
canvas.drawPath(path, paint.apply { color = Color.RED })

// 利用ComposePathEffect先应用圆角特效,再应用虚线特效
canvas.translate(0f, 150f)
paint.pathEffect = ComposePathEffect(dashEffect, cornerEffect) //位置交换就只有dashEffect效果
canvas.drawPath(path, paint)

// 利用SumPathEffect,分别将圆角特效应用于原始路径,然后将生成的两条特效路径合并
canvas.translate(0f, 150f)
paint.pathEffect = SumPathEffect(cornerEffect, dashEffect)
canvas.drawPath(path, paint)
效果图

说明:
特别注意路径D和路径E:
路径D的生成方法为:

ComposePathEffect(dashEffect, cornerEffect) //位置交换就只有dashEffect效果

表示先将圆角特效应用于原始路径,得到路径B,然后再在路径B的基础上应用虚线特效得到最终的效果D;
尝试交换参数位置时,居然只有dashEffect效果了;

路径E的生成方法为:

SumPathEffect(cornerEffect, dashEffect)  // 参数位置可交换

先将圆角特效应用于原始路径A得到路径B,然后将虚线特效应依然应用于原始路径,得到路径C. 然后将路径B和路径C合并(即画在一起),就得到路径E ;

文字设置相关函数

常用文字设置相关函数

之前都有接触过;

上一篇下一篇

猜你喜欢

热点阅读