Android原理之 View、ViewGroup

 作過Android 應用開發的朋友都知道,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佈局,這個例子能夠很好的說明上面的一些概念。

<?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://blog.csdn.net/droidpioneer/article/details/6706695


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章