引言
自定义View 字面意思就是自己定义一个View以此完成自己的业务需求.当你在百度/Google cv大法搞不定你的业务需求的时候,这个时候就需要你自定义一个View来完成你的需求了.
背景简介
Android 系统为我们提供了各种各样的常见控件来满足我们的日常需求,但是谁能不爱美呢.常见的系统控件满足了我们的功能需要,但是原生控件确实不好看这个时候就需要我们做改造了 或者更改Style 或者改颜色背景.但是一些需求原生控件满足不了日益强大的UI的时候我们只能自定义View来实现,比如说各种奇形怪状的控件,各种奇怪的进度条...这个时候我们就需要自己写了.一切从爹开始,继承爹的财产好干事儿,我们继承View这个爹 然后自定义我们的控件就行了
页面展示的层次
了解自定义View以前,咱们先简单介绍一下Android视图层次结构以及DecorView.在Android Studio layout inspector 中能看到页面的布局层次
视图层次.png 屏幕展示的层级.png
上图可以看到整个页面分为状态栏,ActionBar 和setContent()中的引用的布局content
自定义View的绘制流程
自定义View 的流程,View这个父布局给我们提供了很多方法(有兴趣的同学可以去看看源码),我们用到的比较多的是onMeasure().onLayout(),onDraw();
- onMeasure() : 测量
- onLayout() :摆放
- onDraw() :绘制
整体流程:
View的绘制从ActivityThread类中Handler的处理RESUME_ACTIVITY事件开始,在执行performResumeActivity之后,创建Window以及DecorView并调用WindowManager的addView方法添加到屏幕上,addView又调用ViewRootImpl的setView方法,最终执行performTraversals方法,依次执行performMeasure,performLayout,performDraw。也就是view绘制的三大过程。
1.onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int)方法是测量一个View的宽高,onMeasure()调用setMeasuredDimension(w,h)方法设置View的宽高
//获取测量模式
var widthMode=MeasureSpec.getMode(widthMeasureSpec)
widthMode 设置布局的主要模式为
//最多不超过父布局模式
--MeasureSpec.AT_MOST:(wrap_content)父布局根据子布局填充
//精确模式
--MeasureSpec.EXACTLY:(much_content,fill_content,100dp)父布局已经确定了确切尺寸。子布局不能超过父布局
//不指定模式
--MeasureSpec.UNSPECIFIED:父布局没有对子布局施加任何约束。 可以是任何大小
2.onLayout(changed: Boolean, left: Int, top: Int, right: Int, bottom: Int) 设置控件居于屏幕位置(0.0)
changed: 是否有变化
left,top,right,bottom 左上右下两个点的坐标 矩形的左上角和右下角
3.onDraw(canvas: Canvas?) 绘制方法 将控件绘制到手机屏幕上
1.canvas.drawText(@NonNull String text, float x, float y, @NonNull Paint paint) 绘制文字的方法
String text:文字参数
float x:开始位置
float y: 基线位置(文字绘制的位置)
- 获取基线方法
fun getBaseline(p: Paint): Float {
val fontMetrics: Paint.FontMetrics = p.fontMetrics
return height / 2 + ((fontMetrics.descent - fontMetrics.ascent) / 2 - fontMetrics.descent) }
Paint paint: 画笔(设置绘制的 宽度,颜色,模式,以及文字大小,抗锯齿)
2.canvas?.drawArc(RectF oval, float startAngle, float sweepAngle, boolean useCenter,
@NonNull Paint paint):绘制指定的弧,将缩放比例以适合指定的椭圆
RectF() :RectF拥有一个矩形的四个浮点坐标。 矩形是由其4个边(左,上,右下)的坐标表示
startAngle: 开始的角度
sweepAngle:旋转的角度
useCenter:是否填充中心
paint:画笔
3. drawCircle(float cx, float cy, float radius, @NonNull Paint paint):绘制圆形
cx:圆心的x坐标
cy:圆心的y坐标
radius:半径大小
paint: 画笔
其他重要方法
1 : invalidate() 刷新绘制
2 : canvas.save() 保存当前矩阵并将剪辑裁剪到私有堆栈上。
3 : canvas.restore() 这个方法调用平衡了对save()的先前调用,并用于删除所有自上次保存调用以来对矩阵/剪辑状态的修改。 (和save()搭配使用)
总结
感觉这个自定义View 还是有很多没梳理到 暂时先这样,回头接着研究
网友评论