如果考虑轮换改变上面的帧布局中6个TextView的背景色,就会看到上面的颜色渐变条不断地变换,就像大街上的霓虹灯一样。下面的程序还是使用上一篇的FrameLayout布局管理器,只是程序启动了一个线程来控制周期性地改变这6个TextView的背景色。
效果图:
MainActivity.java
1 package com.example.aimee.tablelayouttest; 2 3 import android.os.Handler; 4 import android.os.Message; 5 import android.support.v7.app.AppCompatActivity; 6 import android.os.Bundle; 7 import android.widget.TextView; 8 9 import java.util.Timer; 10 import java.util.TimerTask; 11 12 public class MainActivity extends AppCompatActivity { 13 14 private int currentColor = 0; 15 //定义一个颜色数组 16 final int[] colors = new int[]{ 17 R.color.color1, 18 R.color.color2, 19 R.color.color3, 20 R.color.color4, 21 R.color.color5, 22 R.color.color6 23 }; 24 25 final int[] names = new int[]{ 26 R.id.view01, 27 R.id.view02, 28 R.id.view03, 29 R.id.view04, 30 R.id.view05, 31 R.id.view06 32 }; 33 34 TextView[] views = new TextView[names.length]; 35 Handler handler = new Handler(){ 36 @Override 37 public void handleMessage(Message msg) { 38 //表明消息来自本程序所发送的 39 if (msg.what == 0x123){ 40 for (int i=0;i<names.length;i++){ 41 views[i].setBackgroundResource(colors[(i+currentColor)%names.length]); 42 } 43 currentColor++; 44 } 45 super.handleMessage(msg); 46 } 47 }; 48 49 @Override 50 protected void onCreate(Bundle savedInstanceState) { 51 super.onCreate(savedInstanceState); 52 setContentView(R.layout.layout); 53 for (int i=0;i<names.length;i++){ 54 views[i] = (TextView)findViewById(names[i]); 55 } 56 //定义一个线程周期性地改变currentColor变量值 57 new Timer().schedule(new TimerTask() { 58 @Override 59 public void run() { 60 //发送一条空消息通知系统改变6个TextView组件的背景色 61 handler.sendEmptyMessage(0x123); 62 } 63 },0,200); 64 } 65 }
上面程序中的粗体字代码定义了一个每0.2秒执行一次的任务,该任务仅仅向Handler发送一条消息,通知它更新6个TextView的背景色。
可能会有人问:为何不直接在run()方法里直接更新6个TextView的背景色呢?
这是因为Android的View和UI组件不是线程安全的,所以Android不允许开发者启动线程访问用户界面的UI组件。因此,程序中额外定义了一个Handler来处理TextView背景色的更新。
简单来说,上面的程序通过任务调度控制了每间隔0.2秒轮换更新一次6个TextView的背景色,这样看上去就像大街上的霓虹灯了。
相对布局
相对布局由RelativeLayout所代表,相对布局容器内子组件的位置总是相对兄弟组件、父容器来决定的,因此这种布局方式被称为相对布局。
如果A组件的位置是由B组件的位置来决定的,Android要求先定义B组件,再定义A组件。
RelativeLayout可支持两个XML属性。
android:gravity——setGravity(int)
设置该布局容器内各子组件的对齐方式
android:ignireGravity——setIgnoreGravity(int)
设置哪个组件不受gravity属性的影响
为了控制该布局容器中各子组件的布局分布,RelativeLayout提供了一个内部类:RelativeLayout.LayoutParams,该类提供了大量的XML属性来控制RelativeLayout布局容器中子组件的布局分布。
RelativeLayout.LayoutParams里只能设为true,false的XML属性如下:
android:layout_centerhorizontal
控制该子组件是否位于布局容器的水平居中
android:layout_centervertical
控制该子组件是否位于布局容器的垂直居中
android:layout_centerInParent
控制该子组件是否位于布局容器的中央位置
android:layout_alignParentBottom
控制该子组件是否与布局容器低端对齐
android:layout_alignParentLeft
控制该子组件是否与布局容器左边对齐
android:layout_alignParentRight
控制该子组件是否与布局容器右边对齐
android:layout_alignParentTop
控制该子组件是否与布局容器顶端对齐
RelativeLayout.LayoutParams里属性值为其他UI组件ID的XML属性如下:
android:layout_toRightOf
控制该子组件位于给出ID组件的右侧
android:layout_toLeftOf
控制该子组件位于给出ID组件的左侧
android:layout_above
控制该子组件位于给出ID组件的上方
android:layout_below
控制该子组件位于给出ID组件的下方
android:layout_alignTop
控制该子组件与给出ID组件的上边界对齐
android:layout_alignBottom
控制该子组件与给出ID组件的下边界对齐
android:layout_alignLeft
控制该子组件与给出ID组件的左边界对齐
android:layout_alignRight
控制该子组件与给出ID组件的右边界对齐
除此之外,RelativeLayout.LayoutParams还继承了android.view.ViewGroup.MarginLayout Params,因此RelativeLayout布局容器中每个子组件也可指定android.view.ViewGroup.MarginLayout Params所支持的各XML属性