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种布局就可以了。