Android面试 UI相关

作者: 一个有故事的程序员 | 来源:发表于2022-04-02 14:43 被阅读0次

    面试问题

    • onMeasure onLayout onDraw的作用
    • 自定义View和自定义ViewGroup的区别
    • getMeasureWidth和getWidth的区别
    • getLeft getRight getWidth表示的意义
    • MeasureSpec是什么
    • 如何优化自定义View
    • 自定义view效率高于xml定义吗
    • Draw的基本流程
    • setWillNotDraw的作用
    • invalidate()、postInvalidate()、requestLayout()的区别

    onMeasure onLayout onDraw的作用

    • onMeasure:用来计算控件的尺寸,告诉父控件此控件需要的尺寸。
    • onLayout:父容器的onLayout()调用子类的layout()来确定子view在viewGroup中的位置。
    • onDraw:自定义view的关键方法,用于绘制界面,可以重写此方法以绘制自定义View。

    自定义View和自定义ViewGroup的区别

    • ViewGroup是一个容器,而这个容器是继承与View。
    • ViewGroup是一个基类,并且是Layout和一些View组件的基类。

    getMeasureWidth和getWidth的区别

    • getMeasureWidth()在走完onMeasure()方法之后有值
    • getWidth()在layout()之后有值,是布局完成之后的确切值
    • getMeasureWidth()在onMeasure()之后调用
    • getWidth()在layout()之后调用
    • getMeasureWidth()是view的一个测量大小
    • getWidth()是view被父布局摆放的大小

    getLeft getRight getWidth表示的意义

    getWidth()的值就是getRight()-getLeft()的值。

    MeasureSpec是什么

    从MeasureSpec类的定义我们知道,它封装了对子View的布局要求,由尺寸和模式组成,其实MeasureSpec代表一个32位的int值,高2位表示SpecMode,低30位表示SpecSize,而SpecSize是指在某种SpecMode下的规格大小,从源码我们看出它内部定义了很多常量,从api17以后开始采用位运算,因为位运算的效率最高,我们看下三种模式:
    UNSPECIFIED:未指定模式,不对View大小做限制,如:ListView,ScrollView。
    EXACTLY:精确模式,确切的大小,如:100dp或者march_parent。
    AT_MOST:最大模式,大小不可超过某数值,如:wrap_content。

    如何优化自定义View

    为了加速你的view,对于频繁调用的方法,需要尽量减少不必要的代码。先从onDraw开始,需要特别注意不应该在这里做内存分配的事情,因为它会导致GC,从而导致卡顿。在初始化或者动画间隙期间做分配内存的动作。不要在动画正在执行的时候做内存分配的事情。
    你还需要尽可能的减少onDraw被调用的次数,大多数时候导致onDraw都是因为调用了invalidate(),因此请尽量减少调用invaildate()的次数。如果可能的话,尽量调用含有4个参数的invalidate()方法而不是没有参数的invalidate()。没有参数的invalidate会强制重绘整个view。
    另外一个非常耗时的操作是请求layout。任何时候执行requestLayout(),会使得Android UI系统去遍历整个View的层级来计算出每一个view的大小。如果找到有冲突的值,它会需要重新计算好几次。另外需要尽量保持View的层级是扁平化的,这样对提高效率很有帮助。
    如果你有一个复杂的UI,你应该考虑写一个自定义的ViewGroup来执行他的layout操作。与内置的view不同,自定义的view可以使得程序仅仅测量这一部分,这避免了遍历整个view的层级结构来计算大小。

    自定义view效率高于xml定义吗

    自定义view效率高于xml定义:

    1. 少了解析xml。
    2. 自定义View减少了ViewGroup与View之间的测量,包括父量子,子量自身,子在父中位置摆放,当子view变化时,父的某些属性都会跟着变化。

    Draw的基本流程

    绘制基本上可以分为六个步骤:

    • 首先绘制View的背景;
    • 如果需要的话,保持canvas的图层,为fading做准备;
    • 然后,绘制View的内容;
    • 接着,绘制View的子View;
    • 如果需要的话,绘制View的fading边缘并恢复图层;
    • 最后,绘制View的装饰(例如滚动条等等)。

    setWillNotDraw的作用

    如果一个View不需要绘制任何内容,那么设置这个标记位为true以后,系统会进行相应的优化。

    • 默认情况下,View没有启用这个优化标记位,但是ViewGroup会默认启用这个优化标记位。
    • 当我们的自定义控件继承于ViewGroup并且本身不具备绘制功能时,就可以开启这个标记位从而便于系统进行后续的优化。
    • 当明确知道一个ViewGroup需要通过onDraw来绘制内容时,我们需要显示地关闭WILL_NOT_DRAW这个标记位。

    invalidate()、postInvalidate()、requestLayout()的区别

    • invalidate()与postInvalidate()都用于刷新View,主要区别是invalidate()在主线程中调用,若在子线程中使用需要配合handler;而postInvalidate()可在子线程中直接调用。
    • invalidate()和postInvalidate():View(非容器类)调用invalidate方法只会重绘自身,ViewGroup调用则会重绘整个View树。
    • requestLayout:View执行requestLayout方法,会向上递归到顶级父View中,再执行这个顶级父View的requestLayout,所以其他View的onMeasure,onLayout也可能会被调用。

    更多内容戳这里(整理好的各种文集)

    相关文章

      网友评论

        本文标题:Android面试 UI相关

        本文链接:https://www.haomeiwen.com/subject/tfuzqrtx.html