Android原理揭秘系列之View、ViewGroup (转)

Android的UI界面都是由View和ViewGroup及其派生类组合而成的。其中,View是所有UI组件的基类,而ViewGroup是容纳这些组件的容器,其本身也是从View派生出来的。AndroidUI界面的一般结构可参见下面的示意图:

可见,作为容器的ViewGroup可以包含作为叶子节点的View,也可以包含作为更低层次的子ViewGroup,而子ViewGroup又可以包含下一层的叶子节点的View和ViewGroup。事实上,这种灵活的View层次结构可以形成非常复杂的UI布局,开发者可据此设计、开发非常精致的UI界面。

一般来说,开发Android应用程序的UI界面都不会直接实用View和ViewGroup,而是使用这两大基类的派生类。

View派生出的直接子类有:AnalogClock,ImageView,KeyboardView, ProgressBar,SurfaceView,TextView,ViewGroup,ViewStub

View派生出的间接子类有:AbsListView,AbsSeekBar, AbsSpinner, AbsoluteLayout, AdapterView<T extends Adapter>,AdapterViewAnimator, AdapterViewFlipper, AppWidgetHostView, AutoCompleteTextView,Button,CalendarView, CheckBox, CheckedTextView, Chronometer, CompoundButton,

ViewGroup派生出的直接子类有:AbsoluteLayout,AdapterView<T extends Adapter>,FragmentBreadCrumbs,FrameLayout,LinearLayout,RelativeLayout,SlidingDrawer

ViewGroup派生出的间接子类有:AbsListView,AbsSpinner, AdapterViewAnimator, AdapterViewFlipper, AppWidgetHostView, CalendarView, DatePicker, DialerFilter, ExpandableListView, Gallery, GestureOverlayView,GridView,HorizontalScrollView, ImageSwitcher,ListView,

上面View、ViewGroup的直接子类和间接别子类中标记为红色的类是我们在应用开发中接触和用得比较频繁的类,需要大家重点熟悉和掌握,其详细的API及用法可参见SDK的说明。这里特别指出,ImageView是布局具有图片效果的UI常用的类,SurfaceView是常用来进行游戏开发的空间,与一般View相比较它是特殊的并且非常重要的类(后续会对原理作深入分析),而AbsoluteLayout、FrameLayout,LinearLayout, RelativeLayout这几个ViewGroup的直接子类是Android UI布局中最基本的布局元素。

值得一提的是,上述的所有基类、派生类都是Android framework层集成的标准系统类,开发者在应用开发中可直接引用SDK中这些系统类及其API。但事实上,在UI开发的很多场景下,直接使用这些系统类并不能满足应用开发的需要。比如说,我们想用ImageView在默认情况下加载一幅图片,但是希望在点击该View时View变换出各种图像处理效果,这个时候直接使用ImageView是不行的,此时我们可以重载ImageView,在新派生出的子控件中重载OnDraw等方法来实现我们的定制效果。这种派生出系统类的子类方法我们通常称之为自定义控件。自定义控件可像标准View控件那样在XML及我们的Java文件中进行布局和实例化,但在布局时必须指出其完整的包名和类名。事实上,自定义控件的使用是我们进行Android 开发的必不可少的基本用法,是必须掌握的基本技巧。

下面我们来看一个典型的例子,我们待机Launcher 的XML布局,这个例子能够很好的说明上面的一些概念。

view plaincopy to clipboardprint?

<?xml version="1.0" encoding="utf-8"?>

<!-- Copyright (C) 2007 The Android Open Source Project

Licensed under the Apache License, Version 2.0 (the "License");

you may not use this file except in compliance with the License.

You may obtain a copy of the License at

http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software

distributed under the License is distributed on an "AS IS" BASIS,

WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

See the License for the specific language governing permissions and

limitations under the License.

-->

<com.android.launcher2.DragLayer

xmlns:android="http://schemas.android.com/apk/res/android"

xmlns:launcher="http://schemas.android.com/apk/res/com.android.launcher"

android:id="@+id/drag_layer"

android:layout_width="match_parent"

android:layout_height="match_parent">

<include layout="@layout/all_apps" />

<!-- The workspace contains 3 screens of cells -->

<com.android.launcher2.Workspace

android:id="@+id/workspace"

android:layout_width="match_parent"

android:layout_height="match_parent"

launcher:defaultScreen="2">

<include android:id="@+id/cell1" layout="@layout/workspace_screen" />

<include android:id="@+id/cell2" layout="@layout/workspace_screen" />

<include android:id="@+id/cell3" layout="@layout/workspace_screen" />

<include android:id="@+id/cell4" layout="@layout/workspace_screen" />

<include android:id="@+id/cell5" layout="@layout/workspace_screen" />

</com.android.launcher2.Workspace>

<ImageView

android:id="@+id/previous_screen"

android:layout_width="93dip"

android:layout_height="@dimen/button_bar_height"

android:layout_gravity="bottom|left"

android:layout_marginLeft="6dip"

android:scaleType="center"

android:src="@drawable/home_arrows_left"

android:onClick="previousScreen"

android:focusable="true"

android:clickable="true" />

<ImageView

android:id="@+id/next_screen"

android:layout_width="93dip"

android:layout_height="@dimen/button_bar_height"

android:layout_gravity="bottom|right"

android:layout_marginRight="6dip"

android:scaleType="center"

android:src="@drawable/home_arrows_right"

android:onClick="nextScreen"

android:focusable="true"

android:clickable="true" />

<com.android.launcher2.DeleteZone

android:id="@+id/delete_zone"

android:layout_width="@dimen/delete_zone_size"

android:layout_height="@dimen/delete_zone_size"

android:paddingTop="@dimen/delete_zone_padding"

android:layout_gravity="bottom|center_horizontal"

android:scaleType="center"

android:src="@drawable/delete_zone_selector"

android:visibility="invisible"

launcher:direction="horizontal"

/>

<RelativeLayout

android:id="@+id/all_apps_button_cluster"

android:layout_width="fill_parent"

android:layout_height="@dimen/button_bar_height"

android:layout_gravity="bottom|center_horizontal"

android:paddingTop="2dip"

>

<com.android.launcher2.HandleView

style="@style/HotseatButton"

android:id="@+id/all_apps_button"

android:layout_centerHorizontal="true"

android:layout_alignParentBottom="true"

android:src="@drawable/all_apps_button"

launcher:direction="horizontal"

/>

<ImageView

android:id="@+id/hotseat_left"

style="@style/HotseatButton.Left"

android:layout_toLeftOf="@id/all_apps_button"

android:src="@drawable/hotseat_phone"

android:onClick="launchHotSeat"

/>

<ImageView

android:id="@+id/hotseat_right"

style="@style/HotseatButton.Right"

android:layout_toRightOf="@id/all_apps_button"

android:src="@drawable/hotseat_browser"

android:onClick="launchHotSeat"

/>

</RelativeLayout>

</com.android.launcher2.DragLayer>

<?xml version="1.0" encoding="utf-8"?>

<!-- Copyright (C) 2007 The Android Open Source Project

Licensed under the Apache License, Version 2.0 (the "License");

you may not use this file except in compliance with the License.

You may obtain a copy of the License at

http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software

distributed under the License is distributed on an "AS IS" BASIS,

WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

See the License for the specific language governing permissions and

limitations under the License.

-->

<com.android.launcher2.DragLayer

xmlns:android="http://schemas.android.com/apk/res/android"

xmlns:launcher="http://schemas.android.com/apk/res/com.android.launcher"

android:id="@+id/drag_layer"

android:layout_width="match_parent"

android:layout_height="match_parent">

<include layout="@layout/all_apps" />

<!-- The workspace contains 3 screens of cells -->

<com.android.launcher2.Workspace

android:id="@+id/workspace"

android:layout_width="match_parent"

android:layout_height="match_parent"

launcher:defaultScreen="2">

<include android:id="@+id/cell1" layout="@layout/workspace_screen" />

<include android:id="@+id/cell2" layout="@layout/workspace_screen" />

<include android:id="@+id/cell3" layout="@layout/workspace_screen" />

<include android:id="@+id/cell4" layout="@layout/workspace_screen" />

<include android:id="@+id/cell5" layout="@layout/workspace_screen" />

</com.android.launcher2.Workspace>

<ImageView

android:id="@+id/previous_screen"

android:layout_width="93dip"

android:layout_height="@dimen/button_bar_height"

android:layout_gravity="bottom|left"

android:layout_marginLeft="6dip"

android:scaleType="center"

android:src="@drawable/home_arrows_left"

android:onClick="previousScreen"

android:focusable="true"

android:clickable="true" />

<ImageView

android:id="@+id/next_screen"

android:layout_width="93dip"

android:layout_height="@dimen/button_bar_height"

android:layout_gravity="bottom|right"

android:layout_marginRight="6dip"

android:scaleType="center"

android:src="@drawable/home_arrows_right"

android:onClick="nextScreen"

android:focusable="true"

android:clickable="true" />

<com.android.launcher2.DeleteZone

android:id="@+id/delete_zone"

android:layout_width="@dimen/delete_zone_size"

android:layout_height="@dimen/delete_zone_size"

android:paddingTop="@dimen/delete_zone_padding"

android:layout_gravity="bottom|center_horizontal"

android:scaleType="center"

android:src="@drawable/delete_zone_selector"

android:visibility="invisible"

launcher:direction="horizontal"

/>

<RelativeLayout

android:id="@+id/all_apps_button_cluster"

android:layout_width="fill_parent"

android:layout_height="@dimen/button_bar_height"

android:layout_gravity="bottom|center_horizontal"

android:paddingTop="2dip"

>

<com.android.launcher2.HandleView

style="@style/HotseatButton"

android:id="@+id/all_apps_button"

android:layout_centerHorizontal="true"

android:layout_alignParentBottom="true"

android:src="@drawable/all_apps_button"

launcher:direction="horizontal"

/>

<ImageView

android:id="@+id/hotseat_left"

style="@style/HotseatButton.Left"

android:layout_toLeftOf="@id/all_apps_button"

android:src="@drawable/hotseat_phone"

android:onClick="launchHotSeat"

/>

<ImageView

android:id="@+id/hotseat_right"

style="@style/HotseatButton.Right"

android:layout_toRightOf="@id/all_apps_button"

android:src="@drawable/hotseat_browser"

android:onClick="launchHotSeat"

/>

</RelativeLayout>

</com.android.launcher2.DragLayer>

在上面的XML布局中,最顶层的控件com.android.launcher2.DragLayer是一个自定义控件,其继承自ViewGroup的直接子类FrameLayout。在DragLayer的布局内部,其子Vie w既有ImageView类本身,也有从ImageView的派生出的子定义控件HandleView,既有ViewGroup的框架中的直接子类RelativeLayout,也有从派生出的自定义控件Workspace。总之,这布局的例子是大家学习Android布局、应用开发和理解Android View、ViewGroup概念的非常优秀的例子,大家可下载Launcher模块的源代码来进行深入分析(Launcher单个模块的下载方法可参见博文Android源码下载——用git clone实现单个目录下载 )。

最后,给大家介绍下View和ViewGroup最重要的几个方法——

protected void onDraw(Canvas canvas):View类中用于重绘的方法,这个方法是所有View、ViewGroup及其派生类都具有的方法,也是Android UI绘制最重要的方法。开发者可重载该方法,并在重载的方法内部基于参数canvas绘制自己的各种图形、图像效果。

protected void onLayout(boolean changed, int left, int top, int right, int bottom):View类中布局发生改变时会调用的方法,这个方法是所有View、ViewGroup及其派生类都具有的方法,重载该类可以在布局发生改变时作定制处理,这在实现一些特效时非常有用。

protected void dispatchDraw(Canvas canvas):ViewGroup类及其派生类具有的方法,这个方法主要用于控制子View的绘制分发,重载该方法可改变子View的绘制,进而实现一些复杂的视效,典型的例子可参见Launcher模块Workspace的dispatchDraw重载。

protected boolean drawChild(Canvas canvas, View child, long drawingTime)):ViewGroup类及其派生类具有的方法,这个方法直接控制绘制某局具体的子view,重载该方法可控制具体某个具体子View。

View、ViewGroup是Android UI体系至关重要的两大基类,本文仅对一些最基本的概念、原理和API进行了介绍,大家要全面掌握还需要阅读SDK中对这两个类的介绍并熟悉其API ,并在应用开发中逐渐的加深理解和掌握其用法。

原文摘自: http://wenku.baidu.com/link?url=aa4LLgcs7vz5vrbq6ylGHGI1IOiAitbbt0qO6eb12Bq8z-A0QnnW7EPJn4tZr-z_E8DF8EzUbCBR001AsTgxcN0_A4CABLoV7ObavHZ0Toy

View、ViewGroup (转)的更多相关文章

  1. java.lang.ClassCastException: android.view.ViewGroup$LayoutParams cannot be cast to android.widget.L(转)

    09-09 10:19:59.979: E/AndroidRuntime(2767): FATAL EXCEPTION: main09-09 10:19:59.979: E/AndroidRuntim ...

  2. 自定义View/ViewGroup的步骤和实现

    1.设置属性(供XML调用) 在res目录新建attrs.xml文件 <?xml version="1.0" encoding="utf-8"?> ...

  3. View,ViewGroup的Touch事件的分发机制

    原帖地址:http://blog.csdn.net/xiaanming/article/details/21696315 ViewGroup的事件分发机制 我们用手指去触摸Android手机屏幕,就会 ...

  4. LayoutParams继承于Android.View.ViewGroup.LayoutParams(转)

    LayoutParams相当于一个Layout的信息包,它封装了Layout的位置.高.宽等信息.假设在屏幕上一块区域是由一个Layout占领的,如果将一个View添加到一个Layout中,最好告诉L ...

  5. extends android.view.ViewGroup两种实现

    /*    private int measureHeight(int heightMeasureSpec) {         int count = getChildCount();        ...

  6. Andriod 从源码的角度详解View,ViewGroup的Touch事件的分发机制

    转自:xiaanming的博客(http://blog.csdn.net/xiaanming/article/details/21696315) 今天这篇文章主要分析的是Android的事件分发机制, ...

  7. LayoutParams继承于Android.View.ViewGroup.LayoutParams.

    LayoutParams相当于一个Layout的信息包,它封装了Layout的位置.高.宽等信息.假设在屏幕上一块区域是由一个Layout占领的,如果将一个View添加到一个Layout中,最好告诉L ...

  8. 解决 android.view.ViewGroup$LayoutParams cannot be cast to android.widget.AbsListView$LayoutParams

    错误日志1: 06-13 10:55:50.410: E/KVLog(1129): Error info:java.lang.ClassCastException: android.widget.Li ...

  9. View Focus的处理过程及ViewGroup的mFocused字段分析

    通过上篇的介绍,我们知道在对KeyEvent的处理中有非常重要的一环,那就是KeyEvent在focus view的path上自上而下的分发, 换句话说只有focus的view才有资格参与KeyEve ...

  10. 自定义View和ViewGroup

    为了扫除学习中的盲点,尽可能多的覆盖Android知识的边边角角,决定对自定义View做一个稍微全面一点的使用方法总结,在内容上面并没有什么独特的地方,其他大神们的博客上面基本上都有讲这方面的内容,如 ...

随机推荐

  1. php获取当前方法名和类名

    php提供的一些系统常量可以完成这些 php获取当前方法名(函数名) __FUNCTION__ php获取当前类名 __CLASS__ 或者 get_class($this); php获取本类所有的方 ...

  2. 使用XtraGrid自定义列计算1 z

    Devexpress控件集提供的DataGrid控件,在功能和界面样式上都完爆WinForm的DataGridView控件,以前需要在 DataGridView控件上进行某列的统计,需要在GridVi ...

  3. linux的vnc- rdesktop远程登录windows桌面

    使用vnc来实现任何平台之间(windows, linux, mac等)的远程桌面互访 vnc:virtual network computing 分 vnc server和 vnc client 在 ...

  4. 织梦dedecms如何快速使用拼音首字母做栏目名称

    织梦默认使用拼音为保存目录的时候使用的是中文全拼,当遇到栏目名称比较长的时候目录名称看起来有点冗长,这时候大多数站长喜欢使用拼音首字母作为栏目的保存目录,那么有没有什么快速的办法能让我们快速的使用首字 ...

  5. HTML5中的Range对象的研究

    一:Range对象的概念 Range对象代表页面上的一段连续区域,通过Range对象,可以获取或修改页面上的任何区域,可以通过如下创建一个空的Range对象,如下: var  range = docu ...

  6. 快还要更快,让PHP 7 运行更加神速

    导读 PHP 7 比5.x 快上很多,即使只有单纯的版本升级就已经很有感,不过大家还是希望它变得越来越快,这时再做些小调整就会更有fu,Let's try it! 事前准备 说到PHP 7,那一定跑不 ...

  7. C++中的memset()函数 ------------转自:http://www.360doc.com/content/10/1006/18/1704901_58866679.shtml

    memset()函数可以对大内存的分配进行很方便的操作(初始化),所谓“初始化”,当然是指将你定义的变量或申请的空间赋予你所期望的值,例如语句int i=0;就表明定义了一个变量i,并初始化为0:如果 ...

  8. [BZOJ1941][Sdoi2010]Hide and Seek

    [BZOJ1941][Sdoi2010]Hide and Seek 试题描述 小猪iPig在PKU刚上完了无聊的猪性代数课,天资聪慧的iPig被这门对他来说无比简单的课弄得非常寂寞,为了消除寂寞感,他 ...

  9. 2维特征Feature2D(转)

    转自:http://blog.csdn.net/yang_xian521/article/details/6901762 主要介绍的是如何用SURF进行特征匹配,和SIFT的使用方法基本一致.

  10. maven常见问题

    maven常见错误: 一..在Eclipse导入已存在工作空间的项目,出现 情况1: Scanning errors (1):1 Could not read pom.xml 就是pom.xml出现了 ...