自定义分三部分绘制、布局和触摸反馈,本篇主要讲的布局过程的自定义

布局过程的含义

布局过程,就是程序在运行时利用布局文件的代码来计算出实际尺寸的过程。

布局过程的工作内容

两个阶段:测量阶段和布局阶段。

测量阶段:从上到下递归地调用每个 View 或者 ViewGroup 的 measure() 方法,

测量他们的尺寸并计算它们的位置;

布局阶段:从上到下递归地调用每个 View 或者 ViewGroup 的 layout() 方法,

把测得的它们的尺寸和位置赋值给它们。

View 或 ViewGroup 的布局过程

测量阶段,measure() 方法被父 View 调用,在 measure() 中做一些准备和优化工作后,

调用 onMeasure() 来进行实际的自我测量。

onMeasure() 做的事,View 和 ViewGroup 不一样:

View:View 在 onMeasure() 中会计算出自己的尺寸然后保存;

ViewGroup:ViewGroup 在 onMeasure() 中会调用所有子 View 的 measure() 让它们进行自我测量,并根据子 View 计算出的期望尺寸来计算出它们的实际尺寸和位置(实际上 99.99% 的父 View 都会使用子 View 给出的期望尺寸来作为实际尺寸,原因在下期或下下期会讲到)然后保存。

同时,它也会根据子 View 的尺寸和位置来计算出自己的尺寸然后保存;

布局阶段,layout() 方法被父 View 调用,在 layout() 中它会保存父 View 传进来的自己的位置和

尺寸,并且调用 onLayout() 来进行实际的内部布局。

onLayout() 做的事, View 和 ViewGroup也不一样:

View:由于没有子 View,所以 View 的 onLayout() 什么也不做。

ViewGroup:ViewGroup 在 onLayout() 中会调用自己的所有子 View 的 layout() 方法,

把它们的尺寸和位置传给它们,让它们完成自我的内部布局。

布局过程自定义的方式

三类:

1.重写 onMeasure() 来修改已有的 View 的尺寸;

2.重写 onMeasure() 来全新定制自定义 View 的尺寸;

3.重写 onMeasure() 和 onLayout() 来全新定制自定义 ViewGroup 的内部布局。

第一类自定义--修改已有的 View 的尺寸

重写 onMeasure() 来修改已有的 View 的尺寸的具体做法:

重写 onMeasure() 方法,并在里面调用 super.onMeasure(),触发原有的自我测量;

在 super.onMeasure() 的下面用 getMeasuredWidth() 和getMeasuredHeight()

来获取到之前的测量结果,

并使用自己的算法,根据测量结果计算出新的结果;

调用 setMeasuredDimension() 来保存新的结果。

//重写onMeasure()方法,自定义正方形ImageView

@Override

protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {

super.onMeasure(widthMeasureSpec, heightMeasureSpec);

int measuredWidth = getMeasuredWidth();

int measuredHeight = getMeasuredHeight();

if (measuredWidth > measuredHeight) {

measuredWidth = measuredHeight;

} else {

measuredHeight = measuredWidth;

}

setMeasuredDimension(measuredWidth, measuredHeight);

}

第二类自定义--全新定制自定义 View 的尺寸

全新定制尺寸和修改尺寸的最重要区别:

1.不需要调用super.onMeasure(widthMeasureSpec, heightMeasureSpec);

2.需要在计算的同时,保证计算结果满足父 View 给出的的尺寸限制

父 View 的尺寸限制

由来:开发者的要求(布局文件中 layout_ 打头的属性)经过父 View 处理计算后的更精确的要求;

限制的分类:

UNSPECIFIED:不限制(0)

AT_MOST:限制上限(-2147483648)

EXACTLY:限制固定值(1073741824)

全新定制自定义 View 尺寸的方式:

1.重写 onMeasure(),并计算出 View 的尺寸;

2.使用 resolveSize() 来让子 View 的计算结果符合父 View 的限制(当然,如果你想用自己的方式

来满足父 View 的限制也行。)

@Override

protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {

int width = ---;

int height = ---;

width = resolveSize(width, widthMeasureSpec);

height = resolveSize(height, heightMeasureSpec);

setMeasuredDimension(width, height);

}

public static int resolveSize(int size, int measureSpec) {

return resolveSizeAndState(size, measureSpec, 0) & MEASURED_SIZE_MASK;

}

//View中的静态方法

public static int resolveSizeAndState(int size, int measureSpec, int childMeasuredState) {

final int specMode = MeasureSpec.getMode(measureSpec);

final int specSize = MeasureSpec.getSize(measureSpec);

final int result;

switch (specMode) {

case MeasureSpec.AT_MOST:

if (specSize < size) {

result = specSize | MEASURED_STATE_TOO_SMALL;

} else {

result = size;

}

break;

case MeasureSpec.EXACTLY:

result = specSize;

break;

case MeasureSpec.UNSPECIFIED:

default:

result = size;

}

return result | (childMeasuredState & MEASURED_STATE_MASK);

}

第三类自定义--全新定制 ViewGroup 的内部布局

重写 onMeasure() 和 onLayout() 来定制 Layout 的内部布局。

定制 Layout 内部布局的方式

1.重写 onMeasure() 来计算内部布局

2.重写 onLayout() 来摆放子 View

重写 onMeasure() 的三个步骤:

1.调用每个子 View 的 measure() 来计算子 View 的尺寸

2.计算子 View 的位置并保存子 View 的位置和尺寸

3.计算自己的尺寸并用 setMeasuredDimension() 保存

计算子 View 尺寸的关键

计算子 View 的尺寸,关键在于 measure() 方法的两个参数——也就是子 View 的两个 MeasureSpec 的计算。

子 View 的 MeasureSpec 的计算方式:

1.结合开发者的要求(xml 中 layout_ 打头的属性)和自己的可用空间(自己的尺寸上限 - 已用尺寸)

2.尺寸上限根据自己的 MeasureSpec 中的 mode 而定

2.1 EXACTLY / AT_MOST:尺寸上限为 MeasureSpec 中的 size

2.2 UNSPECIFIED:尺寸无上限

@Override

protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {

//调用ViewGroup类中测量子类的方法

measureChildren(widthMeasureSpec, heightMeasureSpec);

}

/**

* 遍历所有的子view去测量(跳过GONE类型View)

* @param widthMeasureSpec 父视图的宽可用空间测量值

* @param heightMeasureSpec 父视图的高可用空间测量值

*/

protected void measureChildren(int widthMeasureSpec, int heightMeasureSpec) {

final int size = mChildrenCount;

final View[] children = mChildren;

for (int i = 0; i < size; ++i) {

final View child = children[i];

if ((child.mViewFlags & VISIBILITY_MASK) != GONE) {

measureChild(child, widthMeasureSpec, heightMeasureSpec);

}

}

}

/**

* 测量单个子View,将宽高和padding加在一起后交给getChildMeasureSpec去获得最终的测量值

* @param child 需要测量的子视图

* @param parentWidthMeasureSpec 父视图的宽可用空间测量值

* @param parentHeightMeasureSpec 父视图的高可用空间测量值

*/

protected void measureChild(View child, int parentWidthMeasureSpec,

int parentHeightMeasureSpec) {

// 取得子视图的布局参数

final LayoutParams lp = child.getLayoutParams();

// 通过getChildMeasureSpec获取最终的宽高详细测量值

final int childWidthMeasureSpec = getChildMeasureSpec(parentWidthMeasureSpec,

mPaddingLeft + mPaddingRight, lp.width);

final int childHeightMeasureSpec = getChildMeasureSpec(parentHeightMeasureSpec,

mPaddingTop + mPaddingBottom, lp.height);

// 将计算好的宽高详细测量值传入measure方法,完成最后的测量

child.measure(childWidthMeasureSpec, childHeightMeasureSpec);

}

重写 onLayout() 的方式

在 onLayout() 里调用每个子 View 的 layout() ,让它们保存自己的位置和尺寸。

@Override

protected void onLayout(boolean changed, int l, int t, int r, int b) {

for (int i = 0; i < getChildCount(); i++) {

View childAt = getChildAt(i);

childAt.layout(childLeft[i], childTop[i], childRight[i], childBottom[i]);

}

}

总结

好了,今天的分享就到这里,如果你对在面试中遇到的问题,或者刚毕业及工作几年迷茫不知道该如何准备面试并突破现状提升自己,对于自己的未来还不够了解不知道给如何规划,可以简信我获取一下相关面试题及答案资料包及学习视频。

专注分享大型Bat面试知识,后续会持续更新,希望通过这些高级面试题能够降低面试Android岗位的门槛,让更多的Android工程师理解Android系统,掌握Android系统。喜欢的话麻烦点击一个喜欢在关注一下~

android 自定义布局 根据布局获取类,阿里高级Android面试题解析:Android自定义View—布局过程的自定义...相关推荐

  1. 【双11劲爆干货】阿里高级Java面试题(首发,70道)

    转载自 [双11劲爆干货]阿里高级Java面试题(首发,70道,带详细答案) 整理的70道阿里的Java面试题,都来挑战一下,看看自己有多厉害.下面题目都带超详细的解答,详情见底部. 1.java事件 ...

  2. 分享一套阿里高级Java面试题,要去阿里的先过这些题。

    转载自 分享一套阿里高级Java面试题,要去阿里的先过这些题.

  3. java 获取类的注解_Java 自定义注解通过反射获取类、方法、属性上的注解

    反射 JAVA中的反射是运行中的程序检查自己和软件运行环境的能力,它可以根据它发现的进行改变.通俗的讲就是反射可以在运行时根据指定的类名获得类的信息. 注解的定义 注解通过 @interface 关键 ...

  4. android stringbuilder 一次插入多条数据_android开发面试题解析

    俗话说职场如战场,选择好的阵容去"投靠"这一点至关重要,但是这也是需要技术的.我想在三国中最早的面试应该就是"三顾茅庐"了,典故的细节就不说了,面试的难只有我们 ...

  5. Android实现三角形气泡效果方式汇总,高级安卓面试题及答案2019

    通过截图可以发现,气泡由正三角形和圆角长方形组成,于是可以通过组合来形成三角形气泡的效果,下面我们通过三种方式进行实现. 实现方式: 1.通过.9图进行实现: 2.通过shape方式实现: 3.通过自 ...

  6. java 百分比怎么比较_这88道阿里高级岗面试题,刷掉了80%以上的Java程序员

    2020,可谓是招聘面试最难季.不少大厂,如腾讯.字节的招聘名额明显减少,面试门槛却一再拔高,如果不用心准备,很可能就被面试官怼得哑口无言.今天不谈其它,就说说我作为面试官面试的那些事儿. 从某电商项 ...

  7. Android Studio 3.5 怎样获取MD5签名

    Android Studio 3.5 怎样获取MD5签名 问题 解决方法 问题 在Android Studio可能会遇到这个问题--在terminal窗口中使用以下这条名命令仍然获取不到MD5签名,只 ...

  8. android 自定义布局 根据布局获取类,android自定义布局中的平滑移动之ViewGroup实现...

    在android应用程序的开发过程中,相信我们很多人都想把应用的交互做的比较绚丽,比如让界面切换平滑的滚动,还有热度灰常高的伪3D等界面效果,通常情况下,系统提供的应用在特效这方面只能为我们提供简单的 ...

  9. 【JetPack】为现有 Android 项目配置视图绑定 ( ViewBinding ) 模块 ( 视图绑定不影响传统布局操作 | 视图绑定类关联 Activity | 视图绑定类本质 )

    文章目录 I . 为现有项目配置 视图绑定 ( ViewBinding ) 应用 II . 视图绑定 ( ViewBinding ) 定制 III . 视图绑定 ( ViewBinding ) 对于正 ...

最新文章

  1. R语言dataframe数据列中的缺失值NA的个数统计实战:特定数据列的NA值统计、所有特征的NA值统计
  2. android源码阅读笔记1-配置源码路径/阅读源码方法讨论
  3. Linux系统下,MySQL以及禅道的安装/卸载
  4. 图解 CSS (1): 先做一个样式表测试工具
  5. MySQL学习笔记_5_SQL语言的设计与编写(上)
  6. “拼木头”算法挑战赛:禁忌搜索算法,用Javascript 跑
  7. 小甲鱼Python第二十八讲(文件)
  8. 安卓手机app开发之微信app支付【绝对干货】h5打包apk调用微信app支付不再困惑
  9. 二建 机电工程常用材料及工程设备
  10. CodeForces 379A. New Year Candles
  11. 云计算:程序员重回个人英雄时代
  12. matlab上机作业,matlab上机作业(数字信号处理)
  13. 关于荣耀che1-cl20手机制作服务器失败的事
  14. 快乐大脚!快乐的帝企鹅!
  15. 2017年全国大学生电子设计竞赛:四旋翼自主飞行器探测跟踪系统(C题)主控RX23T,STM32F103VET6
  16. Enable VT-x in your BIOS 怎么解决
  17. 要不要试试 FBI 出品的健身APP,绝对不收集信息
  18. 【2018】—不忘初心,砥砺前行
  19. Chatbot 发展遇瓶颈?用什么手段来打破
  20. 索罗斯等华尔街金融大鳄,为什么名声那么臭?

热门文章

  1. Unity 自定义Log系统
  2. 使用MATLAB转换图片为数据进行vga显示
  3. 【MySQL运维】MySQL5.1升级到MySQ 5.5实战
  4. src与href区别
  5. linux下imp导入oracle数据库,Oracle数据库Linux下的导入IMP
  6. EXCEL怎么按照数字大小排列
  7. 跨媒体检索(关联)之基于CCA的方法大总结
  8. TensorFlowOnSpark 接口函数用法
  9. 英文书: Python 网络编程基础手册
  10. 开源GIS(二十)——CAD数据添加属性转GIS数据