自定义控件——Paint画笔

前言

在前面一篇 自定义控件——Canvas 画布,我们也看到如何使用Paint。Paint也是强大的工具类,这篇就来详细介绍。

Paint的API也非常多,具体可以参考官方网址:
Paint API:https://developer.android.google.cn/reference/android/graphics/Paint.html
这里根据这些API分为4种模式:(参考 HenCoder ),主要是便于总结与记忆,不用过于纠结。自己总结一张思维导图:

这里写图片描述

API的使用

1.初始化方法

Paint 构造函数:

Paint()
Paint(int flags) //参考 setFlags

reset()

将画笔恢复到默认设置

set(Paint src)

将src的所有属性复制过来。

setFlags(int flags)

设置画笔的属性

参数:flags的值有很多,就不一一介绍。
demo:

mPaint.setTextSize(20);
mPaint.setFlags(Paint.UNDERLINE_TEXT_FLAG);//设置带下划线的文本
canvas.drawText("厉害了,我的国!!!",200,200,mPaint);

和下面的效果是一样的:

mPaint.setUnderlineText(true);//设置带下划线的文本

2.颜色方法

Paint对于颜色的处理,有多种模式,相关的例子也比较多,这里单独在另一篇介绍。

3.效果方法

setStyle(Style style)

画笔填充模式

参数:
style:设置画笔的样式,有三个值:

  1. FILL(0):单独填充
  2. STROKE (1):单独描边,和画笔宽有关
  3. FILL_AND_STROKE (2):填充并描边,比如圆形,画出来的图像的半径为:原有半径+笔宽

如图所示:(注:有些可能没有效果,是因为画笔宽度太小,不明显)

图片描述

setStrokeWidth(float width)

设置画笔的笔触宽度

图片描述

setStrokeCap(Paint.Cap cap)

设置画笔的笔帽风格

其值有以下3种:

  1. BUTT (0):在画笔的头部和尾部不添加笔帽,默认值;
  2. ROUND (1):在画笔的头部和尾部添加半圆形笔帽;
  3. SQUARE (2):在画笔的头部和尾部添加方形笔帽;
    图片描述

setStrokeJoin(Paint.Join join)

设置画笔的转弯处的连接风格,使用时画笔样式不能为 FILL

join的值有以下3种:

  1. MITER (0):转弯处为锐角
  2. ROUND (1):转弯处为圆弧
  3. BEVEL (2):转弯处为直线
    图片描述

setStrokeMiter (float miter)

设置连接处的倾斜度,参数值必须>=0,miter 的默认值是 4。使用时画笔样式不能为 FILL

这个方法是对setStrokeJoin( )方法的补充,当join = MITER 时,设置 MITER 型拐角的延长线的最大值。

以下介绍引用这里: 这里
当线条拐角为 MITER 时,拐角处的外缘需要使用延长线来补偿。示意图如下:

图片描述

而这种补偿方案会有一个问题:如果拐角的角度太小,就有可能由于出现连接点过长的情况。比如这样:

图片描述

所以为了避免意料之外的过长的尖角出现,MITER型连接点有一个额外的规则:当尖角过长时,自动改用 BEVEL的方式来渲染连接点。例如上图的这个尖角,在默认情况下是不会出现的,而是会由于延长线过长而被转为 BEVEL 型连接点:

图片描述

至于多尖的角属于过于尖,尖到需要转为使用BEVEL来绘制,则是由一个属性控制的,而这个属性就是 setStrokeMiter(miter) 方法中的 miter 参数。miter 参数是对于转角长度的限制,具体来讲,是指尖角的外缘端点和内部拐角的距离与线条宽度的比。也就是下面这两个长度的比:

图片描述

用几何知识得出这个比值的计算公式:如果拐角的大小为 θ ,那么这个比值就等于:

miter = 1 / sin ( θ / 2 )

在这里,miter越大,θ则越小;那么就可能会出现尖角过长的情况。miter 的默认值是 4 ,对应的是一个大约 29° 的锐角

例子:

    mTestPaint.setStyle(Paint.Style.STROKE); //设置画笔风格,只描边

    float miter = mPaint.getStrokeMiter();
    Path path4  = new Path();
    path4.moveTo(100,680);
    path4.lineTo(250,680);
    path4.lineTo(100,780);
    path4.lineTo(100,670);
    canvas.drawPath(path4, mTestPaint);

    Path path5  = new Path();
    mTestPaint.setStrokeMiter(100f);
    path5.moveTo(500,680);
    path5.lineTo(650,680);
    path5.lineTo(350,740);
    path5.close();//闭环
    canvas.drawPath(path5, mTestPaint);

    Path path6  = new Path();
    mTestPaint.setStrokeMiter(2f);
    path6.moveTo(200,880);
    path6.lineTo(450,880);
    path6.lineTo(350,980);
    path6.close();//闭环
    canvas.drawPath(path6, mTestPaint);

图片描述

结论:设置miter,得到一个角度,大于这个角的尖角会被保留,而小于这个夹角的就会被「削成平头」

setAntiAlias(boolean aa)

设置抗锯齿,默认没有设置

图片描述

setDither(boolean dither)

图片颜色更加平滑和饱满,图像更加清晰 ,减少视觉伪影

对于现在的配置来说,setDither(dither) 没有明细效果。默认的色彩深度已经是 32 位的 ARGB_8888
,效果已经足够清晰了。对于16 位色的 ARGB_4444 或者 RGB_565 的时候,开启它才会有比较明显的效果。

setFilterBitmap(boolean filter)

设置是否使用双线性过滤来绘制 Bitmap,貌似也没怎么用到。

setShadowLayer

在图层下方绘制阴影

构造函数:

setShadowLayer (float radius, float dx, float dy, int shadowColor)

参数:

radius:阴影半径,值越大,越模糊,等于0时,则没有阴影;
dx、dy:阴影偏移量,可为正负
shadowColor:阴影的颜色

使用:(在文本方面使用的比较多)

mPaint.reset();
mPaint.setStrokeWidth(30);
mPaint.setTextSize(80);
mPaint.setShadowLayer(10, 5, 5, Color.BLUE);
canvas.drawText("M-Ellen", 100, 300, mPaint);

图片描述

如想清除阴影,可以使用clearShadowLayer()方法。

需要注意的是:

1.设置阴影一般是用在绘制文本上,如果是绘制其他,需要关闭硬件加速;
2.参数shadowColor如果是带透明度的颜色值,那么阴影部分的透明度取shadowColor的值;如果shadowColor是不透明的,那么阴影部分的透明度取Paint的值,但阴影的颜色值与Paint无关。

setMaskFilter (MaskFilter maskfilter)

设置发光阴影 。该方法与setShadowLayer ()类似,同样设置阴影效果,功能却强大很多,对图片的设置也非常好。

参数:
maskfilter:MaskFilter 对象,有2个子类:BlurMaskFilter, EmbossMaskFilter。
下面就介绍这2个类的使用。

BlurMaskFilter
构造函数:

BlurMaskFilter(float radius, BlurMaskFilter.Blur style)

参数:
radius:阴影模糊半径,同上
style:模糊方式,有4种,如下:

INNER:向内部模糊,外部不绘制
OUTER:向外部模糊,内部不绘制(内部为空心)
NORMAL:内部、外部都模糊
SOLID:外部模糊,内部正常绘制(内部为实心)

使用:这里写一个小demo,分别再文字、图形、图片上的效果:

private void testMaskFilter(Canvas canvas){
mPaint.reset();
mPaint.setColor(Color.RED);
mPaint.setTextSize(80);

MaskFilter maskFilter = new BlurMaskFilter(50, BlurMaskFilter.Blur.INNER);
//        MaskFilter maskFilter = new BlurMaskFilter(100, BlurMaskFilter.Blur.OUTER);
//        MaskFilter maskFilter = new BlurMaskFilter(100, BlurMaskFilter.Blur.NORMAL);
//        MaskFilter maskFilter = new BlurMaskFilter(150, BlurMaskFilter.Blur.SOLID);

//        mPaint.setMaskFilter(maskFilter);

canvas.translate(0, 350);
canvas.drawCircle(300,0,150,mPaint);

canvas.translate(0, 300);
canvas.drawBitmap(BitmapFactory.decodeResource(getResources(),R.mipmap.d),100,0, mPaint);

}

private void testMaskFilter1(Canvas canvas){
canvas.drawColor(Color.BLACK);
mTestPaint.reset();
mTestPaint.setColor(Color.RED);
mTestPaint.setTextSize(100);
mTestPaint.setFakeBoldText(true);

//        canvas.drawText("原始图片", 100, 100, mTestPaint);

MaskFilter maskFilter = new BlurMaskFilter(10, BlurMaskFilter.Blur.INNER);
//        MaskFilter maskFilter = new BlurMaskFilter(10, BlurMaskFilter.Blur.OUTER);
//        MaskFilter maskFilter = new BlurMaskFilter(10, BlurMaskFilter.Blur.NORMAL);
//        MaskFilter maskFilter = new BlurMaskFilter(30, BlurMaskFilter.Blur.SOLID);

mTestPaint.setMaskFilter(maskFilter);

canvas.drawText("Blur.INNER", 100, 100, mTestPaint);
//        canvas.drawText("Blur.OUTER", 100, 100, mTestPaint);
//        canvas.drawText("Blur.NORMAL", 100, 100, mTestPaint);
//        canvas.drawText("Blur.SOLID", 100, 100, mTestPaint);

}

注意,这里需要选择合适的模糊半径。上面例子中,由于,模糊半径过大,会导致文字消失,所以文字单独绘制。

为了使效果更明显,这里背景色为黑色,效果图如下:

图片描述

图片描述

看起来是不是觉的像发光效果一样?是的,在黑色背景下,类似有内部发光、外部发光,说是发光其实是相对被模糊的部分。但在白色背景就没有那么明显了。

EmbossMaskFilter

具有浮雕效果的模糊(具体也不知道是个啥)

构造函数:

EmbossMaskFilter(float[] direction, float ambient, float specular, float blurRadius)

官方显示:在API P 不再使用。所以这里只是显示下效果图:

图片描述

setPathEffect(PathEffect effect)

设置图形线条的样式,如设置线条为虚线

该方法的介绍,具体使用在另一篇介绍哦!

4.文本相关方法

Paint的API中,文本相关的是最多的了。同样,这里也单独在另外一篇详细介绍。

结束

距离上一篇总结,到现在已经过去很久,唉,惭愧(假装)!
这一篇由于篇幅很多,分了很多小模块单独介绍,后面会努力将这些小模块补上的。
嗯,会的!

猜你喜欢

转载自blog.csdn.net/pzm1993/article/details/81051892