Android用戶界面設(shè)計(jì):相對(duì)布局
理解布局對(duì)于良好的Android程序設(shè)計(jì)非常重要。在這個(gè)教程里,你將學(xué)到相對(duì)布局的所有知識(shí),相對(duì)布局用于將用戶界面控件或小工具相對(duì)于其它控件或它們的父級(jí)布局組織在屏幕上。當(dāng)使用正確的時(shí)候,相對(duì)布局可以是很強(qiáng)大和靈活布局,很多有趣的Android程序用戶界面都可以基于它來(lái)設(shè)計(jì)。
什么是相對(duì)布局
除了將控件顯示在一行或一列的線性布局,相對(duì)布局也是Android用戶界面設(shè)計(jì)使用得很普遍的布局類型。和其它布局很相似,相對(duì)布局可以通過(guò)XML布局資源來(lái)定義也可以用Java程序來(lái)定義。相對(duì)布局的功能就像它的名字表達(dá)的一樣:它相對(duì)其它控件或父控件本身來(lái)組織控件。
這是什么意思呢?意思是子控件,比如ImageView,TextView,和Button控件,可以放在另外一個(gè)控件的上面,下面,或是左邊或者右邊。子控件可以相對(duì)于父控件(相對(duì)布局容器)放置,包括放置在布局的頂部,底部,左部或右部邊緣。
相對(duì)布局子控件位置使用規(guī)則來(lái)定義。這些規(guī)則定義了相對(duì)布局內(nèi)的控件如何顯示。相對(duì)布局的完整規(guī)則列表請(qǐng)參見(jiàn)RelativeLayout類的Android SDK文檔。相關(guān)的用于XML資源的XML屬性也可以在文檔中找到。
注意:規(guī)則要求每個(gè)子控件恰當(dāng)?shù)卦O(shè)置了它的id屬性。
一個(gè)簡(jiǎn)單的相對(duì)布局
相對(duì)布局最好使用例子來(lái)解釋。假設(shè)我們要設(shè)計(jì)一個(gè)屏幕,包含一個(gè)EditText控件和一個(gè)Button控件。我們希望Button顯示在EditText控件的右邊。因此,我們可以定義一個(gè)包含兩個(gè)子控件的相對(duì)布局:子控件分別是EditText和Button。EditText控件可能有一個(gè)規(guī)則說(shuō):將這個(gè)控件放置在父控件(布局)的左手邊并且在第二個(gè)控件(Button)的左邊。同時(shí),Button控件可能有一個(gè)規(guī)則:將這個(gè)控件放置在父控件(布局)的右手邊。
下面的圖片就展示了這樣一個(gè)相對(duì)布局,分別是豎屏和橫屏模式。這個(gè)相對(duì)布局有兩個(gè)子控件:一個(gè)EditText控件和一個(gè)Button控件。
#p#
定義帶有相對(duì)布局的XML資源文件
設(shè)計(jì)程序用戶界面最方便和可維護(hù)的方法是創(chuàng)建XML布局資源。這個(gè)方法極大地簡(jiǎn)化了UI設(shè)計(jì)過(guò)程,將很多靜態(tài)創(chuàng)建和用戶界面控件的布局以及控件屬性的定義移到XML中去,取代了寫(xiě)代碼。
XML布局資源必須存儲(chǔ)在/res/layout項(xiàng)目目錄下。讓我們看看前一節(jié)介紹的相對(duì)布局。這個(gè)布局資源文件,恰當(dāng)?shù)孛麨?res/layout/relative.xml,在XML中如下定義:
- xmlns:android="http://schemas.android.com/apk/res/android"
- android:layout_height="fill_parent"
- android:layout_width="fill_parent">
- android:id="@+id/EditText01"
- android:hint="Enter some text..."
- android:layout_alignParentLeft="true"
- android:layout_width="fill_parent"
- android:layout_toLeftOf="@+id/Button01"
- android:layout_height="wrap_content">
- android:id="@+id/Button01"
- android:text="Press Here!"
- android:layout_width="wrap_content"
- android:layout_alignParentRight="true"
- android:layout_height="wrap_content">
回憶一下,在Activity中,只需要在onCreate()方法中添加一行代碼來(lái)在屏幕上加載和顯示布局資源。如果布局資源存放在/res/layout/relative.xml文件中,這行代碼應(yīng)該是:
- setContentView(R.layout.relative);
這個(gè)相對(duì)布局設(shè)置了寬和高填充整個(gè)屏幕,并且它的子控件配置了三個(gè)規(guī)則:
◆EditText01:對(duì)齊到布局的左手邊
◆EditText01:顯示在Button01的左邊
◆Button01:對(duì)齊到布局的右手邊
用程序定義相對(duì)布局
你也可以用程序創(chuàng)建和配置相對(duì)布局。這通過(guò)使用RelativeLayout類(android.widget.Relative)來(lái)實(shí)現(xiàn)。你會(huì)在RelativeLayout.LayoutParams類中找到具體的參數(shù)。同樣地,典型的布局參數(shù)(android.view.ViewGroup.LayoutParams),比如layout_height和layout_width,以及邊距參數(shù)(ViewGroup.MarginLayoutParams),也能用在RelativeLayout對(duì)象上。
你必須用Java創(chuàng)建屏幕內(nèi)容,然后向setContentView()方法提供一個(gè)包含所有要作為子視圖顯示的控件內(nèi)容的父布局對(duì)象,而不是像前面所示直接使用setContentView()方法來(lái)加載布局資源。在這里,你的父布局就是相對(duì)布局。例如,下面的代碼示例了如何用程序在活動(dòng)中實(shí)例化一個(gè)RelativeLayout并且在它的onCreate()方法中向它添加一個(gè)TextView和一個(gè)Button控件,就像前面一節(jié)展示的布局一樣:
- public void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- // setContentView(R.layout.relative);
- EditText ed = new EditText(this);
- RelativeLayout.LayoutParams params = new RelativeLayout.LayoutParams(LayoutParams.FILL_PARENT,
- LayoutParams.WRAP_CONTENT);
- params.addRule(RelativeLayout.ALIGN_PARENT_LEFT);
- // use same id as defined when adding the button
- params.addRule(RelativeLayout.LEFT_OF, 1001);
- ed.setLayoutParams(params);
- ed.setHint("Enter some text....");
- Button but1 = new Button(this);
- RelativeLayout.LayoutParams params2 = new RelativeLayout.LayoutParams(LayoutParams.WRAP_CONTENT,
- LayoutParams.WRAP_CONTENT);
- params2.addRule(RelativeLayout.ALIGN_PARENT_RIGHT);
- but1.setLayoutParams(params2);
- but1.setText("Press Here!");
- // give the button an id that we know
- but1.setId(1001);
- RelativeLayout layout1 = new RelativeLayout(this);
- layout1.setLayoutParams(new LayoutParams(LayoutParams.FILL_PARENT, LayoutParams.FILL_PARENT));
- layout1.addView(ed);
- layout1.addView(but1);
- setContentView(layout1);
- }
讓我們仔細(xì)看一下上面的Java代碼。首先我們像平常一樣創(chuàng)建一個(gè)EditText控件。我們給它一些RelativeLayout參數(shù),然后設(shè)置它的規(guī)則。在這里,我們?yōu)镋ditText控件創(chuàng)建2個(gè)規(guī)則。
接下來(lái),我們創(chuàng)建一個(gè)Button控件并且設(shè)置它的規(guī)則(對(duì)齊到父布局右邊緣)。最后,我們創(chuàng)建一個(gè)RelativeLayout對(duì)象,設(shè)置它的參數(shù),使用addView()方法添加兩個(gè)控件并且使用setContentView()方法加載顯示相對(duì)布局。
如你所見(jiàn),當(dāng)越來(lái)越多的控件要添加到屏幕時(shí),代碼量會(huì)很快地增長(zhǎng)。為了易組織和可維護(hù)性,用程序定義并使用布局最好是用在特殊情況而不是一般情況。#p#
探討相對(duì)布局的重要特性和屬性
現(xiàn)在讓我們來(lái)討論一些幫助配置相對(duì)布局和它的子控件的屬性。一些特定的屬性用于相對(duì)布局,也就是子規(guī)則,包括:
◆用于子控件在父布局中居中的規(guī)則,包括:水平居中,垂直居中,或者兩者皆居中。
◆用于子控件在父布局中排布的規(guī)則,包括:在頂部,底部,左,右邊緣放置。
◆用于子控件相對(duì)于其它子控件排布的規(guī)則,包括:在另一個(gè)控件頂,底,左,右邊緣放置。
◆用于子控件相對(duì)于其它子控件放置的規(guī)則,包括:在另一個(gè)控件上面,底下,左邊或右邊放置。
同樣的,通用的 ViewGroup-style屬性也可以應(yīng)用于相對(duì)布局。這些屬性包括:
◆通用布局參數(shù)比如layout_height(必須)和layout_width(必須)(類:ViewGroup.LayoutParams)
◆邊距布局參數(shù)比如margin_top, margin_left, margin_right和margin_bottom (類:ViewGroup. MarginLayoutParams)
布局參數(shù)比如layout_height和layout_width (類:ViewGroup.LayoutParams)
現(xiàn)在讓我們來(lái)實(shí)踐這些規(guī)則吧!
使用布局規(guī)則
讓我們看一個(gè)更復(fù)雜的屏幕設(shè)計(jì)。為了這個(gè)練習(xí),我們從查看最終屏幕效果開(kāi)始,然后再倒回來(lái)工作,并討論這個(gè)相對(duì)布局的特性和為了達(dá)到最終結(jié)果所使用的規(guī)則。
我們希望設(shè)計(jì)一個(gè)如下所示的屏幕:

為了使用相對(duì)布局來(lái)設(shè)計(jì)這個(gè)屏幕,參考以下步驟。
步驟1:在你的XML資源文件中定義一個(gè)相對(duì)布局
首先,在你的XML資源文件中定義一個(gè)相對(duì)布局。因?yàn)槟阆脒@個(gè)布局控制整個(gè)屏幕的內(nèi)容,所以設(shè)置它的高和寬屬性為fill_parent。你的XML資源文件應(yīng)該看起來(lái)像這樣:
- xmlns:android="http://schemas.android.com/apk/res/android"
- android:layout_height="fill_parent"
- android:layout_width="fill_parent">
步驟2:確定子控件
接下來(lái),我們確定需要什么樣的子控件。在這里,我們需要7個(gè)TextView控件(第個(gè)一種顏色)。像平常一樣配置它們,設(shè)置文本屬性為字符串,背景色,字號(hào)等等。將這些控件都放到相對(duì)布局中。
步驟3:定義相對(duì)布局規(guī)則
接下來(lái),我們?yōu)槊總€(gè)子控件定義規(guī)則,以使它們被繪制到合適的位置:
◆RED TextView控件沒(méi)有特別的設(shè)置。默認(rèn)地,這個(gè)控件將會(huì)被繪制到父布局的左上角。
◆ORANGE TextView控件在父布局中水平居中。因?yàn)樗锌丶J(rèn)都會(huì)靠向屏幕的左上角,這有效地將控件定位到父布局的邊緣頂部中間。
◆YELLOW TextView控件定位到父布局的右邊緣。因?yàn)樗锌丶J(rèn)都會(huì)靠向屏幕的左上角,這有效的定位控件到父布局的右上角。
◆GREEN TextView控件在父布局中垂直居中,并且設(shè)置為顯示在BLUE TextView控件的左邊。
◆BLUE TextView控件被定位在父控件的中心(水平和垂直)。這將它顯示在屏幕的中心位置。
◆INDIGO TextView控件在父局中垂直居中,并且設(shè)置為顯示在BLUE TextView控件的右邊。
◆VIOLET TextView控件被定位到父布局的底部邊緣。它的寬度也被設(shè)置為填滿父容器,允許它延伸到屏幕的底部邊緣。
如果你在你的XML資源文件中定義這些規(guī)則,XML文件代碼將看起如下:
- xmlns:android="http://schemas.android.com/apk/res/android"
- android:layout_height="fill_parent"
- android:layout_width="fill_parent">
- android:text="RED"
- android:id="@+id/TextView01"
- android:layout_height="wrap_content"
- android:background="#f00"
- android:gravity="center"
- android:textColor="#000"
- android:layout_width="wrap_content"
- android:padding="25dp">
- android:text="ORANGE"
- android:layout_height="wrap_content"
- android:background="#ffa500"
- android:gravity="center"
- android:textColor="#000"
- android:id="@+id/TextView02"
- android:layout_width="wrap_content"
- android:layout_centerHorizontal="true"
- android:padding="25dp">
- android:text="YELLOW"
- android:layout_height="wrap_content"
- android:background="#ffff00"
- android:gravity="center"
- android:textColor="#000"
- android:id="@+id/TextView03"
- android:layout_width="wrap_content"
- android:layout_alignParentRight="true"
- android:padding="25dp">
- android:text="GREEN"
- android:layout_height="wrap_content"
- android:background="#0f0"
- android:gravity="center"
- android:textColor="#000"
- android:id="@+id/TextView04"
- android:layout_width="wrap_content"
- android:layout_toLeftOf="@+id/TextView05"
- android:padding="25dp"
- android:layout_centerVertical="true">
- android:text="BLUE"
- android:layout_height="wrap_content"
- android:background="#00f"
- android:gravity="center"
- android:textColor="#fff"
- android:id="@+id/TextView05"
- android:layout_width="wrap_content"
- android:layout_centerInParent="true"
- android:layout_margin="10dp"
- android:padding="25dp">
- android:text="INDIGO"
- android:layout_height="wrap_content"
- android:gravity="center"
- android:textColor="#fff"
- android:id="@+id/TextView06"
- android:layout_width="wrap_content"
- android:layout_toRightOf="@+id/TextView05"
- android:background="#4b0082"
- android:padding="25dp"
- android:layout_centerVertical="true">
- android:text="VIOLET"
- android:layout_height="wrap_content"
- android:background="#ee82ee"
- android:gravity="center"
- android:textColor="#000"
- android:id="@+id/TextView07"
- android:layout_alignParentBottom="true"
- android:layout_width="fill_parent"
- android:padding="25dp">
#p#相對(duì)布局使用技巧
◆這里是一些使用相對(duì)布局的技巧。
◆相對(duì)布局的子控件必須有唯一的id屬性以使規(guī)則正確應(yīng)用。
◆當(dāng)心循環(huán)規(guī)則。循環(huán)規(guī)則發(fā)生在兩個(gè)控件具有互相指向的規(guī)則時(shí)。如果你在布局設(shè)計(jì)中使用了循環(huán)規(guī)則,你將會(huì)得到以下錯(cuò)誤信息:
IllegalStateException: Circular dependencies cannot exist in a RelativeLayout(相對(duì)布局中不允許存在循環(huán)依賴)
◆回憶一下相對(duì)布局規(guī)則的應(yīng)用被一次處理是很有用的
◆保持你的相對(duì)布局規(guī)則最小化。這減小了循環(huán)規(guī)則的機(jī)率并且使得你的布局更加可維護(hù)和靈活。
◆一般地,記住測(cè)試一下你的布局設(shè)計(jì)在橫屏和豎屏模式下,以及在不同的屏幕大小和解決方案下是不是符合預(yù)期的。
◆使用相對(duì)布局代替嵌套線性布局以改進(jìn)程序性能和響應(yīng)能力。
總結(jié)
Android程序用戶界面使用布局來(lái)定義,相對(duì)布局是用于使得程序屏幕更加靈活和強(qiáng)大的布局類型之一。相對(duì)布局允許子控件相對(duì)于其它子控件和相對(duì)于父控件(邊緣以及水平和垂直居中)來(lái)組織。一旦你掌握了如何使用相對(duì)布局的規(guī)則,它們可以有非常多的用處,使你能夠創(chuàng)建復(fù)雜布局,而不需要過(guò)多嵌套不同的布局,因此也改進(jìn)了性能。
【編輯推薦】