黑马程序员技术交流社区

标题: Android视图控件架构分析之View、ViewGroup [打印本页]

作者: ERGUANGLI    时间: 2016-5-9 09:25
标题: Android视图控件架构分析之View、ViewGroup
在Android中,视图控件大致被分为两类,即ViewGroup和View,ViewGroup控件作为父控件,包含并管理着子View,通过ViewGroup和View便形成了控件树,各个ViewGoup对象和View对象就是控件树中的节点。在控件树中,以树的深度来遍历查找对应的控件元素,同时,上层控件负责子控件的测量与绘制,并传递交互事件。
Android控件树:
  



AndroidUI界面架构图:
  



一.测量View的工具类:MeasureSpec
1.MeasureSpec包含了测量的模式和测量的大小,通过MeasureSpec.getMode()获取测量模式,通过MeasureSpec.getSize()获取测量大小;
2.MeasureSpec是一个32位的int值,高2位为测量的模式,低30位为测量的大小,使用位运算的目的在于提高优化效率。
二.测量的模式
1.EXACTLY,精确值模式:将layout_width或layout_height属性指定为具体数值或者match_parent。
2.AT_MOST,最大值模式:将layout_width或layout_height指定为wrap_content。
3.UNSPECIFIED: View想多大就多大
三.View类默认的onMeasure()方法只支持EXACTLY模式,如果要支持其它模式,就必须重写onMeasure(),重写onMeasure()的模板代码:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
package com.example.demoapp.views;
  
import android.content.Context;
import android.view.View;
  
public class MeasuredView extends View {
  public MeasuredView(Context context) {
    super(context);
  }
   
  @Override
  protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
    // 调用父类的onMeasure()
    super.onMeasure(measureWidth(widthMeasureSpec), measureHeight(heightMeasureSpec));
    // 或者直接调用父类的setMeasuredDimension(),因为父类的onMeasure()最终调用了setMeasuredDimension()
    // setMeasuredDimension(measureWidth(widthMeasureSpec), measureHeight(heightMeasureSpec));
  }
   
  /**
   * 测量View的width
   * @param measureSpec MeasureSpec对象
   * @return View的width
   */
  private int measureWidth(int measureSpec) {
    int result = 0;
    int specMode = MeasureSpec.getMode(measureSpec);
    int specSize = MeasureSpec.getSize(measureSpec);
      
    if (specMode == MeasureSpec.EXACTLY) {
      result = specSize;
    } else {
      result = 200;
      if (specMode == MeasureSpec.AT_MOST) {
        result = Math.min(result, specSize);
      }
    }
    return result;
  }
   
  /**
   * 测量View的height
   * @param measureSpec MeasureSpec对象
   * @return View的height
   */
  private int measureHeight(int measureSpec) {
    int result = 0;
    int specMode = MeasureSpec.getMode(measureSpec);
    int specSize = MeasureSpec.getSize(measureSpec);
      
    if (specMode == MeasureSpec.EXACTLY) {
      result = specSize;
    } else {
      result = 200;
      if (specMode == MeasureSpec.AT_MOST) {
        result = Math.min(result, specSize);
      }
    }
    return result;
  }
}




四.View的绘制
1.2D绘图必备利器——Canvas
  1)获取Canvas对象的方式:
    a.由方法中的参数传入,例如,View的onDraw()中有一个参数就是Canvas对象
    b.通过构造方法构造,即:Canvas canvas = new Canvas(bitmap),在Canvas的构造方法传入一个Bitmap对象,即可获取一个Canvas对象。通过传入Bitmap对象构造Canvas对象的过程称为“画布的装载”,传入的Bitmap对象承载了多有绘制在Canvas上的像素信息,调用Canvas.drawXXX方法(如:Canvas.drawBitmap(bitmap, 0, 0, null))都将发生在该Bitmap对象上。
  2)利用Canvas绘图
    a.通过Canvas.drwaXXX进行绘制操作将直接作用于Bitmap对象,当再次刷新View的时候,我们将会被绘制的Bitmap对象发生了改变;
    b.利用Canvas和Paint进行绘图;
    c.不管多么复杂、精美的空间,都可以被拆分为一个个小的图形单元,我们只要找到这些图形单元,就可以将控件绘制出来。
五.ViewGroup的测量
  1.ViewGroup的作用:管理子View,如子View的大小、位置;
  2.ViewGroup通过遍历子View,调用子View的Measure()来获得每一个子View的测量结果;
  3.ViewGroup测量完子View,调用子View的Layout()将子View放到合适的位置;
  4.在自定义ViewGroup的时候,通常会重写onLayout()控制子View的显示;
  5.如果需要支持wrap_content属性,必须重写onMeasure()。
六、ViewGroup的绘制
  通常情况下,ViewGoup不需要绘制,但是ViewGroup会使用dispatchDraw()来绘制其子View。







欢迎光临 黑马程序员技术交流社区 (http://bbs.itheima.com/) 黑马程序员IT技术论坛 X3.2