視圖(View)概述
翻譯至 Android.View.View Class Overview,水平有限,敬請諒解。
視圖(View)是一個矩形區域,它負責這個區域裏的繪製和事件處理。視圖類是Android用戶界面的基礎類之一。視圖組(ViewGroup)是視圖的子類,是一個容器,專門負責佈局。視圖組本身沒有可繪製的元素。
開發用戶界面可以先閱讀開發者嚮導的用戶界面(User Interface)部分。
該文章包含:
聲明佈局
創建菜單
公用佈局對象
AdapterView綁定數據
處理UI事件
應用風格(styles)或主題(themes)
自定義組件
Android怎樣繪製視圖
使用視圖
一個窗口中的所有視圖是一個樹形結構。你可以通過代碼創建視圖,也可以通過XML佈局文件來創建。文本、圖像都是視圖的派生類。
視圖和其子類具有如下共同特性:
設置屬性,例如設置文本視圖的文本。不同的子類具有不同的屬性,這些屬性在設計時可以設定。
設置焦點,爲了響應用戶輸入,Android框架會處理焦點的轉移。要把焦點轉移到特定視圖上,可以使用requestFocus()函數。
設置監聽器(listener),視圖可以讓客戶端設置監聽器,特定事件發生時這些監聽器會收到通知。例如,視圖得到或失去焦點時,會收到關於焦點的通知。你可以使用setOnFocusChangeListener(View.OnFocusChangeListener)來註冊監聽器。例如,按鈕Button就有一個點擊事件的監聽器。
設置可見性,用setVisibility(int)顯示和隱藏視圖。
Android框架負責視圖的測量(measuring)、佈局(laying out)、繪製(drawing)。一般情況你不需要調用這些方法,除非你重載ViewGroup這樣的佈局類。
自定義視圖
自定義視圖需要重載下列一些方法。
IDs
視圖有整數ID,這些ID一般在XML佈局文件中分配。一般的樣式
定義一個按鈕並分配一個唯一ID
<Button id="@+id/my_button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/my_button_text"/>
onCreate函數創建視圖時,查找一個按鈕
Button myButton = (Button) findViewById(R.id.my_button);
視圖ID並不要求是全局唯一,不過爲了便於搜索最好在視圖樹的局部是唯一。
位置
視圖在幾何上就是一個矩形,左上角的left和top座標定位,寬width和高height表示尺寸大小,單位是像素pixel。
使用getLeft()和getTop()獲取左上角位置,這些位置都是相對於父視圖。
此外還有幾個方便方法getRight()和getBottom()獲得右邊和底部位置。
尺寸,內間距padding,外間距margins
視圖的尺寸用寬和高表示,一個視圖有兩對寬高值。
第一對寬高值是測量值(measured width, measured height),測量值是子視圖相對父視圖的尺寸大小期望值。可以用getMeasuredWidth()和getMeasuredHeight()獲取。
第二對寬高值是實際值,實際尺寸是視圖完成佈局後繪製時用到的值。
測量尺寸大小時要計算內間距padding,內間距表示了視圖內各個子控件到父控件上下左右四條邊的間距。
普通視圖不支持外間距,只有ViewGroup支持。詳見ViewGroup.MarginLayoutParams。
佈局Layout
佈局分兩個階段(pass):測量階段(measure pass)和佈局階段(layout pass)。測量階段在measure(int, int)方法中實現,整個過程就是從上至下的視圖樹遍歷。在這個遞歸過程,每個視圖都提供尺寸大小描述。測量階段的最後,每個視圖都保存了自己的測量結果。佈局階段在layout(int, int, int, int)函數中實現,這也是一個從上至下的過程。在佈局階段,每個父視圖使用測量階段的估算值爲子視圖安排位置和大小。
當視圖的measure()方法返回後,它和它的子控件的測量值都已經計算出來了。子控件的測量值都要考慮父視圖的區域限制,這就保證了在測試階段結束時,每個父視圖能接受其所有子控件的測量結果。子控件的measure()方法可能被多次調用。例如,包含了尺寸不確定的子控件,父控件會對每個子控件調用一次measure()方法,然後再對尺寸明確的子控件調用measure()方法,這樣作是爲了保證沒有確切尺寸的子控件不至於太大或太小。
測量階段會用到兩個類:View.MeasureSpec和LayoutParams。視圖使用View.MeasureSpec類來表明自己所期望的位置和測量
方式,LayoutParams則是來表明自己期待的大小。
它們都可以使用下面的值:
確切的數值
MATCH_PARENT,在父控件裏儘可能的大(除去內間距padding值)。
WRAP_CONTENT,儘可能的小,只要能容納自己的子控件即可(加上內間距padding值)。
LayoutParams有一些派生類,會被視圖組ViewGroup用到。例如,AbsoluteLayout包含了X和Y值,用來描述佈局時的絕對位置。
MeasureSpecs在父視圖向子控件詢問佈局期望時會被用到。它有三種模式:
UNSPECIFIED,未指定,父控件向子控件詢問佈局期望值。例如,線性佈局類LinearLayout想知道子控件在寬爲240的時候高的期望值,便可以調用子控件的measure()方法,並在傳遞參數中指定高爲UNSPECIFIED,寬爲確定值240像素。
EXACTLY,確定值,父控件指定子控件的尺寸,並要求該子控件的子控件也必須適應這個尺寸。
AT_MOST,最大值,父控件指定子控件的最大尺寸,並要求該子控件的子控件也必須適應這個尺寸。
當視圖想父控件再次對自己執行佈局操作時,可以調用requestLayout(),一般在視圖的尺寸發生改變時會有這種需求。
繪製Drawing
繪製按照視圖樹的順序執行。視圖繪製時會先繪製子控件。如果視圖的背景可見,視圖會在調用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()。
觸摸屏模式Touch Mode
當用戶使用方向鍵盤(D-pad)操作時,當前控件需要聚焦高亮來提示用戶。但是對於觸摸屏,就不再需要這種高亮了。我們管這種模式叫觸摸屏模式。
用戶一接觸觸摸屏設備就進入觸摸屏模式。從此,只有isFocusableInTouchMode()函數返回true的視圖才能聚焦高亮,例如文本框。而按鈕就不需要在觸摸屏模式下高亮了。
用戶一接觸方向鍵,界面就退出觸摸屏模式,並找到當前哪個視圖需要聚焦高亮,以便用戶在鍵盤模式下也能確認正在操作的控件。
觸摸屏模式是全局性的,跨Activity的。isInTouchMode()函數可以獲得是否在觸摸屏模式下。
滾動Scrolling
視圖本身支持滾動,包括XY的偏移位置和滾動條的繪製。
標籤Tag
標籤用於儲藏對象
動畫Animation
視圖可以附加Animation對象,設置動畫setAnimation(Animation),啓動動畫startAnimation(Animation)。Animation可以按時間軸改變視圖的位移、縮放大小、旋轉角度和透明度,來製造動畫效果。Animation的效果是包括了該視圖的子視圖。動畫啓動後,框架就負責重繪該視圖。