zoukankan      html  css  js  c++  java
  • View的相关原理(读书笔记)

    View的使用方法相关:

    1.setContentView()

    2.LayoutInflater.inflate()

    PS:本质上setContentView()方法最终也是通过LayoutInflater来操作View的

    LayoutInflater的工作方式:

    1.LayoutInflater是用过xmlPullParser来读取XML文件里的布局的

    2.读取布局后,通过rInflate(paser,root,attrs)方法来读取View,然后返回

    3.rInflate方法先调用createViewFromTag(name,attrs)方法,然后createViewFromTag()内部再调用createView()方法,以反射的方式进行新建对象并返回

    4.当第三步执行完后,将第三步返回的View对象作为参数,重复调用rInflate()方法,层层递归,遍历每个View里面的子元素,返回给父View

    inflate还存在另一个方法:inflate(int resource, ViewGroup root, boolean attachToRoot) 

    此方法表示是否将resource对应的视图添加进root的方法。

    如果root为null,那么在resource对应的视图里面对应的子元素通过inflate显示的时候,子元素的布局信息会失去效果,因为子元素的布局设置都是相对父布局而言的。

    基于这种子元素布局必须依赖父容器来设置的思想,会产生一个悖论,根布局的设置match_parent是有效的,但我们没有给他们设置父布局,这是为什么呢?

    简单考虑,我们设置的任何View都需要一个容器去承载,而我们又不能每次都自己设置根布局,于是Android系统帮我们解决了这一问题:

    系统帮我们默认建立了一个Framelayout用于承载所有的View元素,这一切都是默认的。

    手机界面生呈现出来的界面经过了层层绘制的具体可参照:http://www.cnblogs.com/beenupper/archive/2012/07/13/2589749.html

    View的绘制过程:

    step 1:Measure()

      measure()方法会接收两个参数widthMeasureSpec和heightMeasureSpec,这两个值分别用于确定视图的宽度和高度的规格和大小。

      MeasureSpec的值由specSize和specMode共同组成的,其中specSize记录的是大小,specMode记录的是规格。

      specMode的三种模式:

      1. EXACTLY

      表示父视图希望子视图的大小应该是由specSize的值来决定的,系统默认会按照这个规则来设置子视图的大小,开发人员当然也可以按照自己的意愿  设置成任意的大小。

      2. AT_MOST

      表示子视图最多只能是specSize中指定的大小,开发人员应该尽可能小得去设置这个视图,并且保证不会超过specSize。系统默认会按照这个规则来设置子视图的大小,开发人员当然也可以按照自己的意愿设置成任意的大小。

      3. UNSPECIFIED

      表示开发人员可以将视图按照自己的意愿设置成任意的大小,没有任何限制。这种情况比较少见,不太会用到。

      而MeasureSpec的值是在performTraversals()方法中,通过调用getRootMeasureSpec()方法获取的,

    真正来执行Measure的程序段:onMeasure()

      (这也是我们能够通过重写该方法自定义View的渠道),该方法默认调用getDefaultSize()方法来获取视图的大小,这个默认方法就是用来识别match_parent和wrap_content设置的。

      我们可以通过在自定义的View中重写onMeasure()方法来覆盖默认的getDefaultSize()方法,让自定义的视图完全按照我们的设计大小绘制

      在我们完成了对自定义视图的设置后,ViewGroup会通过measureChild()方法来解析MeasureSpec,测量具体的大小。

    总结:

      视图大小的控制是由父视图、布局文件、以及视图本身共同完成的,父视图会提供给子视图参考的大小,而开发人员可以在XML文件中指定视图的大小,然后视图本身会对最终的大小进行最终决定。

    step 2:Layout()  

      在完成Measure()之后视图的大小就测量好了,接下来就是确定该视图处于父容器的具体位置,ViewRoot的performTraversals()方法会在measure结束后继续执行,并调用View的layout()方法来执行此过程。

      在Layout方法中会先检测位置信息是否发生改变,然后调用onLayout()方法,但这个onLayout()方法在View中是空的,需要追溯到ViewGroup中,而ViewGroup方法中的代码为:

    @override

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

    这就意味着需要控制位置信息,必须要自己重写方法。

      

    step 3:Draw()

       在以上步骤都完成后,ViewRoot中的代码会继续执行并创建出一个Canvas对象,然后调用View的draw()方法来执行具体的绘制工作

     在Draw()方法中的关键步骤:

      step 1: 绘制backgroud的相关属性,可以是设置的颜色和drawable引用

      step 2: if (!dirtyOpaque) onDraw(canvas);  这里就是执行我们重写的onDraw()方法

      step 3: dispatchDraw(canvas);    绘制子视图

      step 4: onDrawScrollBars(canvas);    绘制draw decorations (scrollbars)  

     而我们最常操作的就是第三步,重写onDraw()方法。

  • 相关阅读:
    该虚拟机似乎正在使用中,请获取所有权
    分配销售区域
    未对销售组织 XXX 分销渠道 00 语言 ZH 定义
    Bash 遍历目录
    plsql 不需配置*.ora就可以访问数据库
    arch linux
    拓端数据tecdat|R语言有限混合模型(FMM,finite mixture model)及其EM算法聚类分析间歇泉喷发时间
    拓端数据tecdat|使用R语言进行多项式回归、非线性回归模型曲线拟合
    拓端数据tecdat|R语言使用ARIMAX预测失业率经济时间序列数据
    拓端数据tecdat|R语言用ARIMA模型,ARIMAX模型预测冰淇淋消费时间序列数据
  • 原文地址:https://www.cnblogs.com/thinfog/p/5768630.html
Copyright © 2011-2022 走看看