一切的开始:onDraw()
自定义绘制的上手非常容易:提前创建好 Paint
对象,重写 onDraw()
,把绘制代码写在 onDraw()
里面,就是自定义绘制最基本的实现。大概就像这样:
Paint paint = new Paint();
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
// 绘制一个圆
canvas.drawCircle(300, 300, 200, paint);
}
就这么简单。所以关于 onDraw()
其实没什么好说的,一个很普通的方法重写,唯一需要注意的是别漏写了 super.onDraw()
。你可能会点击进去查看到 super.onDraw()
其实是一个空实现,那可能只是因为你继承的是 View
吧,你继承 View 的其它子类试试?
Canvas.drawXXX() 系列方法的使用
Canvas
下面的 drawXXX() 系列的方法真没啥好讲的,你想画什么图形直接画就好了。而参数其实也给的非常的明了。你一定要全部了解学习的话,直接可以去看官方文档或者凯哥的 自定义View 1-1
- 填充颜色:Canvas.drawColor(@ColorInt int color)
- 画圆:drawCircle(float centerX, float centerY, float radius, Paint paint)
- 画矩形:drawRect(float left, float top, float right, float bottom, Paint paint)
- 画点:drawPoint(float x, float y, Paint paint)
- 批量画点:drawPoints(float[] pts, int offset, int count, Paint paint) / drawPoints(float[] pts, Paint paint)
- 画椭圆:drawOval(float left, float top, float right, float bottom, Paint paint)
- 画线:drawLine(float startX, float startY, float stopX, float stopY, Paint paint)
- 画弧线或者扇形:drawArc(float left, float top, float right, float bottom, float startAngle, float sweepAngle, boolean useCenter, Paint paint)
- 画自定义图形:drawPath(Path path, Paint paint)
- 画 Bitmap:drawBitmap(Bitmap bitmap, float left, float top, Paint paint)
- 画文字:drawText(String text, float x, float y, Paint paint)
其中可以看到有不少的坐标值参数,你只需要明白的一点是,在 Android 的绘制中,坐标系是这样的。
图片来自扔物线
值得注意的是:
- 在画弧线或者扇形中的角度 angle,x 轴正方向为 0°,顺时针方向为正角度,逆时针为负角度。
- 画弧线或者扇形中的
sweepAngle
参数,代表的是绘制的角度,不要被其它方法误导成了以为是绘制结束时候的角度,官方为何在这里做了个变换,其实我也不知道。 drawPath()
方法可能相对其它较难,但却是自定义 View 实际应用中最多的。非常需要了解其三类方法。这里直接摘抄凯哥的 自定义 View 1-1。drawBitmap()
方法中有个参数是 Bitmap,友情提示:Bitmap 可以通过BitmapFactory.decodeXXX()
获得。
Path 可以描述直线、二次曲线、三次曲线、圆、椭圆、弧形、矩形、圆角矩形。把这些图形结合起来,就可以描述出很多复杂的图形。Path 可以归结为两类方法:
- 直接描述路径,也可以分为两组:
- 添加子图形:
addXXX()
, 此类方法在特定情况下几个Canvas.drawPath()
等同于Canvas.drawXXX()
。- 画直线或曲线:
xxxTo()
: 这一组和第一组addXxx()
方法的区别在于,第一组是添加的完整封闭图形(除了addPath()
),而这一组添加的只是一条线。- 辅助设置或计算,因为应用场景很少,凯哥也只讲了其中一个方法:
Path.setFillType(Path.FillType ft)
设置填充方式
上面有比较多的提到 Paint 这个参数,实际上它是真的很好用,直接在下面讲解。
Paint 的使用
Paint 真的很重要,在自定义绘制中充当关键角色:画笔,所以我们自然可以为「画笔」做很多操作,比如设置颜色、绘制模式、粗细等。
- Paint.setStyle(Style style) 设置绘制模式
- Paint.setColor(int color) 设置颜色
- Paint.setStrokeWidth(float width) 设置线条宽度
- Paint.setTextSize(float textSize) 设置文字大小
- Paint.setAntiAlias(boolean aa) 设置抗锯齿开关
嗯,对,抗锯齿开关还可以直接在 Paint 初始化的时候直接作为构造参数:Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG)
Paint 的 API 大致可以分为 4 类:
- 颜色
- 效果
- drawText() 相关
- 初始化
凯哥专门拿了一期对 Paint 做了重点讲解,依然在实际场景应该用处不大,所以需要的直接点击 这里 跳转。
如果你想先知道凯哥都讲了什么,我这里也单独给你总结一下:
首先是给 Paint 设置着色器。
- Paint.setShader(Shader shader):设置着色器,实际上我们一般传递的参数不会直接传递
Shader
,而会选择直接传递它的子类,具体效果下面给出。
线性渐变:LinearGradient(float x0, float y0, float x1, float y1, int color0, int color1,TileMode tile)
图片来自扔物线
int centerColor, int edgeColor, @NonNull TileMode tileMode)
![外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传](https://img-home.csdnimg.cn/images/20230724024159.png?origin_url=https%3A%2F%2Fuser-gold-cdn.xitu.io%2F2017%2F11%2F8%2F7b98fe75bd81f86fe01802dd04148878%3FimageView2%2F0%2Fw%2F1280%2Fh%2F960%2Fignore-error%2F1&pos_id=img-NSI4XOYT-1712765080513) 图片来自扔物线 * 扫描渐变:SweepGradient(float cx, float cy, int color0, int color1) ![外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传](https://img-home.csdnimg.cn/images/20230724024159.png?origin_url=https%3A%2F%2Fuser-gold-cdn.xitu.io%2F2017%2F11%2F8%2F0e71db67673ebc8d68ddd2f48fb5f116%3FimageView2%2F0%2Fw%2F1280%2Fh%2F960%2Fignore-error%2F1&pos_id=img-IGZO1GH5-1712765080514) 图片来自扔物线 还有很多,就不一一给图了。 * BitmapShader(@NonNull Bitmap bitmap, TileMode tileX, TileMode tileY) * 混合着色:ComposeShader(Shader shaderA, Shader shaderB, PorterDuff.Mode mode)
其中需要注意的是:
Paint.setShader()
优先级高于Paint.setColor()
系列方法。- 最后一个 tile 参数,代表的是断点范围之外的着色规则。它是一个枚举类型,有三种参数。
- CLAMP : 直译是「夹子模式」,会在端点之外延续端点处的颜色。
- MIRROR : 镜像模式。
- REPEAT : 重复模式。
其次是设置颜色过滤
设置颜色过滤可以采用 Paint.setColorFilter(ColorFilter colorFilter)
方法。它的名字已经足够解释它的作用:为绘制设置颜色过滤。颜色过滤的意思,就是为绘制的内容设置一个统一的过滤策略,然后 Canvas.drawXXX()
方法会对每个像素都进行过滤后再绘制出来。
这个其实貌似在拍照或者照片整理类应用上用的比较多,其它方面貌似我还很少遇到过,GitHub 上的库 StyleImageView 诠释的很棒。
再其它也就没啥好说的,感兴趣直接去看 HenCoder 吧
这里可以重点说一下:Paint.setStrokeCap(Paint.Cap cap)
,设置线头的形状。线头形状有三种:BUTT
平头、ROUND
圆头、SQUARE
方头。默认为 BUTT
。
图片来自扔物线
虚线是额外加的,虚线左边是线的实际长度,虚线右边是线头。有了虚线作为辅助,可以清楚地看出 BUTT 和 SQUARE 的区别。
Canvas 的文字绘制
Canvas 的文字绘制方法有三个:
- drawText()
- drawTextRun()
- drawTextOnPath()
我们大多数情况用不了那么多,所以同样这里不做详解,对于始终想追根到底的同学,同样给你提供了 凯哥的链接。
下面只对部分需要注意的重点总结一下。
drawText()
drawText(@NonNull String text, float x, float y, @NonNull Paint paint)
其中的参数很简单:text 是文字内容,x 和 y 是文字的坐标。但需要注意:这个坐标并不是文字的左上角,而是一个与左下角比较接近的位置。大概在这里:图片来自扔物线
而如果你像绘制其他内容一样,在绘制文字的时候把坐标填成 (0, 0),文字并不会显示在 View 的左上角,而是会几乎完全显示在 View 的上方,到了 View 外部看不到的位置:
canvas.drawText(text, 0, 0, paint);
大概是这样:图片来自扔物线
另外,Canvas.drawText()
只能绘制单行的文字,而不能换行。就算显示不完,也会直接绘制到屏幕外面去。
那如果要换行,得 drawText()
很多次吗?并没有,还有一个 StaticLayout
可以完美达到我们的效果。对于详细使用,这里也不多提了。
对 drawTextRun()
和 drawTextOnPath()
,运用的可能并不多,这里就不说了。
简单提一下设置效果辅助类吧,这个可能直接就有用。
Paint 对文字绘制的辅助
- 设置文字大小:
Paint.setTextSize(float textSize)
- 设置字体:
Paint.setTypeface(Typeface typeface)
,其中的 Typeface 里面涵盖了相关字体。另外,还可以通过Typeface.createFromAsset(AssetManager mgr, String path)
来设置自定义字体,其中mgr
可以给getResources().getAssets()
,path
给文件名字,需要把字体文件 .ttf 放在工程的 res/assets 下,「assets」是新建的专用目录。 - 设置文字是否加粗:
Paint.setFakeBoldText(boolean fakeBoldText)
- 设置文字是否加删除线:
Paint.setStrikeThruText(boolean strikeThruText)
- 设置文字是否加下划线:
Paint.setUnderlineText(boolean underlineText)
- 设置字体倾斜度:
Paint.setTextSkewX(float skewX)
「skewX」 向左倾斜为正。 - 设置文字横向放缩:
Paint.setTextScaleX(float scaleX)
- 设置字体间距,默认值为 0:
Paint.setLetterSpacing(float letterSpacing)
这个不是行间距哦。 - 设置文字对齐方式:
Paint.setTextAlign(Paint.Align align)
,其中「align」有三个值:LEFT
、CENTER
和RIGHT
,默认值是LEFT
。 - 设置绘制所使用的 Locale:
Paint.setTextLocale(Locale locale)
/Paint.setTextLocales(LocaleList locales)
实际上,这些方法基本都在我们 TextView 里面的。
自定义 View 之范围裁切
范围裁切主要采用两个方法:
- clipRect()
- clipPath()
自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。
深知大多数Android工程师,想要提升技能,往往是自己摸索成长或者是报班学习,但对于培训机构动则几千的学费,着实压力不小。自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!
因此收集整理了一份《2024年Android移动开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。
既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上Android开发知识点,真正体系化!
由于文件比较大,这里只是将部分目录大纲截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且后续会持续更新
如果你觉得这些内容对你有帮助,可以添加V获取:vip204888 (备注Android)
新的开始
改变人生,没有什么捷径可言,这条路需要自己亲自去走一走,只有深入思考,不断反思总结,保持学习的热情,一步一步构建自己完整的知识体系,才是最终的制胜之道,也是程序员应该承担的使命。
《系列学习视频》
《系列学习文档》
《我的大厂面试之旅》
一个人可以走的很快,但一群人才能走的更远。不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎扫码加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!
QWqO7vKd-1712765080518)]
《我的大厂面试之旅》
[外链图片转存中…(img-Na6Y2aSC-1712765080519)]
一个人可以走的很快,但一群人才能走的更远。不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎扫码加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!
[外链图片转存中…(img-5oG79MWB-1712765080519)]