阿里面试官;Android自定义View你都知道吗?
前言
View,有很多的名称。不论是你熟知的布局,还是控件,他们全部都继承自View。
文内部分图片转载自Carson_Ho大佬的文章
思维导图
工作流程
measure
其实通过layout中的第二张图我们已经知道了控件大小的计算了。
- height = bottom - top
- width = right - left
对于ViewGroup而言,就是对容器内子控件的遍历和计算了。
因为直接继承自View的控件使用wrap_cotent和match_parent是显示出来的效果是相同的。需要我们使用MeasureSpec中的getMode()方法来对当前的模式进行区分和比较。
模式状态UNSPECIFIED未指定模式,View想多大就多大,父容器不做限制,一般用于系统内部的测量AT_MOST最大模式,对应wrap_content,View的大小不大于SpecSize的值EXACTLY精确模式,对应match_parent,View的大小为SpecSize的值
@Override
layout
在确定位置时,我们有一个非常需要主要的地方—— 坐标系。
Android系统的坐标系和平时画的坐标系并不相同。
所以相对应的,我们的位置计算方法自然和我们原来的正好是相反的。
4个顶点的位置分别由4个值决定:
- top:子View上边界到所在容器上边界的距离。
- left:子View左边界到所在容器左边界的距离。
- bottom:子View下边界到所在容器上边界的距离。
- right:子View右边界到所在容器左边界的距离。
所有的计算都是相对于所在容器才能够开始的。
draw
一共有6个步骤:
- 如果需要,则绘制背景 --drawBackground(canvas);
- 保存当前canvas层 --saveCount = canvas.getSaveCount();
- 绘制View的内容 --if (!dirtyOpaque) onDraw(canvas);
- 绘制子View --dispatchDraw(canvas);
- 如果需要,则绘制View的褪色边缘,类似于阴影效果 --canvas.restoreToCount(saveCount);
- 绘制装饰,比如滚动条 --onDrawForeground(canvas);
关于开发者需要重写的方法一般是第三步绘制View的内容对应的onDraw()。
private Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG);
入门自定义View
在日常项目的布局文件中我们经常会使用到xmlns:app="http://schemas.android.com/apk/res-auto"这样标签,其实他就是用来引入我们自定义的标签使用的。
- 在res/values目录下创建attrs
<?xml version="1.0" encoding="utf-8"?>
- 在DefaultView(Context context, @Nullable AttributeSet attrs)中获取。以下是整个完整代码。
/**
基础的性能优化
首先的话我们先了解如何去知道一个View是否被过度绘制了?
其实在我们手机中的开发模式已经存在这个选项了。
开启前开启后
下方给出绘制的次数对应图
那如何做到性能优化呢?
在这个问题之前,需要了解什么是过度绘制,你可以理解为同一位置的控件不断的叠加而产生的无用数据,那我们就来说说集中解决方案吧。
方案1:减少嵌套层数。
使用线性布局 | 使用约束布局 |
因为只是一个案例,想说的意思,如果多个LinearLayout嵌套实现的效果,如果能被一个ConstraintLayout直接实现,那么就用后者替代,因为不会这样在同一个区域重复出现。
方案2:去除默认的背景
这个解决方案其实针对的背景会被自动绘制的问题,如果我们把这个层次消去,从绘制角度老说也是一种提升了。正如图示一般直接减少了一层的绘制。
在代码中的具体表现,通过对****style.xml中的Theme进行修改:
<item name="android:windowBackground">@null</item>
总结
以上就是我的学习成果,如果有什么我没有思考到的地方或是文章内存在错误,欢迎与我分享。
上一篇: [爬虫]Python爬取网易云音乐搜索并下载歌曲!
下一篇: 大一寒假学习总结