您的位置:首页 > 运维架构 > 网站架构

Android群英传第三章笔记·Android控件架构与自定义控件详解

2016-04-22 17:55 603 查看

Android控件架构

Android中,控件大致被分为两类,即ViewGroup控件与View控件。ViewGroup控件作为父控件可以包含多个View控件,并管理其包含的View控件。

通常在Activity中使用的findViewById()方法,就是在控件树中以树的深度优先遍历来查找对应元素。

View树结构:



UI界面架构图:



PhoneWindow将一个DecorView设置为整个应用窗口的根View。

DecorView将要显示的具体内容呈现在了PhoneWindow上,这里面的所有View的监听事件,都通过WindowManagerService来进行接收,并通过Activity对象来回调相应的onClickLisener。

在代码中,程序在onCreate方法调用setContentView方法后,ActivityManagerService会回调onResume方法,此时系统才会把整个DecorView添加到PhoneWindow中,并让其显示出来,从而完成界面的绘制。

View的测量

Android在绘制View前,也必须对View进行测量,即告诉系统该画一个多大的View。这个过程在onMeasure方法中进行。

Android给我们提供了一个设计短小精悍却功能强大的类——MeasureSpec类,通过它来帮助我们测量View。MeasureSpec是一个32位的int值,其中高2位为测量的模式,低30位为测量的大小,在计算中使用位运算的原因是为了提高并优化效率。



onMeasure方法:父控件传递给子控件的“建议”尺寸大小,两个参数表示宽高大小及测量模式(MeasureSpec类介绍及使用详解)。如果是ViewGroup,且大小为Wrap_content时,则需要遍历所有子View测量他们的大小,然后设置自身的大小。

protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {

super.onMeasure(widthMeasureSpec,heightMeasureSpec);

}

setMeasureDimension方法:将测量后的尺寸传递给子控件,完成测量工作。

protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {

setMeasureDimension(measureWidth(widthMeasureSpec),measureHeight(heightMeasureSpec));

}

public static int measureWidth(int measureSpec)
{//根据父控件给的建议尺寸和测量模式,计算相应的尺寸
int result = 0;
int specMode = MeasureSpec.getMode(measureSpec);
int specSize =  MeasureSpec.getSize(measureSpec);
switch (specMode)
{
case MeasureSpec.UNSPECIFIED:
result = size;
break;
case MeasureSpec.AT_MOST:
result = 200;//指定view的大小
result = Math.min(result, specSize);
break;
case MeasureSpec.EXACTLY:
result = specSize;
break;
}
return result;
}


ViewGroup的子View位置设定

在ViewGrope及其子View完成测量之后,需要对子view进行放置位置的设定。在放置子view前,需要确定整个vewGroup的高度。然后在OnLayout方法中遍历调用子view的layout方法设定具体位置。

View的绘制

过程:重写onDraw(),在Canvas对象上绘制图形。Canvas为系统2D绘图API必须要使用的对象。

canvas通常会带有一个bitmap参数,用于存储绘制在canvas上的像素信息。当创建了含有bitmap的canvas对象后,所有canvas.drawxxx方法都发生在这个bitmap上。值得注意的是,view的onDraw方法中会创建两个bitmap,并将第二个bitmap封装到另一个canvas对象中,只在第二个bitmap上进行绘图。

ViewGroup的绘制:如果没有设置背景色,不会调用onDraw方法,而是调用dispatchDraw方法绘制子View。原理也是遍历子view并调用其绘制方法。

自定义View

自定义View通常需要重写onDraw方法来绘制自定义内容。如果设置了wrap_content属性,那么必须重写onMeasure方法测量大小。

View中有一些重要的回调方法:

onFinishInflate():从XML加载组件后回调

onSizeChanged():组件大小改变时回调

onMeasure:测量

onLayout():回调该方法来确定显示的位置

onTouchEvent():监听到触摸事件回调

实现自定义控件的方式

对现有控件进行拓展

@Override

protected void onDraw(Canvas canvas) {

//父类绘制之前,实现自己的效果

super.onDraw(canvas);

//父类绘制完成后,再实现自己的效果

通过组合来实现新的控件

自定义属性

命名控件 介绍

重写View来实现全新的控件 例子:音频条形图

自定义view的一个例子

事件拦截机制

几个重要的方法:dispatchTouchEvent,onInterceptTouchEvent,onTouchEvent.

从ViewGroup到view的事件分发和处理回调事件顺序如下(以ViewGroupA,ViewGroupB,view为例):

ViewGroupA.dispatchTouchEvent –> ViewGroupA.onInterceptTouchEvent –> ViewGroupB.dispatchTouchEvent –> ViewGroupB.onInterceptTouchEvent –> view.dispatchTouchEvent –> view.onTouchEvent –> ViewGroupB.onTouchEvent –> ViewGroupA.onTouchEvent

解释:

dispatchTouchEvent方法用于分发事件,一般不用重写。onInterceptTouchEvent用来拦截TouchEvent,onTouchEvent用来处理TouchEvent。

onInterceptTouchEvent返回true则拦截事件,不往下分发;onTouchEvent返回true则不往上回调。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: