ViewGroup和View的理解和当子视图发生更新时通知viewgroup更新

来源:互联网 发布:mfc多文档编程实例 编辑:程序博客网 时间:2024/06/06 17:42

  

1. 概念

Android中的View与我们以前理解的“视图”不同。在Android中,View比视图具有更广的含义,它包含了用户交互和显示,更像Windows操作系统中的window。

ViewGroup是View的子类,所以它也具有View的特性,但它主要用来充当View的容器,将其中的View视作自己的孩子,对它的子View进行管理,当然它的孩子也可以是ViewGroup类型。

ViewGroup(树根)和它的孩子们(View和ViewGroup)以树形结构形成了一个层次结构,View类有接受和处理消息的功能,android系统所产生的消息会在这些ViewGroup和 View之间传递。

2.          Android的窗口系统
Android的窗口系统是Client/Server模式的,我在这里只讲窗口系统的客户端(图1)。     我们所提到的概念:View,ViewGroup,DecorView,ViewRoot都是存在于窗口系统的Client端。

Android中的Window是表示Top Level等顶级窗口的概念。DecorView是Window的Top-Level View,这个View可以称之为主View,DecorView会缺省的attach到Activity的主窗口中。

ViewRoot建立了主View(DecorView)与窗口系统Server端的通讯桥梁, ViewRoot是 Handler的子类,即它其实是个Handler,它接受窗口系统服务器端的消息并将消息投递到窗口系统的客户端(图1),然后消息就从客户端的主View往其下面的子View传递,直到消息被完全处理掉为止。


  DecorView实际上是一个ViewGroup。在依存关系上来讲,对单个主窗口来讲,DecorView是Top-Level View。View并不是关注的重点,重要的是我们需要知道消息分发路径是建立在什么关系上的。View的成员变量mParent用来管理View上级关系的。而ViewGroup顾名思义就是一组View的管理,于是在ViewGroup构建了焦点管理和子View节点数组。这样通过View的mParent和ViewGroup的mChildren构建了Android中View直接的关系网。

 3.          View的介绍

(1)     事件和绘制

绘制流程:

绘制按照视图树的顺序执行。视图绘制时会先绘制子控件。如果视图的背景可见,视图会在调用onDraw函数之前绘制背景。强制重绘,可以使用invalidate()。

 

事件的基本流程如下:
         1、事件分配给相应视图,视图处理它,并通知相关监听器。
         2、操作过程中如果发生视图的尺寸变化,则该视图用调用requestLayout()方法,向父控件请求再次布局。
         3、操作过程中如果发生视图的外观变化,则该视图用调用invalidate()方法,请求重绘。
         4、如果requestLayout()或invalidate()有一个被调用,框架会对视图树进行相关的测量、布局和绘制。
        注意,视图树是单线程操作,直接调用其它视图的方法必须要在UI线程里。跨线程的操作必须使用句柄Handler。

 

焦点处理:
        框架处理焦点的转移,来响应用户输入。isFocusable()函数表示视图是否能接受焦点。setFocusable(boolean)函数可以改变视图能否接受焦点。触摸屏模式(Touch Mode)的相关函数是isFocusableInTouchMode()和setFocusableInTouchMode(boolean)。
        焦点转移按照就近算法。按哪个方向就近可以在XML布局文件中配置。
         nextFocusDown
         nextFocusLeft
         nextFocusRight
         nextFocusUp
        视图请求焦点可以使用requestFocus()。

 

(2) 成员介绍

protected ViewParent mParent;

mParent用于记录它的父亲,就是我们前面提到的ViewGroup。

 

protected OnClickListener mOnClickListener;

mOnClickListener是click事件的回调接口.

大家经常使用的setOnClickListener(OnClickListener listener):

public void setOnClickListener(OnClickListener I) {

        if (!isClickable()) {

            setClickable(true);

        }

        mOnClickListener =I;

}

可以看出,mOnClickListener其实就是保存我们在应用程序中定义的OnClickListener接口的。

 

public void draw(Canvas canvas)

这个函数用于渲染View和它的孩子,我们不应该在子类对它进行override。

 

protected void onDraw(Canvas canvas)

我们一般override此函数来实现自己的绘制操作。

 

IWindowSession getWindowSession() {

        return mAttachInfo != null ? mAttachInfo.mSession : null;

}

函数getWindowSession()用户得到窗口系统Client端和服务器端通讯的接口IWindowSession。这是一个AIDL接口,android系统中的跨进程通讯就是用AIDL接口实现的。

 

public final void layout(int l, int t, int r, int b)

此函数用于确定View和其子View的尺寸和位置,它的调用发生在onMeasure之后。

 

protected void onLayout(boolean changed, int left, int top, int right, int bottom)

此函数在layout调用完成后执行,View的子类一般override此函数,并在函数中对其每个孩子调用layout方法。

 

 

public View getRootView()

此函数用于得到View层次结构的top-level View,即上文中提到的DecorView。

 

public final void measure(int widthMeasureSpec, int heightMeasureSpec)

此函数用户找出View的大小,它的参数widthMeasureSpec、heightMeasureSpec是其父亲传递给它的,这2个参数是View找出其大小时的限制条件,其实真正的精确大小确定是由onMeasure()完成的,onMeasure由measure函数调用。

 

protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec)

此函数测量View并根据其内容来决定View的高和宽,它应该被子类override以实现大小的精确测量。在onMeasure中我们必须调用View.setMeasuredDimension(int, int)来保存测量得到的大小,高和宽分别被保存在View.mMeasuredHeight和View.mMeasureWidth中。

 

 

public boolean onKeyUp(int keyCode, KeyEvent event)

此函数会在键盘按键释放后被调用,但前提是View必须获得焦点。

 

public boolean onTouchEvent(MotionEvent event)

此函数用于响应触摸屏事件。

 

public void invalidate()

此函数将调用onDraw,强制重绘。

 

public void requestLayout()

当某些东西发生改变后,当前View层次结构无效了,调用此函数对View的层次结构进行重新布局。

 

当增加滑动事件时,如果加了changed判断可能视图没有更新,去掉判断就行了

protected void onLayout(boolean changed, int l, int t, int r, int b) {
                Log.e(TAG,"onLayout");
                //if (changed) {
                        int childLeft = 0;
                        final int childCount = getChildCount();
                        for (int i=0; i<childCount; i++) {
                                final View childView = getChildAt(i);
                                if (childView.getVisibility() != View.GONE) {
                                        final int childWidth = childView.getMeasuredWidth();
                                        Log.e(TAG,"childWidth="+childWidth);
                                        Log.e(TAG,"childHeight="+childView.getMeasuredHeight());
                                        childView.layout(childLeft, 0, 
                                                        childLeft+childWidth, childView.getMeasuredHeight());
                                        childLeft += childWidth;
                                }
                        }
        //        }
        }

去掉if(changed)判断就可以了

*******************这是通过整理网上的一些资料**********************************************************************************
*******************源码下载地址*********************************************************************************************
*******************http://download.csdn.net/detail/util_c/5959489 **********************************************************************************

原创粉丝点击