Android用户界面布局(layouts)
Android用戶界面布局(layouts)
?
備注:view理解為視圖
?
一個布局定義了用戶界面的可視結(jié)構(gòu),比如activity的UI或是APP widget的UI,我們可以用下面兩種方式來聲明布局:
(1)??在XML文件中聲明UI元素,Android提供一種直觀的XML詞匯(vocabulary,應(yīng)該是指屬性表)來對應(yīng)View類及其子類,比如那些用于部件(widget)和布局的詞匯。
(2)??在運行時實例化(初始化)布局元素,我們的應(yīng)用能夠以編程的方式創(chuàng)建View和ViewGroup對象(和操縱它們的屬性)。
?
Android應(yīng)用框架(framework)使我們能夠很靈活使用這兩種方式來聲明和管理我們應(yīng)用的UI,比如,我們可在XML中聲明我們應(yīng)用默認(rèn)的布局,包括將在它們和它們屬性中顯示的屏幕元素。然后我們可以在應(yīng)用中增加代碼來修改屏幕對象的狀態(tài),包括那些在XML和運行時聲明的。
?
在XML中聲明UI的好處在于使我們可以更好地把控制行為的代碼和應(yīng)用程序的外觀分開。我們UI描述在應(yīng)用代碼之外,這意味著我們能夠在不修改代碼和重新編譯的情況下修改UI。比如,我們能夠為不同屏幕方向(橫向或是縱向)、不同的屏幕大小和多國語言創(chuàng)建XML布局。另外,在XML中聲明布局使得我們的UI更直觀,所以更容易調(diào)試問題。就這點而言,本文的重點在告訴我們?nèi)绾卧赬ML中聲明布局,如果我們對在運行時初始化View對象,可參考ViewGroup和View類參考文獻(xiàn)。
?
總的來說,定義UI元素的XML詞匯緊密遵循類和方法的結(jié)構(gòu)與命名,UI元素名對應(yīng)類型,而屬性名對應(yīng)方法名。確切地說,由于它們之間的一致性,我們可以從類方法名猜出XML屬性,或者可以通過xml元素猜出類方法。然而,請注意并不是所有的詞匯都是相同的,比如,EditText元素有一個text屬性對應(yīng)的是
EditText.setText()這個方法。
?
1.?????寫XML(Write the XML)
使用Android的XML詞匯,采用一系列嵌套的元素,我們能夠快速設(shè)計出UI布局和它們包含的屏幕元素,我們也可以采用相同的方式在HTML中創(chuàng)建網(wǎng)頁網(wǎng)站(web pages)。
?
每個布局文件必須明確的包含一個根元素,該元素必須是一個View或是ViewGroup對象。一旦我們定義了根元素后,就可以增加額外的布局對象或是widget作為子元素來逐步構(gòu)建了我們布局的視圖層級。比如,下面是使用一個垂直LinearLayout來包含一個TextView和一個button的XML布局:
<?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">
? ? <TextView android:id="@+id/text"
? ? ? ? ? ? ? android:layout_width="wrap_content"
? ? ? ? ? ? ? android:layout_height="wrap_content"
? ? ? ? ? ? ? android:text="Hello, I am a TextView"/>
? ? <Button android:id="@+id/button"
? ? ? ? ? ? android:layout_width="wrap_content"
? ? ? ? ? ? android:layout_height="wrap_content"
? ? ? ? ? ? android:text="Hello, I am a Button"/>
</LinearLayout>
我們在XML中聲明了布局后,保存為xml擴(kuò)展名的文件,次文件保存在我們Android工程的res/layout/文件夾下,這樣它將正確編譯。
?
2.?????加載XML資源(Load the XML Resource)
在編譯我們APP時,每個布局文件被編譯成一個View資源,我們就能在代碼中加載這些布局資源,這在Activity.onCreate()回調(diào)函數(shù)中實現(xiàn)。調(diào)用setContentView()函數(shù),并將布局資源的引用R.layout.layout_file_name傳遞給它。比如,如果我們的XML布局保存在main_layout.xml文件中,我們可以像下面這樣在activity中加載資源:
publicvoid onCreate(Bundle savedInstanceState){
? ? super.onCreate(savedInstanceState);
? ? setContentView(R.layout.main_layout);
}
當(dāng)activity被啟動的時候,Android framework調(diào)用我們這個activity的onCreate回調(diào)函數(shù)。
?
3.?????屬性(Attributes)
每個View和ViewGroup對象支持它們各自的一系列XML屬性,一些屬性針對于具體的View對象(比如,TextView支持textSize屬性),這些屬性也被哪些擴(kuò)展自這些類的View對象繼承(也就是View和ViewGroup的屬性,對繼承了它們的子類也有效)。有些屬性對于所有的View對象時公共的,因為它們是繼承之根View類(如id屬性)。另外,一些參數(shù)被作為“布局參數(shù)(layout parameters)”,它們描述View對象的某一布局方向(certain layout orientations),布局參數(shù)由對象的父對象ViewGroup定義。
?
4.?????唯一標(biāo)識符(ID)
任何View對象都有一個與它關(guān)聯(lián)的整數(shù)ID,這可以在View樹中唯一地標(biāo)識每個View對象。當(dāng)APP編譯時,這個ID被引用作為一個整數(shù),但I(xiàn)D通常被分配在布局XML文件中作為一個字符串(string),放在id屬性中。這是所有View對象公共的XML屬性(被View類定義)和我們將經(jīng)常使用它,一個ID的語法,在XML標(biāo)記如下:
android:id="@+id/my_button"
以@符號開始的字符串告訴XML解析器應(yīng)解析和展開ID字符串的剩余部分并識別它作為一個ID資源。+符號表示這是一個新資源名稱,必須被創(chuàng)建和增加到我們的資源中(在R.java文件中)。Android framework還提供其他的ID資源,當(dāng)引用一個Android資源ID,我們不需要這個+符號,當(dāng)時必須增加android包命名空間(package namespace),像下面這樣:
android:id="@android:id/empty"
在適當(dāng)?shù)牡胤绞褂胊ndroid包命名空間,我們現(xiàn)在引用的ID是來之a(chǎn)ndroid.R資源類,而不是本地資源類(本地的資源類是<包名>.R,是自動生成的)。
?
為了創(chuàng)建視圖和在應(yīng)用中引用它們,一個常用的模式如下:
(1)??在布局文件中定義一個view/widget和為其分配一個唯一的ID:
<Buttonandroid:id="@+id/my_button"
? ? ? ? android:layout_width="wrap_content"
? ? ? ? android:layout_height="wrap_content"
? ? ? ? android:text="@string/my_button_text"/>
(2)??然后創(chuàng)建view對象的實例并從布局中獲取它(一般在onCreate()方法中)
Button myButton= (Button) findViewById(R.id.my_button);
當(dāng)創(chuàng)建一個相對布局(RelativeLayout)時,定義view對象的ID是非常重要的。在相對布局中,兄弟view能夠通過唯一的ID引用來定義它們之間布局的相對位置。
?
一個ID在整個視圖數(shù)中不需要是唯一的,但必須是我們要搜索的數(shù)部分是唯一的(通常是整棵樹,所以可能的話最好是整棵樹)。
?
?
5.?????布局參數(shù)(Layout Parameters)
名為layout_something的XML布局屬性定義了view的布局參數(shù),這些參數(shù)適用于view所在的ViewGroup。
?
每個ViewGroup類實現(xiàn)一個擴(kuò)展自ViewGroup.LayoutParams的嵌套類,該子類包括定義了每個子view大小和位置的屬性類型,適用于視圖組(view group)。正如我們在下圖看到的,父視圖組定義了每個子視圖(包括子視圖組,比如這里的子視圖有下圖的View,子視圖組有下圖的RelativeLayout)的布局參數(shù)。
圖1
注意每個LayoutParams子類有它自己設(shè)置值的語法,每個子元素必須定義適用于其父元素的LayoutParams,雖然父元素也可以為它的子元素定義不同的LayoutParams。
?
所有的視圖組都包含一個寬度和高度(layout_width和layout_height),且每個視圖都要定義它們。很多LayoutParams頁可以包括可選的margins(頁邊的空白)和borders(邊距)。
?
我們可以使用精確的度量指定寬度和高度,盡管我們可能很少這么使用。更常見的是我們將使用下面的常數(shù)設(shè)置寬度或是高度:
(1)??wrap_content?告訴我們view調(diào)整自身內(nèi)容所需要的尺寸來調(diào)整自己的大小。
(2)?? fill_parent?(從API 8版本開始重命名為match_parent?)告訴我們的視圖和它的父視圖組一樣大小就可以。
?
通常,不推薦使用比如是像素這樣的絕對單位來指定布局寬度和高度,相反,使用比如是和密度無關(guān)的像素單元(density-independent pixel units,dp)相對度量。使用wrap_content或fill_parent是更好的辦法,因為這樣它有助于確保我們的應(yīng)用程序在不同屏幕大小的設(shè)備上正常顯示,Android系統(tǒng)能夠接受的單位類型在Available Resources文檔中定義
(http://developer.android.com/guide/topics/resources/available-resources.html#dimension)
?
6.?????布局位置(Layout Position)
?
View的幾何形狀是矩形,一個view的位置采用一對left和top坐標(biāo)來表示,view的二維(可理解為尺寸)用width和height來表示,位置和尺寸的單位是像素。
?
可調(diào)用方法getLeft()和getTop()來獲取view的位置,前者返回代表view的矩形的左或是X坐標(biāo),后者返回代表view的矩形的上或是Y坐標(biāo)。這兩個方法都返回相對于其父對象的位置。比如,當(dāng)getLeft()返回20,意味著view位于其父對象左邊緣以右的20像素處。
?
另外,提供了一些避免沒必要計算的方法getRight()和getBottom(),這些方法返回代表view的矩形的右邊和下邊邊緣的坐標(biāo)。比如調(diào)用gerRight()相當(dāng)于這樣的計算:getLeft() + getWidth()。
?
7.?????大小、內(nèi)邊距和外邊距(Size,Padding and Margins)
View的大小用一個寬度和高度來描述,實際上,view有兩組寬度和高度的值。
?
第1對被稱為測量寬度和測量高度(measured width and measured height),這些長度定義一個view在其父view中的大小。測量尺寸(measured dimensions)能夠調(diào)用getMeasuredWidth()和getMeasuredHeight()。
?
第2對被簡稱為寬度和高度(width and height),或是有時候被稱為繪制寬度和高度(drawing width and drawing height)。這些尺寸定義了view在屏幕上繪制和布局時的實際大小,這些值可能,但不一定和測量寬度和測量高度相同,這個寬度和高度通過調(diào)用getWidth()和getHeight()獲得。
?
為了測量view的尺寸,一個view必須把它的padding考慮進(jìn)來,padding用像素來表示,一個view的上下左右部分都有padding。通過一個指定數(shù)量像素的padding來位移view的內(nèi)容。比如,包含2個像素點的一個左padding將使view的內(nèi)容相對于左邊界向右推移2個像素。Padding通過調(diào)用setPadding(int, int, int, int)方法來設(shè)置和調(diào)用getPaddingLeft()、getPaddingTop()、getPaddingRight()和getPaddingBottom()來查詢。
?
雖然一個view能夠定義一個padding,但它不提供任何對margins(外邊距)的支持。但是view groups提供這樣的支持,參考ViewGroup和 ViewGroup.MarginLayoutParams以獲取更多的信息。
?
為獲取更多關(guān)于尺寸的信息,請看Dimension Values
http://developer.android.com/guide/topics/resources/more-resources.html#Dimension
?
8.?????常見布局(Common Layouts)
ViewGroup類的子類提供獨特的方式來顯示嵌入到ViewGroup中view。下面是一些常見的布局類型內(nèi)置在Android平臺中。
?
注意:雖然我們可以在另一個布局中嵌入一個或是多個布局來完成我們的UI設(shè)計,我們應(yīng)盡可能保持我們的布局層次結(jié)構(gòu)盡可能淺。有更少嵌套的布局在繪制時更快(寬視圖層次結(jié)構(gòu)比深度視圖層次結(jié)構(gòu)更好,a wide view hierarchy is better than a deepview hierarchy)。
圖2
(1)??線性布局(Linear Layout)
線性布局以一個單一的水平或是垂直的排列方式來組織里面的view,如果布局窗口的長度超過屏幕的長度,它就創(chuàng)建一個滾動條。
?
(2)??相對布局(Relative Layout)
使我們能夠指定每個子view之間的相對位置(比如子view A在子view B左邊的相對位置),或是相對于父view的位置(和父view的頂部對齊)。
?
(3)??網(wǎng)頁視圖(Web View)
顯示網(wǎng)頁。
?
9.?????建立適配器的布局(Building Layouts with an Adapter)
當(dāng)我們布局的內(nèi)容是動態(tài)的或是不是預(yù)設(shè)的,我們可以使用繼承自AdapterView的布局來在運行時填充包含有views的布局。一個AdapterView的子類使用一個Adapter來綁定數(shù)據(jù)到它的布局中。這個Adapter表現(xiàn)為數(shù)據(jù)源和AdapterView布局的中間人,這個Adapter獲取數(shù)據(jù)(比如從一個數(shù)據(jù)或是一個數(shù)據(jù)庫查詢)和將每個條目轉(zhuǎn)換為一個能被添加到AdapterView布局中的view。
?
依靠一個adapter支持的常見布局包括:
圖3
(1)??列表視圖(List View)
顯示一個滾動的單一列清單。
?
(2)??網(wǎng)格視圖(Grid View)
顯示一個滾動列和行的網(wǎng)格。
?
10.? 向一個適配器view填充數(shù)據(jù)(Filling an adapter view with data)
我們能夠通過綁定AdapterView實例到一個Adapter來填充像ListView或是GridView這樣的AdapterView,Adapter從一個外部數(shù)據(jù)源獲取數(shù)據(jù)和創(chuàng)建一個代表了每個輸入條目的view。
?
Android提供了多個Adapter子類,這些子類有助于獲取不同類型的數(shù)據(jù)和為一個AdapterView建立view,兩個最常見的adapters如下:
(1)??ArrayAdapter(數(shù)組適配器)
當(dāng)數(shù)據(jù)源是一個數(shù)組時使用這個適配器,默認(rèn)情況,ArrayAdapter通過在每個數(shù)組項上調(diào)用toString()來為每個數(shù)組項創(chuàng)建一個view和將這些內(nèi)容保存在TextView。
?
比如,如果我們想要在ListView中顯示一個字符串?dāng)?shù)組,使用構(gòu)造函數(shù)初始化一個新的ArrayAdapter來指定每個字符串和這個字符串?dāng)?shù)據(jù)的布局:
?
ArrayAdapter adapter = new ArrayAdapter<String>(this, android.R.layout.simple_list_item_1, myStringArray);這個構(gòu)造函數(shù)的參數(shù)如下:
This:我們APP的上下文(context)。
android.R.layout.simple_list_item_1:布局,包含一個TexView(文本框)中數(shù)組的每個字符串。
myStringArray:字符串?dāng)?shù)據(jù)。
?
然后簡單的調(diào)用我們ListView的setAdapter(),如下:
ListView listView = (ListView) findViewById(R.id.listview); listView.setAdapter(adapter);如果要自定義每項的外觀,我們可以重寫(override)我們保存在數(shù)組中的對象的toString()方法,或者,為不同于TextView的對象的每一項創(chuàng)建view,徐璈擴(kuò)展ArrayAdapter類和重寫getView()來獲得我們想要的每一項的view類型。
?
(2)??SimpleCursorAdapter
當(dāng)我們從光標(biāo)處獲取數(shù)據(jù)時使用這個adapter,在使用SimpleCursorAdapter時,我們必須在光標(biāo)處為每行指定要使用布局,在光標(biāo)處的列應(yīng)該插入這個布局的views。比如,如果我們要創(chuàng)建一個人的名字和電話號碼列表,我們能夠執(zhí)行一個返回一個光標(biāo)的查詢,這個查詢的結(jié)果包括每個人的一行和名字與電話號碼的列。然后我們可以創(chuàng)建一個字符串?dāng)?shù)組來指定光標(biāo)處開始的哪些列,這些列對應(yīng)于每個結(jié)果中布局的內(nèi)容,創(chuàng)建一個整數(shù)數(shù)組來指定每一列重要放置的views。
String[] fromColumns = {ContactsContract.Data.DISPLAY_NAME, ContactsContract.CommonDataKinds.Phone.NUMBER}; int[] toViews = {R.id.display_name, R.id.phone_number};當(dāng)我們實例化SimpleCursorAdapter,傳遞布局用于每個結(jié)果,cursor參數(shù)包含了結(jié)果,另外兩個參數(shù)是兩個數(shù)組:
SimpleCursorAdapter adapter = new SimpleCursorAdapter(this, R.layout.person_name_and_number, cursor, fromColumns, toViews, 0); ListView listView = getListView(); listView.setAdapter(adapter);SimpleCursorAdapter然后在光標(biāo)處創(chuàng)建一個view,使用提供的布局R.layout.person_name_and_number將每個fromColums項插入到對應(yīng)的toView視圖中。
?
如果在我們APP聲明周期之內(nèi),我們改變了由adapter讀取的底層數(shù)據(jù),我們應(yīng)該調(diào)用notifyDataSetChanged(),這將通知這個視圖數(shù)據(jù)已經(jīng)改變,它應(yīng)該刷新自己。
?
11.? 處理點擊事件(Handling click events)
通過實現(xiàn)AdapterView.OnItemClickListener接口,我們可以響應(yīng)一個AdapterView每一項的點擊事件,比如:
// Create a message handling object as an anonymous class. private OnItemClickListener mMessageClickedHandler = new OnItemClickListener() {public void onItemClick(AdapterView parent, View v, int position, long id) {// Do something in response to the click} };listView.setOnItemClickListener(mMessageClickedHandler);?
?
參考鏈接:
Layouts
http://developer.android.com/guide/topics/ui/declaring-layout.html
?
XML布局
http://weimingtom.iteye.com/blog/1276406
?
android2.2官方開發(fā)手冊(02-01)-DeclaringLayout-設(shè)計布局
http://blog.csdn.net/forlong401/article/details/6295024
?
?
總結(jié)
以上是生活随笔為你收集整理的Android用户界面布局(layouts)的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 并不是所有的程序员都适合做技术管理
- 下一篇: Android XML使用的学习记录