一、Android的控件架构:

1、每个Activity包含一个Window对象(Window是abstract的,一般是由PhoneWindow实现)。
2、PhoneWindow将DecorView设置为整个应用的根View。DecorView将具体的内容呈现在了PhoneWindow上。
3、DecorView里面所有View的监听事件都通过WindowManagerService来接收,通过Activity对象来回调对应的OnClickListener。
4、DecorView把显示分成两部分:TiitleView 和 ContentView。
5、当我们在Activity中setContentView时,实际就是把activityxxx.xml设置在ID为content的FrameLayout中。
6、当程序在onCreate()方法中调用setContentView后,ActivityManagerService会回调onResume()方法,此时系统才会把整个DecorView添加到PhoneWindow中,并让其显示,从而完成界面的绘制。

二、View的测量:

关于View测量必须要知道的:

1、MeasureSpec类,其是一个32位的int值,低30位为测量的大小,高2位是测量模式,在计算中用位运算是为了提高效率。
2、EXACTLY:精确模式,当layout_width或layout_height设为具体数值或match_parent时。
3、AT_MOST::最大值模式,当layout_width或layout_height指定为wrap_content时,其随着子控件的内容变化而变化。
4、UNSPECIFIED:View想多大就多大,多在自定义View时用。
5、View类默认的onMeasure() 方法只支持EXACTLY模式,如果要让自定义View支持wrap_content,必须重写onMeasure方法指定wrap_content时的大小。

开始测量:

我们最终要做的工作就是把测量后的宽高值作为参数设置给setMeasuredDimension()方法

第一步:重写onMeasure()方法
 @Overrideprotected void onMeasure(int widthMeasureSpec,int heightMeasureSpec){      setMeasuredDimension(        measureWidth(widthMeasureSpec),        measureHeight(heightMeasureSpec));}
第二步:以measureWidth为例,从MeasureSpec对象中提取出具体的测量模式和大小。
int specMode = MeasureSpec.getMode(measureSpec);int specSize = MeasureSpec.getSize(measureSpec);
第三步:通过判断测量的模式,给出不同的测量值。

当specMode为EXACTLY时,直接使用指定的specSize即可,当specMode为其他两种模式时,需要给它一个默认的大小。
特别地,如果指定wrap_content属性,即AT_MOST模式,则需要取出我们指定的大小与specSize中最小的一个来作为最后的测量值。

以下可作为模版代码:
  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的绘制:

关于View绘制必须要知道的:

1、当测量好一个View后,我们就可以简单地重写onDraw()方法,并在Canvas对象上来绘制所需要的图形。
2、Canvas是画板,用Paint在上面作画。

第一步:创建一个Canvas对象
  Canvas canvas =  new Canvas(bitmap);
第二步:开始绘制
  canvas.drawXXX();

1、不提倡创建时不传入bitmap,因为这个bitmap要和Canvas画布紧紧联系在一起,此过程称之为:装载画布,这个bitmap用来存储所有绘制在Canvas上的像素信息。
2、当用以上方式创建好后,后面调用所有的Canvas.drawXXX方法都发生在这个bitmap上。
3、虽然我们也使用了Canvas的绘制API,但其实并没有将图形直接绘制在onDraw()方法指定的那块画布上,而是通过改变bitmap,然后让View重绘,从而显示改变之后的bitmap。

三、ViewGroup的测量:

1、ViewGroup会去管理其子View,其中一个任务就是负责View的显示大小。
2、当ViewGroup大小为wrap_content时,ViewGroup就需要对子View进行遍历,已便获得所有子View的大小,从而决定自己的大小。
3、ViewGroup在测量时遍历子View,从而调用子View的Measure方法获得每个子View的测量结果,前面说的对View的测量,就是在这进行的。(ViewGroup的Layout过程与其相似)
4、当子View测量完毕后,就需要将子View放到合适的位置,这个过程就是View的Layout过程。
5、在自定义ViewGroup时,通常会去重写onLayout()方法控制子View显示位置的逻辑。
6、如果还需支持wrap_content,必须重写onMeasure()方法自己实现,这点与View是相同的。

四、ViewGroup的绘制

1、ViewGroup通常不需要绘制,除了指定ViewGroup的背景色,它的onDraw()方法会调用之外,其他情况都不会调用。
2、ViewGroup会使用dispatchDraw()方法来绘制其子View,其过程同样是遍历所有子view,并调用子View的绘制方法来完成绘制工作。(这点与ViewGroup的测量和Layout()过程雷同)

参考资料:
1、《Android群英传》第3章Android控件架构与自定义控件详解。

更多相关文章

  1. Android(安卓)获得view的宽和高
  2. android stdio 开发时使用系统权限和hide函数报错的解决方法
  3. Android中杀死进程的方法
  4. Android系统启动流程源码分析
  5. Android设计——Activity和Task的设计思路和方法
  6. Android(安卓)WebView 的回退方法(goback) 遭遇重定向
  7. Android进行单元测试难在哪-part4
  8. Android中WebView方法WebViewClient和WebChromeClient的区别
  9. android之官方下拉刷新组件SwipeRefreshLayout

随机推荐

  1. OpenGL ES for Android 绘制立方体
  2. Android Studio打不开虚拟机,两种情况详解
  3. Android Volley的使用
  4. android隐藏EditText光标
  5. Storm——Android SQLite数据库管理类库
  6. Android MQTT 实现Push
  7. Android(安卓)Studio Gradle Sync同步慢
  8. 《Android学习指南》分享给大家
  9. android:orientation参数说明
  10. Android中使用Gson解析JSON数据,以及把JS