自定义View绘图篇(二)-Paint

1、常用方法

方法 描述 方法 描述
setARGB 设置绘制的颜色,a代表透明 setAlpha 设置绘制图形的透明度
setColor 设置绘制的颜色 setAntiAlias 设置是否使用抗锯齿功能,会消耗资源
setDither 是否使用图像抖动处理,图片平滑和清晰 setStyle 设置画笔的样式,如FILL,FILL_OR_STROKE,或STROKE
setStrokeWidth 设置笔刷的粗细度 setStrokeCap 设置笔刷的图形样式, 如圆Cap.ROUND,或方形样式Cap.SQUARE
setFilterBitmap 是否在图像进行动画时滤掉对Bitmap图像的优化操作 setSrokeJoin 设置接合处的状态,MITER(锐角)、ROUND(圆弧)、BEVEL(直线)
setTextSize 设置绘制文字的字号大小 setTextColor 设置文字颜色
setTextAlign 设置绘制文字的对齐方向 setTextScaleX 设置绘制文字x轴的缩放比例
setTextSkewX 设置斜体文字,skewX为倾斜弧度 setUnderlineText 设置带有下划线的文字效果
setStrikeThruText 设置带有删除线的效果 setFakeBoldText 模拟实现粗体文字,设置在小字体上效果会非常差

2、设置字体setTypeface

Typeface:

  • BOLD:加粗

  • ITALIC:斜体

  • BOLD_ITALIC:粗斜体

  • NORMAL:正常

  • DEFAULT:默认正常字体对象

  • DEFAULT_BOLD:默认的字体对象,注意:这实际上不可能是粗体的,这取决于字体设置。 由getStyle()来确定

  • MONOSPACE:monospace 字体风格

  • SANS_SERIF:sans serif字体风格

  • SERIF:serif字体风格

  • 自定义,将我们的TTF文件,防到assets/font/目录下

    Typeface typeFace =Typeface.createFromAsset(getAssets(),"font/MONACO.ttf");

使用:

paint.setTypeface(Typeface.DEFAULT);

3、文字基线

计算文本的垂直方向的中间线与所占布局中间线的偏移量的方法为:

tip 内容引用自https://www.jianshu.com/p/15b8163ee8e7

image

其中baseline为基线,基线以上为负值,以下为正值。即top, ascent为负值,descent, bottom为正值。

image

4、实现滤镜效果setMaskFilter

4.1、BlurMaskFilter(模糊)

构造方法:

BlurMaskFilter(float radius, Blur style)
  • radius:指定模糊边缘的半径;
  • style:指定模糊的风格:
    • BlurMaskFilter.Blur.NORMAL:内外模糊
    • BlurMaskFilter.Blur.OUTER:外部模糊
    • BlurMaskFilter.Blur.INNER:内部模糊
    • BlurMaskFilter.Blur.SOLID:内部加粗,外部模糊
BlurMaskFilter bmf = new BlurMaskFilter(10f, BlurMaskFilter.Blur.OUTER);
paint.setMaskFilter(bmf);
canvas.drawText("我是一段模糊的文本~", 100, 100, paint);

setLayerType(View.LAYER_TYPE_SOFTWARE, null);     //关闭硬件加速

4.2、EmbossMaskFilter(浮雕)

通过指定环境光源的方向和环境光强度来添加浮雕效果,是图片更具与立体效果

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

  • direction:浮点型数组,用于控制x,y,z轴的光源方向
  • ambient:设置环境光亮度,0到1之间
  • specular:镜面反射系数
  • blurRadius:模糊半径
float[] direction = new float[]{ 1, 1, 3 };   // 设置光源的方向
float light = 0.4f;     //设置环境光亮度
float specular = 8;     // 定义镜面反射系数
float blur = 3.0f;      //模糊半径
EmbossMaskFilter emboss=new EmbossMaskFilter(direction,light,specular,blur);
paint.setMaskFilter(emboss);
canvas.drawText("我是一段具有浮雕效果的文本~", 100, 100, paint);

setLayerType(View.LAYER_TYPE_SOFTWARE, null);     //关闭硬件加速

5、图形重叠处理setXfermode

注意事项:

关闭硬件加速

再API 11后,在程序集中加入了对GPU的支持,而当我们的targetSdkVersion >= 14以上版本都是默认开启硬件加速的,而有些函数是不支持硬件加速的,因此需要关闭,关闭方式有以下三种:

  • Application:在配置文件的application节点添加: android:hardwareAccelerated="true"
  • Activity:在配置文件的activity节点添加 android:hardwareAccelerated="false"
  • 可以获得View对象后调用,或者直接在View的onDraw()方法里设置:
    view.setLayerType(View.LAYER_TYPE_HARDWARE, null);

使用离屏缓冲

saveLayer绘图流程:

这是因为在调用saveLayer时,会生成了一个全新的bitmap,这个bitmap的大小就是我们指定的保存区域的大小,新生成的bitmap是全透明的,在调用saveLayer后所有的绘图操作都是在这个bitmap上进行的。若没有设置,我们先把整个画布给染成了绿色,然后再画上了一个圆形,所以在应用xfermode来画源图像的时候,目标图像当前Bitmap上的所有图像了,也就是整个绿色的屏幕和一个圆形了。所以这时候源图像的相交区域是没有透明像素的,透明度全是100%,即saveLayer是为了区分哪一步的图形应该与合成模式和Bitmap去合成。

 int saved = canvas.saveLayer(null, null, Canvas.ALL_SAVE_FLAG);
 canvas.restoreToCount(saved);

处理方式:

这里涉及2个概念:源图像(SRC):图上黄色圆形,目标图形(DST):图上蓝色矩形。先设置重叠处理模式,再绘制时先绘制源图像,再绘制目标图形,会形成下面不同结果。

  • CLEAR:所绘制不会提交到画布上,会清除图像
  • SRC:显示上层绘制图片
  • DST:显示下层绘制图片
  • SRC_OVER:正常绘制显示,上下层绘制叠盖,正常显示。
  • DST_OVER:上下层都显示,下层居上显示。
  • SRC_IN:取两层绘制交集,显示上层(常用)。
  • DST_IN:取两层绘制交集,显示下层(常用)。
  • SRC_OUT:取上层绘制非交集部分(常用)。
  • DST_OUT:取下层绘制非交集部分(常用)。
  • SRC_ATOP:取下层非交集部分与上层交集部分
  • DST_ATOP:取上层非交集部分与下层交集部分
  • XOR:上层与下层交集部分不绘制
  • DARKEN:变暗,较深的颜色覆盖较浅的颜色,若两者深浅程度相同则混合
  • LIGHTEN:变亮,与DARKEN相反,DARKEN和LIGHTEN生成的图像结果与Android对颜色值深浅的定义有关
  • MULTIPLY:正片叠底,下层图像素颜色值乘以上层图像素颜色值除以255得到混合后图像像素颜色值
  • SCREEN:滤色,色调均和,保留两个图层中较白的部分,较暗的部分被遮盖

5.1、实现刮刮卡

思路:

  1. 使用Canvas绘制背景,以及展示给用户的中奖信息。
  2. 创建一个Bitmap用于保存给予用户展示的灰色层以及处理用户触摸path路径的交互。
  3. 将bitmap绘制Canvas中达到效果。

tip:做一个遮盖层,然后随着用户的刮开透明,完整代码:快速传送门

6、设置渐变

 setShader(Shader shader) 

6.1、线性渐变

LinearGradient(float x0, float y0, float x1, float y1, int color0, int color1, Shader.TileMode tile) 。

参数:

  • x0,y0,x1,y1:渐变的两个端点的位置`

  • color0,color1:是端点的颜色

  • tile:端点范围之外的着色规则

    • CLAMP:延续渐变
    • MIRROR:镜像渐变
    • REPEAT:重复渐变
    Shader shader= new LinearGradient(0,60,100,60, Color.BLUE,
      Color.RED, Shader.TileMode.CLAMP);
    mPaint.setShader(shader);
    canvas.drawRect(0,0,300,150,mPaint);
    
    Shader shader1= new LinearGradient(0,160,100,160, Color.BLUE,
      Color.RED, Shader.TileMode.MIRROR);
    mPaint.setShader(shader1);
    canvas.drawRect(0,200,300,350,mPaint);
    
    Shader shader2= new LinearGradient(0, 460, 100, 460, Color.BLUE,
      Color.RED, Shader.TileMode.REPEAT);
    mPaint.setShader(shader2);
    canvas.drawRect(0, 400, 300, 550,mPaint);
    

6.2、辐射渐变

中心向周围辐射状的渐变

RadialGradient(float centerX, float centerY, float radius, int centerColor, int edgeColor, TileMode tileMode)。

参数:

  • centerX centerY:辐射中心的坐标
  • radius:辐射半径
  • centerColor:辐射中心的颜色
  • edgeColor:辐射边缘的颜色
  • tileMode:辐射范围之外的着色模式。

6.3、扫描渐变

SweepGradient(float cx, float cy, int color0, int color1)

参数:
cx cy :扫描的中心
color0:扫描的起始颜色
color1:扫描的终止颜色

Shader shader = new SweepGradient(300, 300, Color.BLUE, Color.RED);
        mPaint.setShader(shader);
        canvas.drawCircle(300, 300, 200, mPaint);

6.4、BitmapShader

Bitmap 的像素来作为图形或文字的填充

BitmapShader(Bitmap bitmap, Shader.TileMode tileX, Shader.TileMode tileY)

参数:

  • bitmap:用来做模板的 Bitmap 对象
  • tileX:横向的 TileMode
  • tileY:纵向的 TileMode
Bitmap bitmap = BitmapFactory.decodeResource(getResources(), R.mipmap.scratch);
        Shader shader = new BitmapShader(bitmap, Shader.TileMode.CLAMP, Shader.TileMode.CLAMP);
mPaint.setShader(shader);
canvas.drawCircle(300, 300, 200, mPaint);
1539423445652.png

7、路径样式

设置路径样式

setPathEffect(PathEffect effect)

7.1、圆形拐角效果

CornerPathEffect(float radius)

参数:

  • 拐角圆的半径
path.moveTo(100, 100);
path.lineTo(200,200);
path.lineTo(400, 100);
path.lineTo(400, 400);
path.lineTo(600, 100);
mPaint.setPathEffect(new CornerPathEffect(100));
canvas.drawPath(path, mPaint);

7.2、虚线效果

DashPathEffect(float intervals[], float phase)

参数:

  • intervals[]:组成虚线的各个线段的长度(长度必须大于等于2,个数必须为偶数
  • phase:开始绘制的偏移值
//.........
mPaint.setPathEffect(new DashPathEffect(new float[]{5,5},2));
canvas.drawPath(path, mPaint);

7.3、离散路径效果

DiscretePathEffect(float segmentLength, float deviation)

参数:

  • segmentLength:示将原来的路径切成多长的线段,值越小,切得线段也越多
  • deviation:表示被切成的每个小线段的可偏移距离
//.......
mPaint.setPathEffect(new DiscretePathEffect(4,5));
canvas.drawPath(path, mPaint);

7.4、Path形状效果

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

参数:

  • shape:表示印章路径,如三角,点等;

  • advance:表示两个印章路径间的距离,很容易理解,印章间距离越大,间距就越大。

  • phase:路径绘制偏移距离

  • style:表示在遇到转角时,如何操作印章以使转角平滑过渡,取值有:Style.ROTATE(旋转)、Style.MORPH(变形)、Style.TRANSLATE(位移);

path.moveTo(100, 100);
path.lineTo(200,200);
path.lineTo(400, 100);
path.lineTo(400, 400);
path.lineTo(600, 100);

Path stampPath = new Path();
stampPath.moveTo(0, 20);
stampPath.lineTo(10, 0);
stampPath.lineTo(20, 20);
stampPath.close();
stampPath.addCircle(0, 0, 3, Path.Direction.CCW);

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

推荐阅读更多精彩内容

  • 本文是自定义View的第二篇,主要学习:Paint第一篇地址Android自定义View(一) -- 初识 本文计...
    T9的第三个三角阅读 4,023评论 2 26
  • 系列文章之 Android中自定义View(一)系列文章之 Android中自定义View(二)系列文章之 And...
    YoungerDev阅读 2,165评论 0 4
  • 自定义绘制 自定义绘制的方式是重写绘制方法,其中最常用的是 onDraw() 绘制的关键是 Canvas 的使用C...
    android小菜鸡一枚阅读 776评论 1 1
  • 今天,值得纪念的一天。这么说,对我来说一定不是什么好事。说白了,是我来到这所学校哭的最惨的一次。竟然不是因为亲情、...
    还要遇见好天气阅读 388评论 0 0
  • 早上,迷迷糊糊听到爸爸在隔壁问妈妈:“虹到学校去了吗?”,顿时清醒,拿起手机一看才六点四十。一下子想起高中时期,闹...
    七颜子阅读 112评论 1 0