理解布局对于良好的Android程序设计非常重要。在这个教程里,你将学到相对布局的所有知识,相对布局用于将用户界面控件或小工具相对于其它控件或它们的父级布局组织在屏幕上。当使用正确的时候,相对布局可以是很强大和灵活布局,很多有趣的Android程序用户界面都可以基于它来设计。

什么是相对布局

除了将控件显示在一行或一列的线性布局,相对布局也是Android用户界面设计使用得很普遍的布局类型。和其它布局很相似,相对布局可以通过XML布局资源来定义也可以用Java程序来定义。相对布局的功能就像它的名字表达的一样:它相对其它控件或父控件本身来组织控件。

这是什么意思呢?意思是子控件,比如ImageView,TextView,和Button控件,可以放在另外一个控件的上面,下面,或是左边或者右边。子控件可以相对于父控件(相对布局容器)放置,包括放置在布局的顶部,底部,左部或右部边缘。

相对布局子控件位置使用规则来定义。这些规则定义了相对布局内的控件如何显示。相对布局的完整规则列表请参见RelativeLayout类的Android SDK文档。相关的用于XML资源的XML属性也可以在文档中找到。

注意:规则要求每个子控件恰当地设置了它的id属性。

一个简单的相对布局

相对布局最好使用例子来解释。假设我们要设计一个屏幕,包含一个EditText控件和一个Button控件。我们希望Button显示在EditText控件的右边。因此,我们可以定义一个包含两个子控件的相对布局:子控件分别是EditText和Button。EditText控件可能有一个规则说:将这个控件放置在父控件(布局)的左手边并且在第二个控件(Button)的左边。同时,Button控件可能有一个规则:将这个控件放置在父控件(布局)的右手边。

下面的图片就展示了这样一个相对布局,分别是竖屏和横屏模式。这个相对布局有两个子控件:一个EditText控件和一个Button控件。

 

Android用户界面设计:相对布局_相对布局


Android用户界面设计:相对布局_控件_02


定义带有相对布局的XML资源文件

设计程序用户界面最方便和可维护的方法是创建XML布局资源。这个方法极大地简化了UI设计过程,将很多静态创建和用户界面控件的布局以及控件属性的定义移到XML中去,取代了写代码。

XML布局资源必须存储在/res/layout项目目录下。让我们看看前一节介绍的相对布局。这个布局资源文件,恰当地命名为/res/layout/relative.xml,在XML中如下定义:



    1. xmlns:android="http://schemas.android.com/apk/res/android" 
    2.  
    3. android:layout_height="fill_parent" 
    4.  
    5. android:layout_width="fill_parent"> 
    6.  
    7.  
    8. android:id="@+id/EditText01" 
    9.  
    10. android:hint="Enter some text..." 
    11.  
    12. android:layout_alignParentLeft="true" 
    13.  
    14. android:layout_width="fill_parent" 
    15.  
    16. android:layout_toLeftOf="@+id/Button01" 
    17.  
    18. android:layout_height="wrap_content"> 
    19.  
    20.  
    21. android:id="@+id/Button01" 
    22.  
    23. android:text="Press Here!" 
    24.  
    25. android:layout_width="wrap_content" 
    26.  
    27. android:layout_alignParentRight="true" 
    28.  
    29. android:layout_height="wrap_content">



    回忆一下,在Activity中,只需要在onCreate()方法中添加一行代码来在屏幕上加载和显示布局资源。如果布局资源存放在/res/layout/relative.xml文件中,这行代码应该是:



      1. setContentView(R.layout.relative);



      这个相对布局设置了宽和高填充整个屏幕,并且它的子控件配置了三个规则:

      ◆EditText01:对齐到布局的左手边

      ◆EditText01:显示在Button01的左边

      ◆Button01:对齐到布局的右手边

      用程序定义相对布局

      你也可以用程序创建和配置相对布局。这通过使用RelativeLayout类(android.widget.Relative)来实现。你会在RelativeLayout.LayoutParams类中找到具体的参数。同样地,典型的布局参数(android.view.ViewGroup.LayoutParams),比如layout_height和layout_width,以及边距参数(ViewGroup.MarginLayoutParams),也能用在RelativeLayout对象上。

      你必须用Java创建屏幕内容,然后向setContentView()方法提供一个包含所有要作为子视图显示的控件内容的父布局对象,而不是像前面所示直接使用setContentView()方法来加载布局资源。在这里,你的父布局就是相对布局。例如,下面的代码示例了如何用程序在活动中实例化一个RelativeLayout并且在它的onCreate()方法中向它添加一个TextView和一个Button控件,就像前面一节展示的布局一样:



        1. public void onCreate(Bundle savedInstanceState) {  
        2.  
        3. super.onCreate(savedInstanceState);  
        4.  
        5. // setContentView(R.layout.relative);  
        6.  
        7. EditText ed = new EditText(this);  
        8.  
        9. RelativeLayout.LayoutParams params = new RelativeLayout.LayoutParams(LayoutParams.FILL_PARENT,  
        10.  
        11. LayoutParams.WRAP_CONTENT);  
        12.  
        13. params.addRule(RelativeLayout.ALIGN_PARENT_LEFT);  
        14.  
        15. // use same id as defined when adding the button  
        16.  
        17. params.addRule(RelativeLayout.LEFT_OF, 1001);  
        18.  
        19. ed.setLayoutParams(params);  
        20.  
        21. ed.setHint("Enter some text....");  
        22.  
        23. Button but1 = new Button(this);  
        24.  
        25. RelativeLayout.LayoutParams params2 = new RelativeLayout.LayoutParams(LayoutParams.WRAP_CONTENT,  
        26.  
        27. LayoutParams.WRAP_CONTENT);  
        28.  
        29. params2.addRule(RelativeLayout.ALIGN_PARENT_RIGHT);  
        30.  
        31. but1.setLayoutParams(params2);  
        32.  
        33. but1.setText("Press Here!");  
        34.  
        35. // give the button an id that we know  
        36.  
        37. but1.setId(1001);  
        38.  
        39. RelativeLayout layout1 = new RelativeLayout(this);  
        40.  
        41. layout1.setLayoutParams(new LayoutParams(LayoutParams.FILL_PARENT, LayoutParams.FILL_PARENT));  
        42.  
        43. layout1.addView(ed);  
        44.  
        45. layout1.addView(but1);  
        46.  
        47. setContentView(layout1);  
        48.  
        49. }



        让我们仔细看一下上面的Java代码。首先我们像平常一样创建一个EditText控件。我们给它一些RelativeLayout参数,然后设置它的规则。在这里,我们为EditText控件创建2个规则。

        接下来,我们创建一个Button控件并且设置它的规则(对齐到父布局右边缘)。最后,我们创建一个RelativeLayout对象,设置它的参数,使用addView()方法添加两个控件并且使用setContentView()方法加载显示相对布局。

        如你所见,当越来越多的控件要添加到屏幕时,代码量会很快地增长。为了易组织和可维护性,用程序定义并使用布局最好是用在特殊情况而不是一般情况。




        探讨相对布局的重要特性和属性

        现在让我们来讨论一些帮助配置相对布局和它的子控件的属性。一些特定的属性用于相对布局,也就是子规则,包括:

        ◆用于子控件在父布局中居中的规则,包括:水平居中,垂直居中,或者两者皆居中。

        ◆用于子控件在父布局中排布的规则,包括:在顶部,底部,左,右边缘放置。

        ◆用于子控件相对于其它子控件排布的规则,包括:在另一个控件顶,底,左,右边缘放置。

        ◆用于子控件相对于其它子控件放置的规则,包括:在另一个控件上面,底下,左边或右边放置。

        同样的,通用的 ViewGroup-style属性也可以应用于相对布局。这些属性包括:

        ◆通用布局参数比如layout_height(必须)和layout_width(必须)(类:ViewGroup.LayoutParams)

        ◆边距布局参数比如margin_top, margin_left, margin_right和margin_bottom (类:ViewGroup. MarginLayoutParams)

        布局参数比如layout_height和layout_width (类:ViewGroup.LayoutParams)

        现在让我们来实践这些规则吧!

        使用布局规则

        让我们看一个更复杂的屏幕设计。为了这个练习,我们从查看最终屏幕效果开始,然后再倒回来工作,并讨论这个相对布局的特性和为了达到最终结果所使用的规则。

        我们希望设计一个如下所示的屏幕:



        Android用户界面设计:相对布局_android_03


        为了使用相对布局来设计这个屏幕,参考以下步骤。

        步骤1:在你的XML资源文件中定义一个相对布局

        首先,在你的XML资源文件中定义一个相对布局。因为你想这个布局控制整个屏幕的内容,所以设置它的高和宽属性为fill_parent。你的XML资源文件应该看起来像这样:


        1. xmlns:android="http://schemas.android.com/apk/res/android"   
        2.  
        3. android:layout_height="fill_parent"    
        4.  
        5. android:layout_width="fill_parent">



        步骤2:确定子控件

        接下来,我们确定需要什么样的子控件。在这里,我们需要7个TextView控件(第个一种颜色)。像平常一样配置它们,设置文本属性为字符串,背景色,字号等等。将这些控件都放到相对布局中。

        步骤3:定义相对布局规则

        接下来,我们为每个子控件定义规则,以使它们被绘制到合适的位置:

        ◆RED TextView控件没有特别的设置。默认地,这个控件将会被绘制到父布局的左上角。

        ◆ORANGE TextView控件在父布局中水平居中。因为所有控件默认都会靠向屏幕的左上角,这有效地将控件定位到父布局的边缘顶部中间。

        ◆YELLOW TextView控件定位到父布局的右边缘。因为所有控件默认都会靠向屏幕的左上角,这有效的定位控件到父布局的右上角。

        ◆GREEN TextView控件在父布局中垂直居中,并且设置为显示在BLUE TextView控件的左边。

        ◆BLUE TextView控件被定位在父控件的中心(水平和垂直)。这将它显示在屏幕的中心位置。

        ◆INDIGO TextView控件在父局中垂直居中,并且设置为显示在BLUE TextView控件的右边。

        ◆VIOLET TextView控件被定位到父布局的底部边缘。它的宽度也被设置为填满父容器,允许它延伸到屏幕的底部边缘。

        如果你在你的XML资源文件中定义这些规则,XML文件代码将看起如下:



        1. xmlns:android="http://schemas.android.com/apk/res/android" 
        2.  
        3. android:layout_height="fill_parent" 
        4.  
        5. android:layout_width="fill_parent"> 
        6.  
        7.  
        8. android:text="RED" 
        9.  
        10. android:id="@+id/TextView01" 
        11.  
        12. android:layout_height="wrap_content" 
        13.  
        14. android:background="#f00" 
        15.  
        16. android:gravity="center" 
        17.  
        18. android:textColor="#000" 
        19.  
        20. android:layout_width="wrap_content" 
        21.  
        22. android:padding="25dp"> 
        23.  
        24.  
        25. android:text="ORANGE" 
        26.  
        27. android:layout_height="wrap_content" 
        28.  
        29. android:background="#ffa500" 
        30.  
        31. android:gravity="center" 
        32.  
        33. android:textColor="#000" 
        34.  
        35. android:id="@+id/TextView02" 
        36.  
        37. android:layout_width="wrap_content" 
        38.  
        39. android:layout_centerHorizontal="true" 
        40.  
        41. android:padding="25dp"> 
        42.  
        43.  
        44. android:text="YELLOW" 
        45.  
        46. android:layout_height="wrap_content" 
        47.  
        48. android:background="#ffff00" 
        49.  
        50. android:gravity="center" 
        51.  
        52. android:textColor="#000" 
        53.  
        54. android:id="@+id/TextView03" 
        55.  
        56. android:layout_width="wrap_content" 
        57.  
        58. android:layout_alignParentRight="true" 
        59.  
        60. android:padding="25dp"> 
        61.  
        62.  
        63. android:text="GREEN" 
        64.  
        65. android:layout_height="wrap_content" 
        66.  
        67. android:background="#0f0" 
        68.  
        69. android:gravity="center" 
        70.  
        71. android:textColor="#000" 
        72.  
        73. android:id="@+id/TextView04" 
        74.  
        75. android:layout_width="wrap_content" 
        76.  
        77. android:layout_toLeftOf="@+id/TextView05" 
        78.  
        79. android:padding="25dp" 
        80.  
        81. android:layout_centerVertical="true"> 
        82.  
        83.  
        84. android:text="BLUE" 
        85.  
        86. android:layout_height="wrap_content" 
        87.  
        88. android:background="#00f" 
        89.  
        90. android:gravity="center" 
        91.  
        92. android:textColor="#fff" 
        93.  
        94. android:id="@+id/TextView05" 
        95.  
        96. android:layout_width="wrap_content" 
        97.  
        98. android:layout_centerInParent="true" 
        99.  
        100. android:layout_margin="10dp" 
        101.  
        102. android:padding="25dp"> 
        103.  
        104.  
        105. android:text="INDIGO" 
        106.  
        107. android:layout_height="wrap_content" 
        108.  
        109. android:gravity="center" 
        110.  
        111. android:textColor="#fff" 
        112.  
        113. android:id="@+id/TextView06" 
        114.  
        115. android:layout_width="wrap_content" 
        116.  
        117. android:layout_toRightOf="@+id/TextView05" 
        118.  
        119. android:background="#4b0082" 
        120.  
        121. android:padding="25dp" 
        122.  
        123. android:layout_centerVertical="true"> 
        124.  
        125.  
        126. android:text="VIOLET" 
        127.  
        128. android:layout_height="wrap_content" 
        129.  
        130. android:background="#ee82ee" 
        131.  
        132. android:gravity="center" 
        133.  
        134. android:textColor="#000" 
        135.  
        136. android:id="@+id/TextView07" 
        137.  
        138. android:layout_alignParentBottom="true" 
        139.  
        140. android:layout_width="fill_parent" 
        141.  
        142. android:padding="25dp">




        相对布局使用技巧

        ◆这里是一些使用相对布局的技巧。

        ◆相对布局的子控件必须有唯一的id属性以使规则正确应用。

        ◆当心循环规则。循环规则发生在两个控件具有互相指向的规则时。如果你在布局设计中使用了循环规则,你将会得到以下错误信息:

        IllegalStateException: Circular dependencies cannot exist in a RelativeLayout(相对布局中不允许存在循环依赖)

        ◆回忆一下相对布局规则的应用被一次处理是很有用的

        ◆保持你的相对布局规则最小化。这减小了循环规则的机率并且使得你的布局更加可维护和灵活。

        ◆一般地,记住测试一下你的布局设计在横屏和竖屏模式下,以及在不同的屏幕大小和解决方案下是不是符合预期的。

        ◆使用相对布局代替嵌套线性布局以改进程序性能和响应能力。