Android View 系統 1
View簡介
在Android作業系統中,幾乎所有的UI元素都是基於View
和ViewGroup
創建出來的。View就是一塊可以用來進行繪畫,可以處理輸入事件進行互動的矩形區域,而ViewGroup
就是一種可以容納View的矩形容器。
下圖就是ViewGroup
和View
組成的UI佈局結構。View
和ViewGroup
通過這種樹形結構組合在一起,構成了我們在手機螢幕上看到的一個個的複雜的介面。
從設計模式的角度看,ViewGroup
和View
是組合模式的典型應用。View
是基本的控制元件元素,ViewManager
介面定義了新增、刪除View
的介面addView
、removeView
ViewGroup
實現了ViewParent
的介面,因此可以作為容器管理View,同時ViewGroup
又繼承自View
,可以被其他的ViewGroup
管理。這樣ViewGroup
和View
就可以組成上面的樹狀結構了。
實際的程式碼實現過程中很少會直接使用ViewGroup
和View
,而是使用繼承自它們的之類,如FrameLayout
、LinearLayout
、ListView
等是ViewGroup
的子類,TextView
、ImageView
、SurfaceView
等是View的子類。
建立View樹
上面介紹了ViewGroup
和View
是通過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
載入資源的過程也封裝好了,只需要提供資源就可以了,如設定Activity
的ContentView
的程式碼:
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main_layout);
}
通過Layout資源建立View樹的優勢是層次結構清晰,管理方便。同時View樹中各個View的屬性也可以在layout資源裡進行設定。缺點是無法在應用執行時對View樹結構進行變化。
從程式碼建立View樹
從Java程式碼中通過ViewGroup
的addView
、removeView
等介面同樣可以管理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);