Android View 系統 1 - View樹

風靈使發表於2018-11-06

View簡介

在Android作業系統中,幾乎所有的UI元素都是基於ViewViewGroup建立出來的。View就是一塊可以用來進行繪畫,可以處理輸入事件進行互動的矩形區域,而ViewGroup就是一種可以容納View的矩形容器。
下圖就是ViewGroupView組成的UI佈局結構。ViewViewGroup通過這種樹形結構組合在一起,構成了我們在手機螢幕上看到的一個個的複雜的介面。

View層次結構的圖示

從設計模式的角度看,ViewGroupView是組合模式的典型應用。View是基本的控制元件元素,ViewManager介面定義了新增、刪除View的介面addView、removeViewViewGroup實現了ViewParent的介面,因此可以作為容器管理View,同時ViewGroup又繼承自View,可以被其他的ViewGroup管理。這樣ViewGroupView就可以組成上面的樹狀結構了。

View類圖結構

實際的程式碼實現過程中很少會直接使用ViewGroupView,而是使用繼承自它們的之類,如FrameLayoutLinearLayoutListView等是ViewGroup的子類,TextViewImageViewSurfaceView等是View的子類。

建立View樹

上面介紹了ViewGroupView是通過View樹的形式組合在一起的,一個View樹也就是一個Layout佈局,下面就介紹一下怎樣建立、管理Layout佈局。

Layout資源建立View

最常見的建立Layout的方式就是使用Layout資源。Android 應用的程式碼目錄結構裡,在資源res資料夾下有一個layout資料夾,應用中使用的layout資源都會放在這個資料夾下。父View與子View是以XML的形式巢狀在一起的,下面就是一個layout的例子:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    android:orientation="vertical" >
    <FrameLayout
        android:id="@+id/container"
        android:layout_width="fill_parent"
        android:layout_height="fill_parent" >
        <TextView
            android:id="@+id/text"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="I am a TextView" />
    </FrameLayout>
    <Button
        android:id="@+id/button"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="I am a Button" />
</LinearLayout>

同時layout之間也可以相互巢狀,如下面的形式:

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

當在程式碼中需要使用XML資源裡定義的layout時可以使用下面的程式碼:

LayoutInflater inflater = getLayoutInflater();
View view = inflater.inflate(R.layout.main, null);

很多類中將通過LayoutInflater載入資源的過程也封裝好了,只需要提供資源就可以了,如設定ActivityContentView的程式碼:

@Override
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.main_layout);
}

通過Layout資源建立View樹的優勢是層次結構清晰,管理方便。同時View樹中各個View的屬性也可以在layout資源裡進行設定。缺點是無法在應用執行時對View樹結構進行變化。

從程式碼建立View樹

從Java程式碼中通過ViewGroupaddViewremoveView等介面同樣可以管理View樹,如下面的程式碼:

TextView text = new TextView(this);
Button button = new Button(this);

FrameLayout frame = new FrameLayout(this);
frame.addView(text);

LinearLayout linear = new LinearLayout(this);
linear.setOrientation(LinearLayout.VERTICAL);
linear.addView(frame);
linear.addView(button);

從程式碼中建立View樹最多的應用場景是在使用AdapterView的子類的時候,如ListView、GridView、Spinner等。繼承自AdapterView的控制元件一般會通過一個介面卡Adapter來新增、刪除自己的子View

ListView list = new ListView(this);
ArrayAdapter<String> adapter = new ArrayAdapter<String>(this,
        android.R.layout.simple_list_item_1, myStringArray);
list.setAdapter(adapter);

在程式碼中建立View樹的優點是對View的管理比較靈活,可以在程式執行過程中動態的管理View樹的狀態,缺點就是程式碼實現比較複雜,程式的擴充套件性不好不容易維護。

通常在開發過程中這兩種建立View樹的方式是結合在一起使用的。

管理View

View樹裡的每一個View都會有一個整型ID,用來方便對這個View進行查詢管理,View的ID可以在佈局檔案裡定義(如前面佈局資原始檔裡為TextView指定的android:id="@+id/text")也可以在View例項建立後通過View.setId(int id)方法設定。通過View樹中根節點的findViewById(int id)方法就可以查詢到id對應的View。

LayoutInflater inflater = getLayoutInflater();
View view = inflater.inflate(R.layout.main, null);
TextView text = (TextView) view.findViewById(R.id.text);

View樹中每個View的 ID 並不強制要求是唯一的,這樣可以方便一些子View樹重複利用(如ListView中每個item的佈局),但是通過findViewById()查詢時只會得到最先找到的View,因此建議在資原始檔中定義的View使用唯一的ID。

建立了view樹以後,還可能會根據實際場景對View樹裡進行新增或者刪除View的操作,使用前面提到過的addView、removeView介面就可以,如:

LayoutInflater inflater = getLayoutInflater();
FrameLayout container = (FrameLayout) inflater.inflate(R.layout.main, null);

TextView text = (TextView) container.findViewById(R.id.text);
container.removeView(text);

Button button = new Button(this);
button.setId(button.hashCode());
container.addView(button);

相關文章