Android Studio开发实战:从零基础到App上线 (移动开发丛书)
上QQ阅读APP看书,第一时间看更新

3.1 其他布局

本节介绍Android另外两个常用的布局视图,分别是相对布局RelativeLayout的属性说明与注意点、框架布局FrameLayout的属性说明与注意点。

3.1.1 相对布局RelativeLayout

RelativeLayout下级视图的位置是相对位置,得有具体的参照物才能确定最终位置。如果不设定下级视图的参照物,那么下级视图默认显示在RelativeLayout内部的左上角。用于确定视图位置的参照物分两种,一种是与该视图自身平级的视图,另一种是该视图的上级视图(RelativeLayout)。与参照物对比,相对位置的属性与类型值见表3-1。

表3-1 相对位置的属性与类型的取值说明

为了更好地理解上述相对属性的含义,接下来使用RelativeLayout及其下级视图进行布局,看看实际效果图是怎样的。下面是演示相对布局的XML代码:

        <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
            android:layout_width="match_parent"
            android:layout_height="500dp" >
            <Button
              android:id="@+id/btn_center"
              style="@style/btn_relative"
              android:layout_centerInParent="true"
              android:text="我在中间"/>
          <Button
              android:id="@+id/btn_center_horizontal"
              style="@style/btn_relative"
              android:layout_centerHorizontal="true"
              android:text="我在水平中间"/>
          <Button
              android:id="@+id/btn_center_vertical"
              style="@style/btn_relative"
              android:layout_centerVertical="true"
              android:text="我在垂直中间"/>
          <Button
              android:id="@+id/btn_parent_left"
              style="@style/btn_relative"
              android:layout_marginTop="100dp"
              android:layout_alignParentLeft="true"
              android:text="我跟上级左边对齐"/>
          <Button
              android:id="@+id/btn_parent_top"
              style="@style/btn_relative"
              android:layout_width="120dp"
              android:layout_alignParentTop="true"
              android:text="我跟上级顶部对齐"/>
          <Button
              android:id="@+id/btn_parent_right"
              style="@style/btn_relative"
              android:layout_marginTop="100dp"
              android:layout_alignParentRight="true"
              android:text="我跟上级右边对齐"/>
          <Button
              android:id="@+id/btn_parent_bottom"
              style="@style/btn_relative"
              android:layout_width="120dp"
              android:layout_alignParentBottom="true"
              android:layout_centerHorizontal="true"
              android:text="我跟上级底部对齐"/>
          <Button
              android:id="@+id/btn_left_bottom"
              style="@style/btn_relative"
              android:layout_toLeftOf="@+id/btn_parent_bottom"
              android:layout_alignTop="@+id/btn_parent_bottom"
              android:text="我在底部左边"/>
            <Button
                android:id="@+id/btn_right_bottom"
                style="@style/btn_relative"
                android:layout_toRightOf="@+id/btn_parent_bottom"
                android:layout_alignBottom="@+id/btn_parent_bottom"
                android:text="我在底部右边"/>
            <Button
                android:id="@+id/btn_above_center"
                style="@style/btn_relative"
                android:layout_above="@+id/btn_center"
                android:layout_alignLeft="@+id/btn_center"
                android:text="我在中间上面"/>
            <Button
                android:id="@+id/btn_below_center"
                style="@style/btn_relative"
                android:layout_below="@+id/btn_center"
                android:layout_alignRight="@+id/btn_center"
                android:text="我在中间下面"/>
        </RelativeLayout>

上述布局文件的效果如图3-1所示,RelativeLayout的下级视图为各个按钮控件,按钮上的文字说明了所处的相对位置,具体的控件显示方位正如XML属性中描述的那样。

图3-1 在布局文件中定义的相对布局

一般我们在布局文件中就定义好了视图的相对位置,很少会等到在代码中定义。不过也有特殊情况,如果视图是在代码中动态添加的,那么相对位置也只能在代码中临时定义。代码中定义相对位置用到的是RelativeLayout.LayoutParams的addRule方法,该方法的第一个参数表示相对位置的类型,具体取值说明见表3-1;第二个参数表示参照物视图的ID,即当前视图要参照哪个视图确定自身位置。

下面是在代码中给RelativeLayout动态添加子视图并指定子视图相对位置的代码片段:

            public void onClick(View v) {
                if (v.getId() == R.id.btn_add_left) {
                    addNewView(RelativeLayout.LEFT_OF, RelativeLayout.ALIGN_TOP, v.getId());
                } else if (v.getId() == R.id.btn_add_above) {
                    addNewView(RelativeLayout.ABOVE, RelativeLayout.ALIGN_LEFT, v.getId());
                } else if (v.getId() == R.id.btn_add_right) {
                    addNewView(RelativeLayout.RIGHT_OF, RelativeLayout.ALIGN_BOTTOM, v.getId());
                } else if (v.getId() == R.id.btn_add_below) {
                    addNewView(RelativeLayout.BELOW, RelativeLayout.ALIGN_RIGHT, v.getId());
                } else if (v.getId() == R.id.btn_add_center) {
                    addNewView(RelativeLayout.CENTER_IN_PARENT, -1, rl_content.getId());
                } else if (v.getId() == R.id.btn_add_parent_left) {
                    addNewView(RelativeLayout.ALIGN_PARENT_LEFT, RelativeLayout.CENTER_VERTICAL, rl_content.getId());
                } else if (v.getId() == R.id.btn_add_parent_top) {
                    addNewView(RelativeLayout.ALIGN_PARENT_TOP, RelativeLayout.CENTER_HORIZONTAL, rl_content.getId());
                } else if (v.getId() == R.id.btn_add_parent_right) {
                    addNewView(RelativeLayout.ALIGN_PARENT_RIGHT, -1, rl_content.getId());
                } else if (v.getId() == R.id.btn_add_parent_bottom) {
                    addNewView(RelativeLayout.ALIGN_PARENT_BOTTOM, -1, rl_content.getId());
                }
            }


            private void addNewView(int firstAlign, int secondAlign, int referId) {
                View v = new View(this);
                v.setBackgroundColor(0xaa66ff66);
                RelativeLayout.LayoutParams rl_params = new RelativeLayout.LayoutParams(100, 100);
                rl_params.addRule(firstAlign, referId);
                if (secondAlign >= 0) {
                    rl_params.addRule(secondAlign, referId);
                }
                v.setLayoutParams(rl_params);
                v.setOnLongClickListener(new OnLongClickListener() {
                    @Override
                    public boolean onLongClick(View vv) {
                        rl_content.removeView(vv);
                        return true;
                    }
                });
                rl_content.addView(v);
            }

动态添加子控件的效果如图3-2所示,在图上给每个方块子视图做了编号,以此区分该方块是由哪个按钮添加的以及添加的相对位置。

图3-2 在代码中动态添加下级视图的相对布局

3.1.2 框架布局FrameLayout

FrameLayout也是较常用的布局,其下级视图无法指定所处的位置,只能统统从上级FrameLayout的左上角开始添加,并且后面添加的子视图会把之前的子视图覆盖掉。框架布局一般用于需要重叠显示的场合,比如绘图、游戏界面等,常见属性说明如下。

● foreground:指定框架布局的前景图像。该图像在框架内部永远处于最顶层,不会被框架内的其他视图覆盖。

● foregroundGravity:指定前景图像的对齐方式。该属性的取值说明同gravity。

为了更直观地理解FrameLayout,我们可在代码中为框架布局动态添加子视图,然后观察前后两个子视图的显示效果。

先给框架布局添加一个暗灰色的子视图,如图3-3所示。再给框架布局添加一个鲜红色子视图,如图3-4所示。此时后面添加的视图会覆盖前面添加的视图。注意,框架视图上方正中间的小图标一直都没被覆盖,是它被指定为前景图像的缘故。

图3-3 在框架布局中添加第一个子视图

图3-4 在框架布局中添加第二个子视图

除了线性布局、相对布局、框架布局外,Android还提供了其他几个布局视图,如绝对布局AbsoluteLayout、表格布局TableLayout等,不过这几个布局在实际开发中用得并不多,读者只需掌握前3种布局就可以了。