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

参考:

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

基本用法

基本设置函数

  • reset() 重置画笔
  • setColor(int color) 给画笔设置颜色值
  • setARGB(int a, int r, int g, int b) 同样是设置颜色,但是利用ARGB分开设置
  • setAlpha(int a) 设置画笔透明度
  • setStyle(Paint.Style style) 设置画笔样式,取值有
    • Paint.Style.FILL :填充内部
    • Paint.Style.FILL_AND_STROKE :填充内部和描边
    • Paint.Style.STROKE :仅描边
  • setStrokeWidth(float width) 设置画笔宽度
  • setAntiAlias(boolean aa) 设置画笔是否抗锯齿

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

其他设置函数

  • setStrokeCap(Paint.Cap cap) 设置线冒样式,取值有:
    • Cap.ROUND(圆形线冒);
    • Cap.SQUARE(方形线冒)
    • Cap.BUTT(无线冒)
  • setStrokeJoin(Paint.Join join) 设置线段连接处样式,取值有:
    • Join.MITER(结合处为锐角);
    • Join.Round(结合处为圆弧);
    • Join.BEVEL(结合处为直线)
  • setStrokeMiter(float miter) 设置笔画的倾斜度
  • setPathEffect(PathEffect effect) 设置路径样式;取值类型是所有PathEffect的子类:
    • ComposePathEffect;
    • CornerPathEffect;
    • DashPathEffect;
    • DiscretePathEffect,
    • PathDashPathEffect,
    • SumPathEffect

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[]:表示组成虚线的各个线段的长度;整条虚线就是由intervals[]中这些基本线段循环组成的。比如,我们定义new float[] {20,10};那这个虚线段就是由两段线段组成的,第一个可见的线段长为20,每二个线段不可见,长度为10;
  • 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) 

参数说明:

  • segmentLength:表示将原来的路径切成多长的线段。如果值为2,那么这个路径就会被切成一段段由长度为2的小线段。所以这个值越小,所切成的小线段越多;这个值越大,所切成的小线段越少。
  • 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)  

参数说明:

  • Path shape:表示印章路径;
  • float advance:表示两个印章路径间的距离,间隙;
  • float phase:路径绘制偏移距离,与DashPathEffect中的phase参数意义相同;
  • Style style:表示在遇到转角时,如何操作印章以使转角平滑过渡,取值有:
    • Style.ROTATE: 表示通过旋转印章来过渡转角
    • Style.MORPH: 表示通过变形印章来过渡转角
    • Style.TRANSLATE: 表示通过位移来过渡转角

示例代码:

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 ;

文字设置相关函数

常用文字设置相关函数

  • setTextSize(float textSize) 设置文字大小
  • setFakeBoldText(boolean fakeBoldText) 设置是否为粗体文字
  • setStrikeThruText(boolean strikeThruText) 设置带有删除线效果
  • setUnderlineText(boolean underlineText) 设置下划线
  • setTextAlign(Paint.Align align) 设置开始绘图点位置
  • setTextScaleX(float scaleX) 水平拉伸设置
  • setTextSkewX(float skewX) 设置字体水平倾斜度,普通斜体字是-0.25,可见往右斜
  • setTypeface(Typeface typeface)

之前都有接触过;

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 206,839评论 6 482
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 88,543评论 2 382
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 153,116评论 0 344
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 55,371评论 1 279
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 64,384评论 5 374
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,111评论 1 285
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,416评论 3 400
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,053评论 0 259
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 43,558评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,007评论 2 325
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,117评论 1 334
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,756评论 4 324
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,324评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,315评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,539评论 1 262
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,578评论 2 355
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,877评论 2 345