面试一问:关于-View测量、布局及绘制原理(1),2024年Android常见面试题

先自我介绍一下,小编浙江大学毕业,去过华为、字节跳动等大厂,目前阿里P7

深知大多数程序员,想要提升技能,往往是自己摸索成长,但自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!

因此收集整理了一份《2024年最新Android移动开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友。
img
img
img
img
img
img
img

既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,涵盖了95%以上Android开发知识点,真正体系化!

由于文件比较多,这里只是将部分目录截图出来,全套包含大厂面经、学习笔记、源码讲义、实战项目、大纲路线、讲解视频,并且后续会持续更新

如果你需要这些资料,可以添加V获取:vip204888 (备注Android)
img

正文

measure()方法中,传入了两个参数 widthMeasureSpec, heightMeasureSpec 表示 View的宽高的一些信息。

protected void onMeasure(int widthMeasureSpec, int heightMeasure Spec) {
setMeasuredDimension(getDefaultSize(getSuggestedMinimumW idth(), widthMeasureSpec),
getDefaultSize(getSuggestedMinimumHeight(), heig htMeasureSpec));
}

由上述流程来看Measure流程很简单,关键点是在于widthMeasureSpec, heightMeasureSpec这两个参数信息怎么获得?

如果有了widthMeasureSpec, heightMeasureSpec,通过一定的处理(可以重写,自 定义处理步骤),从中获取View的宽/高,调用setMeasuredDimension()方法,指定 View的宽高,完成测量工作。

MeasureSpec的确定

先介绍下什么是MeasureSpec

MeasureSpec由两部分组成,一部分是测量模式,另一部分是测量的尺寸大
小。 其中,Mode模式共分为三类

UNSPECIFIED 不对View进行任何限制,要多大给多大,一般用于系统内部

EXACTLY 对应LayoutParams中的match_parent和具体数值这两种模式。检测到 View所需要的精确大小,这时候View的最终大小就是SpecSize所指定的值,

AT_MOST 对应LayoutParams中的wrap_content。View的大小不能大于父容器 的大小。

那么MeasureSpec又是如何确定的?

对于DecorView,其确定是通过屏幕的大小,和自身的布局参数LayoutParams

这部分很简单,根据LayoutParams的布局格式(match_parentwrap_content或 指定大小),将自身大小,和屏幕大小相比,设置一个不超过屏幕大小的宽高,以 及对应模式。 对于其他View(包括ViewGroup),其确定是通过父布局的MeasureSpec和自身的 布局参数LayoutParams。 这部分比较复杂。以下列图表表示不同的情况:

当子View的LayoutParams的布局格式是wrap_content,可以看到子View的大小 是父View的剩余尺寸,和设置成match_parent时,子View的大小没有区别。为了 显示区别,一般在自定义View时,需要重写onMeasure方法,处理wrap_content 时的情况,进行特别指定。

从这里看出MeasureSpec的指定也是从顶层布局开始一层层往下去,父布局影响 子布局。

可能关于MeasureSpec如何确定View大小还有些模糊,篇幅有限,没详细具体展开介绍

View的测量流程:

三、Layout流程

测量完View大小后,就需要将View布局在Window中,View的布局主要通过确定上 下左右四个点来确定的。

其中布局也是自上而下,不同的是ViewGroup先在layout()中确定自己的布局,然 后在onLayout()方法中再调用子View的layout()方法,让子View布局。在Measure 过程中,ViewGroup一般是先测量子View的大小,然后再确定自身的大小。

public void layout(int l, int t, int r, int b) {
// 当前视图的四个顶点
int oldL = mLeft;
int oldT = mTop;
int oldB = mBottom;
int oldR = mRight;

// setFrame() / setOpticalFrame():确定View自身的位置
// 即初始化四个顶点的值,然后判断当前View大小和位置是否发生了变化并返回

boolean changed = isLayoutModeOptical(mParent) ?
setOpticalFrame(l, t, r, b) : setFrame(l, t, r, b);
//如果视图的大小和位置发生变化,会调用onLayout()
if (changed || (mPrivateFlags & PFLAG_LAYOUT_REQUIRED) == PF LAG_LAYOUT_REQUIRED) {
// onLayout():确定该View所有的子View在父容器的位置
onLayout(changed, l, t, r, b);

}

上面看出通过 setFrame() / setOpticalFrame():确定View自身的位置,通过 onLayout()确定子View的布局。 setOpticalFrame()内部也是调用了 setFrame(),所以具体看setFrame()怎么确定自身的位置布局。

protected boolean setFrame(int left, int top, int right, int bot tom) {

// 通过以下赋值语句记录下了视图的位置信息,即确定View的四个顶点
// 即确定了视图的位置
mLeft = left;
mTop = top;
mRight = right;
mBottom = bottom;

mRenderNode.setLeftTopRightBottom(mLeft, mTop, mRight, mBott om);
}

确定了自身的位置后,就要通过onLayout()确定子View的布局。onLayout()是一个 可继承的空方法。

protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
}

如果当前View就是一个单一的View,那么没有子View,就不需要实现该方法。

如果当前View是一个ViewGroup,就需要实现onLayout方法,该方法的实现个自 定义ViewGroup时其特性有关,必须自己实现。

由此便完成了一层层的的布局工作。 View的布局流程:

四、Draw过程

View的绘制过程遵循如下几步:

①绘制背景 background.draw(canvas)
②绘制自己(onDraw
③绘制Children(dispatchDraw)
④绘制装饰(onDrawScrollBars

从源码中可以清楚地看出绘制的顺序。

public void draw(Canvas canvas) {
// 所有的视图最终都是调用 View 的 draw ()绘制视图( ViewGroup 没有复写 此方法)
// 在自定义View时,不应该复写该方法,而是复写 onDraw(Canvas) 方法进行绘 制。
// 如果自定义的视图确实要复写该方法,那么需要先调用 super.draw(canvas)完 成系统的绘制,然后再进行自定义的绘制。

int saveCount;
if (!dirtyOpaque) {
// 步骤1: 绘制本身View背景
drawBackground(canvas);
}

最后

我坚信,坚持学习,每天进步一点,滴水穿石,我们离成功都很近!
以下是总结出来的字节经典面试题目,包含:计算机网络,Kotlin,数据结构与算法,Framework源码,微信小程序,NDK音视频开发,计算机网络等。

字节高级Android经典面试题和答案


网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。

需要这份系统化的资料的朋友,可以添加V获取:vip204888 (备注Android)
img

一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!

)**
[外链图片转存中…(img-cwNqycVC-1713377817305)]

一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!

  • 5
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值