帧布局
帧布局由FrameLayout所代表,FrameLayout直接继承了ViewGroup组件。
帧布局容器为每个加入其中的组件创建一个空白区域(称为一个帧),每个子组件占据一帧,这些帧都会根据gravity属性执行自动对齐。帧布局的效果是把组件一个一个地叠加在一起。
表2.7显示了FrameLayout常用的XML属性及相关方法说明。
表2.7 FrameLayout的常用XML属性及相关方法
XML属性 | 相关方法 | 说 明 |
android:foreground | setForeground(Drawable) | 设置该帧布局容器的前景图像 |
android:foregroundGravity | setForegroundGravty(int) | 定义绘制前景图像的gravity属性 |
FrameLayout包含的子元素也受FrameLayout.LayoutParams控制,因此它所包含的子元素也可指定android:layout_gravity属性,该属性控制该子元素在FrameLayout中的对齐方式。
下面示范了帧布局的用法,可以看到6个TextView叠加在一起,上面的TextView遮住下面的TextView。下面是使用帧布局的页面定义代码。
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="fill_parent" android:layout_height="fill_parent" android:orientation="vertical" android:layout_gravity="center" > <!--依次定义6个TextView,先定义的TextView位于底层 后定义的TextView位于上层 --> <!--android:gravity:属性是对该View中内容的限定,android:layout_gravity: 是用来设置View相对与父View的位置 -->
<TextView android:id="@+id/view01" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="center" android:width="320dp" android:height="320dp" android:background="#f00" /> <TextView android:id="@+id/view02" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="center" android:width="280dp" android:height="280dp" android:background="#0f0" /> <TextView android:id="@+id/view03" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="center" android:width="240dp" android:height="240dp" android:background="#00f" /> <TextView android:id="@+id/view04" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="center" android:width="200dp" android:height="200dp" android:background="#ff0" /> <TextView android:id="@+id/view05" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="center" android:width="160dp" android:height="160dp" android:background="#f0f" /> <TextView android:id="@+id/view06" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="center" android:width="120dp" android:height="120dp" android:background="#0ff" />" </FrameLayout>
上面的界面布局定义使用FrameLayout布局,并向该布局容器中添加了7个TextView,这7个TextView的高度完全相同,而宽度则逐渐减少——这样可以保证最新添加的TextView不会被完全遮挡;而且我们设置了7个TextView的背景色渐变。
实例:霓虹灯效果
如果考虑轮换改变上面的帧布局中6个TextView的背景色,就会看到上面的颜色渐变条不断地变换,就向大街上的霓虹灯一样。下面的程序还是使用上面的FrameLayout布局管理器,只是程序启动了一条线程来控制周期性地改变这6个TextView的背景色。下面是该主程序的代码。
package org.crazyit.helloworld; import java.util.*; import android.os.*; import android.app.Activity; import android.view.Menu; import android.widget.*; public class FrameLayout extends Activity { private int currentColor=0; //定义一个颜色数组 final int[] colors=new int[]{R.color.red,R.color.blue,R.color.beige,R.color.black, R.color.brown,R.color.coral}; final int[] names=new int[]{R.id.view01,R.id.view02,R.id.view03,R.id.view04, R.id.view05,R.id.view06}; TextView[] views=new TextView[names.length]; Handler handler=new Handler(){ @Override public void handleMessage(Message msg) { //表明消息来自本本程序所发出 if(msg.what==0x123) { for(int i=0;i<names.length;i++) { views[i].setBackgroundResource(colors[(i+currentColor)%names.length]); } currentColor++; } super.handleMessage(msg); } }; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.frame_layout); for(int i=0;i<names.length;i++) { views[i]=(TextView)findViewById(names[i]); } //定义一个线程周期性的改变currentColor变量值 new Timer().schedule(new TimerTask(){ @Override public void run() { // TODO Auto-generated method stub //发送一条空消息通知系统改变6个TextView组件的背景色 handler.sendEmptyMessage(0x123); } }, 0,200); } @Override public boolean onCreateOptionsMenu(Menu menu) { // Inflate the menu; this adds items to the action bar if it is present. getMenuInflater().inflate(R.menu.frame_layout, menu); return true; } }
上面的程序中粗体字代码定义了一个米0.2秒执行一次的任务,该任务仅仅向Handler发送一条消息,通知它更新6个TextView的背景色。
运行Activity可以看到如图2.12所示的效果。
图2.12帧布局
上面的程序中粗体字代码定义了一个没0.2秒执行一次的任务,该任务仅仅向Handler发送一条消息,通知它更新6个TextView的背景色。
到目前为止有一个疑问:为何不直接在run()方法里直接更新6个TextView的背景色呢?这是因为Android的View和UI组件不是线程安全的,所以Android不允许开发者启动线程访问用户界面的UI组件。所以程序中额外定义了一个Handler来处理TextView背景色的更新。