前言
View,有很多的名称。不论是你熟知的布局,还是控件,他们全部都继承自View。
文内部分图片转载自Carson_Ho大佬的文章
思维导图
工作流程
measure
其实通过layout中的第二张图我们已经知道了控件大小的计算了。
对于ViewGroup而言,就是对容器内子控件的遍历和计算了。
因为直接继承自View的控件使用wrap_cotent和match_parent是显示出来的效果是相同的。需要我们使用MeasureSpec中的getMode()方法来对当前的模式进行区分和比较。
模式 | 状态 |
---|---|
UNSPECIFIED | 未指定模式,View想多大就多大,父容器不做限制,一般用于系统内部的测量 |
AT_MOST | 最大模式,对应wrap_content,View的大小不大于SpecSize的值 |
EXACTLY | 精确模式,对应match_parent,View的大小为SpecSize的值 |
- @Override
- protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
- super.onMeasure(widthMeasureSpec, heightMeasureSpec);
- //用于获取设定的模式
- int widthMode = MeasureSpec.getMode(widthMeasureSpec);
- int heightMode = MeasureSpec.getMode(heightMeasureSpec);
- // 用于获取设定的长度
- int widthSize = MeasureSpec.getSize(widthMeasureSpec);
- int heightSize = MeasureSpec.getSize(heightMeasureSpec);
- // 类似这样的判断,后面不过多复述
- // 用于判断是不是wrap_content
- // 如果不进行处理,效果会是match_parent
- if(widthMode == MeasureSpec.AT_MOST && heightMode == MeasureSpec.AT_MOST){
- setMeasuredDimension(20, 20);
- }
- }
layout
在确定位置时,我们有一个非常需要主要的地方—— 坐标系。
Android系统的坐标系和平时画的坐标系并不相同。
所以相对应的,我们的位置计算方法自然和我们原来的正好是相反的。
4个顶点的位置分别由4个值决定:
所有的计算都是相对于所在容器才能够开始的。
draw
一共有6个步骤:
关于开发者需要重写的方法一般是第三步绘制View的内容对应的onDraw()。
- private Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG);
- @Override
- protected void onDraw(Canvas canvas) {
- super.onDraw(canvas);
- int width = getWidth();
- int height = getHeight();
- // 在画布上进行类似这样的操作
- canvas.drawLine(0, height/2, width,height/2, paint);
- }
入门自定义View
在日常项目的布局文件中我们经常会使用到xmlns:app="http://schemas.android.com/apk/res-auto"这样标签,其实他就是用来引入我们自定义的标签使用的。
1.在res/values目录下创建attrs
- <?xml version="1.0" encoding="utf-8"?>
- <resources>
- <declare-styleable name="DefaultView">
- <attr name="color" format="color"/>
- </declare-styleable>
- </resources>
2.在DefaultView(Context context, @Nullable AttributeSet attrs)中获取。以下是整个完整代码。
- /**
- * author: ClericYi
- * time: 2020-01-30
- */
- public class DefaultView extends View {
- private Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG);
- private int mColor = Color.RED;
- public DefaultView(Context context, @Nullable AttributeSet attrs) {
- super(context, attrs);
- initAttrs(context, attrs);
- initDraw();
- }
- private void initAttrs(Context context, @Nullable AttributeSet attrs) {
- TypedArray array = context.obtainStyledAttributes(attrs, R.styleable.DefaultView);
- // 从styleable中获取的名字是系统会生成的,一般是 类名_name 的形式
- mColor = array.getColor(R.styleable.DefaultView_color, Color.GREEN);
- // 获取完资源后即使回收
- array.recycle();
- }
- private void initDraw() {
- paint.setColor(mColor);
- paint.setStrokeWidth(3f);
- }
- @Override
- protected void onDraw(Canvas canvas) {
- super.onDraw(canvas);
- int width = getWidth();
- int height = getHeight();
- canvas.drawLine(0, height/2, width,height/2, paint);
- }
- @Override
- protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
- super.onMeasure(widthMeasureSpec, heightMeasureSpec);
- int widthMode = MeasureSpec.getMode(widthMeasureSpec);
- int heightMode = MeasureSpec.getMode(heightMeasureSpec);
- int widthSize = MeasureSpec.getSize(widthMeasureSpec);
- int heightSize = MeasureSpec.getSize(heightMeasureSpec);
- if(widthMode == MeasureSpec.AT_MOST){
- setMeasuredDimension(20, 20);
- }
- }
- }
基础的性能优化
首先的话我们先了解如何去知道一个View是否被过度绘制了?
其实在我们手机中的开发模式已经存在这个选项了。
下方给出绘制的次数对应图
那如何做到性能优化呢?
在这个问题之前,需要了解什么是过度绘制,你可以理解为同一位置的控件不断的叠加而产生的无用数据,那我们就来说说集中解决方案吧。
方案1:减少嵌套层数。
因为只是一个案例,想说的意思,如果多个LinearLayout嵌套实现的效果,如果能被一个ConstraintLayout直接实现,那么就用后者替代,因为不会这样在同一个区域重复出现。
方案2:去除默认的背景
这个解决方案其实针对的背景会被自动绘制的问题,如果我们把这个层次消去,从绘制角度老说也是一种提升了。正如图示一般直接减少了一层的绘制。
在代码中的具体表现,通过对style.xml中的Theme进行修改:
- <item name="android:windowBackground">@null</item>
总结
人工智能+医学影像 ,是将目前最先进的人工智能技术应用于医学影像诊断中,帮助...
1.世上不爱的理由和借口有很多:忙,累,没感觉,不合适,为你好而爱的表现只有...
去年Covid-19开始大流行时,克利夫兰诊所医师、首席研究信息官拉若杰依和她的同...
基于人工智能和深度学习方法的现代计算机视觉技术在过去10年里取得了显著进展。...
时至今日,科技巨头及其基于AI的数字平台与解决方案,完全有能力影响全球领导人...
经过短期徘徊之后,电信业务收入终于在今年10月份出现了向上增长势头。虽然我们...
前言: 最近帮人做了个小设备,使用了无线模块、触摸芯片,主要功能就是把触摸按...
RPA工具在过去的几年中的使用量激增。今年发生的疫情给组织带来加快实现自动化的...
今年10月,DCByte与Knight Frank合作发布了《数据中心报告》。该报告是对欧洲十...
机器人已经进入零售业,从六英尺高的自由移动机器发现巨人食品商店中的溢出物,...