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()方法。

  • 相关阅读:
    为图片指定区域添加链接
    数值取值范围问题
    【leetcode】柱状图中最大的矩形(第二遍)
    【leetcode 33】搜索旋转排序数组(第二遍)
    【Educational Codeforces Round 81 (Rated for Div. 2) C】Obtain The String
    【Educational Codeforces Round 81 (Rated for Div. 2) B】Infinite Prefixes
    【Educational Codeforces Round 81 (Rated for Div. 2) A】Display The Number
    【Codeforces 716B】Complete the Word
    一个简陋的留言板
    HTML,CSS,JavaScript,AJAX,JSP,Servlet,JDBC,Structs,Spring,Hibernate,Xml等概念
  • 原文地址:https://www.cnblogs.com/thinfog/p/5768630.html
Copyright © 2011-2022 走看看