Android布局

梦里梦外; 2022-07-08 20:25 517阅读 0赞

Android布局

  1. 我们对[Android][] [应用程序][Link 1] 运行原理及布局文件可谓有了比较深刻的认识和理解,并且用“Hello World!”程序来实践证明了。在继续深入[Android开发之旅][Android 1] 之前,有必要解决前两篇中没有介绍的遗留问题:View的几种布局显示方法,以后就不会在针对布局方面做过多的介绍。View的布局显示方式有下面几种:**线性布局** Linear Layout)、**相对布局** Relative Layout)、**表格布局** Table Layout)、**网格视图** Grid View)、**标签布局** Tab Layout)、**列表视图** List View)、**绝对布局** AbsoluteLayout)。本文虽然是介绍View的布局方式,但不仅仅是这样,其中涉及了很多小的知识点,绝对能给你带来Android大餐!

本文的主要内容就是分别介绍以上视图的七种布局显示方式效果及实现,大纲如下:

  • 1、View布局概述
  • 2、线性布局(Linear Layout)

    • 2.1、Tips:android :layout_weight =”1”
  • 3、相对布局(Relative Layout)
  • 4、表格布局(Table Layout)
  • 5、列表视图(List View)

    • 5.1、一个小的改进
    • 5.2、补充说明
  • 6、网格视图(Grid View)
  • 7 、绝对布局()
  • 8、标签布局(Tab Layout)

1、view的布局显示概述

  1. 通过前面的学习我们知道:在一个Android应用程序中,用户界面通过View ViewGroup 对象构建。Android中有很多种ViewViewGroup,他们都继承自View 类。View对象是Android平台上表示用户界面的基本单元。

View的布局显示方式直接影响用户界面,View的布局方式是指一组View元素如何布局,准确的说是一个ViewGroup中包含的一些View怎么样布局。ViewGroup 类是布局(layout)和视图容器(View container)的基类,此类也定义了ViewGroup.LayoutParams 类,它作为布局参数的基类,此类告诉父视图其中的子视图想如何显示。例如,XML布局文件中名为layout_something 的属性(参加上篇的4.2节 )。我们要介绍的View 的布局方式的类,都是直接或间接继承自ViewGroup 类,如下图所示:

图1、继承自ViewGroup的一些布局类

其实,所有的布局方式都可以归类为ViewGroup的5个类别,即ViewGroup的5个直接子类。其它的一些布局都扩展自这5个类。下面分小节分别介绍View的七种布局显示方式。

2、线性布局(Linear Layout)

线性布局 :是一个ViewGroup以线性方向显示它的子视图(view)元素,即垂直地水平地 。之前我们的Hello World!程序中view的布局方式就是线性布局的,一定不陌生!如下所示res/layour/main.xml :

<? xml version=”1.0” encoding=”utf-8”?>
< LinearLayout xmlns :android =”http://schemas.android.com/apk/res/android“
android :layout_width =”fill_parent”
android :layout_height =”fill_parent”
android :orientation =”horizontal” >
< Button android :id =”@+id/button1”
android :layout_width =”wrap_content”
android :layout_height =”wrap_content”
android :text =”Hello, I am a Button1”
android :layout_weight =”1”
/>
< Button android :id =”@+id/button2”
android :layout_width =”wrap_content”
android :layout_height =”wrap_content”
android :text =”Hello, I am a Button2”
android :layout_weight =”1”
/>
< Button android :id =”@+id/button3”
android :layout_width =”wrap_content”
android :layout_height =”wrap_content”
android :text =”Hello, I am a Button3”
android :layout_weight =”1”
/>
< Button android :id =”@+id/button4”
android :layout_width =”wrap_content”
android :layout_height =”wrap_content”
android :text =”Hello, I am a Button4”
android :layout_weight =”1”
/>
< Button android :id =”@+id/button5”
android :layout_width =”wrap_content”
android :layout_height =”wrap_content”
android :text =”Hello, I am a Button5”
android :layout_weight =”1”
/>
</ LinearLayout >

从上面可以看出根LinearLayout视图组(ViewGroup)包含5个Button,它的子元素是以线性方式(horizontal,水平的)布局,运行效果如下图所示:

linearlayout1

图2、线性布局(水平或者说是横向)

如果你在android :orientation =”horizontal” 设置为vertical ,则是是垂直或者说是纵向的,如下图所示:

linearlayout2

图3、线性布局(垂直或者说是纵向)

2.1、Tips:android :layout_weight =”1”

这个属性很关键,如果你没有显示设置它,它默认为0。把上面布局文件(水平显示的那个 )中的这个属性都去掉,运行会得出如下结果:

linearlayout3

图4、layout_weight属性

没有了这个属性,我们本来定义的5个Button运行后却只显示了2个Button,为什么呢??

“ weight” 顾名思义是权重 的 意思,layout_weight 用于给一个线性布局中的诸多视图的重要程度赋值。所有的视图都有一个layout_weight值,默认为零,意思是需要显示多大的视图就占据多大的屏幕 空间。这就不难解释为什么会造成上面的情况了:Button1~Button5都设置了layout_height和layout_width属性为 wrap_content即包住文字内容,他们都没有设置layout_weight 属性,即默认为0.,这样Button1和Button2根据需要的内容占据了整个屏幕,别的就显示不了啦!

若 赋一个高于零的值,则将父视图中的可用空间分割,分割大小具体取决于每一个视图的layout_weight值以及该值在当前屏幕布局的整体 layout_weight值和在其它视图屏幕布局的layout_weight值中所占的比率而定。举个例子:比如说我们在 水平方向上有一个文本标签和两个文本编辑元素。该文本标签并无指定layout_weight值,所以它将占据需要提供的最少空间。如果两个文本编辑元素 每一个的layout_weight值都设置为1,则两者平分在父视图布局剩余的宽度(因为我们声明这两者的重要度相等)。如果两个文本编辑元素其中第一 个的layout_weight值设置为1,而第二个的设置为2,则剩余空间的三分之二分给第一个,三分之一分给第二个(数值越小,重要度越高 )。

3、相对布局(Relative Layout)

相对布局 :是一个ViewGroup以相对位置显示它的子视图(view)元素,一个视图可以指定相对于它的兄弟视图的位置(例如在给定视图的左边或者下面)或相对于RelativeLayout 的特定区域的位置(例如底部对齐,或中间偏左)。

相对布局是设计用户界面的有力工具,因为它消除了嵌套视图组。如果你发现你使用了多个嵌套的LinearLayout 视图组后,你可以考虑使用一个RelativeLayout 视图组了。看下面的res/layour/main.xml :

<? xml version=”1.0” encoding=”utf-8”?>
< RelativeLayout xmlns :android =”http://schemas.android.com/apk/res/android“
android :layout_width =”fill_parent”
android :layout_height =”fill_parent” >
< TextView
android :id =”@+id/label”
android :layout_width =”fill_parent”
android :layout_height =”wrap_content”
android :text =”Type here:” />
< EditText
android :id =”@+id/entry”
android :layout_width =”fill_parent”
android :layout_height =”wrap_content”
android :background =”@android:drawable/editbox_background”
android :layout_below =”@id/label” />
< Button
android :id =”@+id/ok”
android :layout_width =”wrap_content”
android :layout_height =”wrap_content”
android :layout_below =”@id/entry”
android :layout_alignParentRight =”true”
android :layout_marginLeft =”10dip”
android :text =”OK” />
< Button
android :layout_width =”wrap_content”
android :layout_height =”wrap_content”
android :layout_toLeftOf =”@id/ok”
android :layout_alignTop =”@id/ok”

android :text =”Cancel” />
</ RelativeLayout >

从上面的布局文件我们知道,RelativeLayout 视图组包含一个TextView、一个EditView、两个Button,注意标记了 的属性,在使用相对布局 方式中就是使用这些类似的属性来定位视图到你想要的位置,它们的值是你参照的视图的id 。这些属性的意思很简单,就是英文单词的直译,就不多做介绍了。运行之后,得如下结果:

relativelayout

图5、相对布局

4、 表格布局(Table Layout)

表格布局 :是一个ViewGroup以表格显示它的子视图(view)元素,即行和列标识一个视图的位置。其实Android的表格布局跟HTML中的表格布局非常类似,TableRow 就像HTML表格的<tr>标记。

用表格布局需要知道以下几点

  • android:shrinkColumns ,对应的方法:setShrinkAllColumns(boolean) ,作用:设置表格的列是否收缩(列编号从0开始,下同),多列用逗号隔开(下同),如android:shrinkColumns=”0,1,2” ,即表格的第1、2、3列的内容是收缩的以适合屏幕,不会挤出屏幕。
  • android:collapseColumns ,对应的方法:setColumnCollapsed(int,boolean) ,作用:设置表格的列是否隐藏
  • android:stretchColumns ,对应的方法:setStretchAllColumns(boolean) ,作用:设置表格的列是否拉伸

看下面的res/layour/main.xml :

<? xml version=”1.0” encoding=”utf-8”?>
< TableLayout xmlns :android =”http://schemas.android.com/apk/res/android“
android :layout_width =”fill_parent”
android :layout_height =”fill_parent”
android :shrinkColumns =”0,1,2” >
< TableRow >
< Button android :id =”@+id/button1”
android :layout_width =”wrap_content”
android :layout_height =”wrap_content”
android :text =”Hello, I am a Button1”
android :layout_column =”0”
/>
< Button android :id =”@+id/button2”
android :layout_width =”wrap_content”
android :layout_height =”wrap_content”
android :text =”Hello, I am a Button2”
android :layout_column =”1”
/>
</ TableRow >
< TableRow >
< Button android :id =”@+id/button3”
android :layout_width =”wrap_content”
android :layout_height =”wrap_content”
android :text =”Hello, I am a Button3”
android :layout_column =”1”
/>
< Button android :id =”@+id/button4”
android :layout_width =”wrap_content”
android :layout_height =”wrap_content”
android :text =”Hello, I am a Button4”
android :layout_column =”1”
/>
</ TableRow >
< TableRow >
< Button android :id =”@+id/button5”
android :layout_width =”wrap_content”
android :layout_height =”wrap_content”
android :text =”Hello, I am a Button5”
android :layout_column =”2”
/>
</ TableRow >
</ TableLayout >

运行之后可以得出下面的结果:

tablelayout

图6、表格布局

5、列表视图(List View)

列表布局 :是一个ViewGroup以列表显示它的子视图(view)元素,列表是可滚动的列表。列表元素通过ListAdapter 自动插入到列表。

ListAdapter :扩展自Adapter ,它是ListView 和数据列表之间的桥梁。ListView可以显示任何包装在ListAdapter中的数据。该类提供两个公有类型的抽象方法:

  1. public abstract boolean areAllItemsEnabled () :表示ListAdapter中的所有元素是否可激活的?如果返回真,即所有的元素是可选择的即可点击的。
  2. public abstract boolean isEnabled (int position) :判断指定位置的元素是否可激活的?

下面通过一个例子来,创建一个可滚动的列表,并从一个字符串数组读取列表元素。当一个元素被选择时,显示该元素在列表中的位置的消息。

1)、首先,将res/layour/main.xml 的内容置为如下:

<? xml version=”1.0” encoding=”utf-8”?>
< TextView xmlns :android =”http://schemas.android.com/apk/res/android“
android :layout_width =”fill_parent”
android :layout_height =”fill_parent”
android :padding =”10dp”
android :textSize =”16sp” >
</ TextView >

这样就定义了元素在列表中的布局。

2)、src/skynet.com.cnblogs.www/HelloWorld.Java 文件的代码如下:

  1. package
  2. skynet.com.cnblogs.www;import
  3. android.app.ListActivity;import
  4. android.os.Bundle;import
  5. android.view.View;import
  6. android.widget.AdapterView;import
  7. android.widget.ArrayAdapter;import
  8. android.widget.ListView;import
  9. android.widget.TextView;import
  10. android.widget.Toast;import
  11. android.widget.AdapterView.OnItemClickListener;public
  12. class
  13. HelloWorld extends
  14. ListActivity
  15. {
  16. //注意这里Helloworld类不是扩展自Acitvity,而是扩展自ListAcitivty /** Called when the activity is first created. */
  17. @Override public
  18. void
  19. onCreate(Bundle savedInstanceState) { super
  20. .onCreate(savedInstanceState); setListAdapter(new
  21. ArrayAdapter<String>(this
  22. , R.layout.main, COUNTRIES));
  23. ListView lv = getListView(); lv.setTextFilterEnabled(true
  24. ); lv.setOnItemClickListener(new
  25. OnItemClickListener() { public
  26. void
  27. onItemClick(AdapterView<?> parent, View view, int
  28. position, long
  29. id) { // When clicked, show a toast with the TextView text
  30. Toast.makeText(getApplicationContext(), ((TextView) view).getText(), Toast.LENGTH_SHORT).show(); } }); } static
  31. final
  32. String[] COUNTRIES = new
  33. String[] { "1
  34. ", "2
  35. ", "3
  36. ", "4
  37. ", "5
  38. ", "6
  39. ", "7
  40. ", "8
  41. ", "9
  42. ", "10
  43. ", "11
  44. ", "12
  45. ", "13
  46. ", "14
  47. ", "15
  48. ", "16
  49. ", "17
  50. ", "18
  51. ", "19
  52. ", "20
  53. ", "21
  54. ", "22
  55. ", "23
  56. ", "24
  57. " };}

Note :onCreate() 函数中并不像往常一样通过setContentView() 为活动(Activity)加载布局文件,替代的是通过setListAdapter(ListAdapter) 自动添加一个ListView填充整个屏幕的ListActivity。在此文件中这个方法以一个ArrayAdapter为参数:setListAdapter(new ArrayAdapter<String>(this , R.layout.main, COUNTRIES)) , 这个ArrayAdapter管理填入ListView中的列表元素。ArrayAdapter的构造函数的参数为:this(表示应用程序的上下文 context)、表示ListViewde布局文件(这里是R.layout.main)、插入ListView的List对象对数组(这里是 COUNTRES)。

setOnItemClickListener(OnItemClickListener) 定义了每个元素的点击(on-click)的监听器,当ListView中的元素被点击时,onItemClick() 方法被调用,在这里是即一个Toast 消息——每个元素的位置将显示。

3)、运行应用程序得如下结果(点击1之后,在下面显示了1):

listview

图7、列表布局

NOTE: 如果你改了HelloWorld extends ListActivity 而不是Activity 之 后,运行程序是提示:“Conversion to Dalvik format failed with error 1”。可以这么解决:解决办法是 Project > Clean… > Clean project selected below > Ok

5.1、一个小的改进

上面我们是把要填充到ListView中的元素硬编码到HelloWorld.java文件中,这样就缺乏灵活性!也不符合推荐的应用程序的界面控制它行为的代码 更好地分离的准则!

其实我们可以把要填充到ListView的元素写到res/values/strings.xml 文件中的<string-array> 元素中,然后再源码中动态地读取。这样strings.xml的内容类似下面:

  1. <?
  2. xml version="1.0" encoding="utf-8"?>
  3. <
  4. resources
  5. >
  6. <
  7. string
  8. -array
  9. name
  10. ="countries_array"
  11. >
  12. <
  13. item
  14. >
  15. 1</
  16. item
  17. >
  18. <
  19. item
  20. >
  21. 2</
  22. item
  23. >
  24. <
  25. item
  26. >
  27. 3</
  28. item
  29. >
  30. <
  31. item
  32. >
  33. 4</
  34. item
  35. >
  36. <
  37. item
  38. >
  39. 5</
  40. item
  41. >
  42. <
  43. item
  44. >
  45. 6</
  46. item
  47. >
  48. <
  49. item
  50. >
  51. 7</
  52. item
  53. >
  54. </
  55. string
  56. -array>
  57. </
  58. resources
  59. >

然而HelloWorld.java文件中的onCreate() 函数,则这样动态访问这个数组及填充到ListVies:

String[] countries = getResources().getStringArray(R.array.countries_array);
setListAdapter(new ArrayAdapter(this , R.layout.list_item, countries));

5.2、补充说明

首先总结一下列表布局的关键部分:

  • 布局文件中定义ListView
  • Adapter用来将数据填充到ListView
  • 要填充到ListView的数据,这些数据可以字符串、图片、控件等等

其中Adapter是ListView和数据源之间的桥梁,根据数据源的不同Adapter可以分为三类:

  • String[]: ArrayAdapter
  • List>: SimpleAdapter
  • 数据库Cursor: SimpleCursorAdapter

使 用ArrayAdapter(数组适配器)顾名思义,需要把数据放入一个数组以便显示,上面的例子就是这样的;SimpleAdapter能定义各种各样 的布局出来,可以放上ImageView(图片),还可以放上Button(按钮),CheckBox(复选框)等 等;SimpleCursorAdapter是和数据库有关的东西。篇幅有限后面两种就不举例实践了。你可以参考android ListView详解 orArrayAdapter ,SimpleAdapter ,SimpleCursorAdapter 区别 。

6、网格视图(Grid View)

网格布局 :是一个ViewGroup以网格显示它的子视图(view)元素,即二维的、滚动的网格。网格元素通过ListAdapter 自动插入到网格。 ListAdapter跟上面的列表布局是一样的,这里就不重复累述了。

下面也通过一个例子来,创建一个显示图片缩略图的网格。当一个元素被选择时,显示该元素在列表中的位置的消息。

1)、首先,将上面实践截取的图片放入res/drawable/

2)、res/layour/main.xml 的内容置为如下:这个GridView填满整个屏幕,而且它的属性都很好理解,按英文单词的意思就对了。

  1. <?
  2. xml version="1.0" encoding="utf-8"?>
  3. <
  4. GridView
  5. xmlns
  6. :android
  7. ="http://schemas.android.com/apk/res/android"
  8. android
  9. :id
  10. ="@+id/gridview"
  11. android
  12. :layout_width
  13. ="fill_parent"
  14. android
  15. :layout_height
  16. ="fill_parent"
  17. android
  18. :columnWidth
  19. ="90dp"
  20. android
  21. :numColumns
  22. ="auto_fit"
  23. android
  24. :verticalSpacing
  25. ="10dp"
  26. android
  27. :horizontalSpacing
  28. ="10dp"
  29. android
  30. :stretchMode
  31. ="columnWidth"
  32. android
  33. :gravity
  34. ="center"
  35. />

3)、然后,HelloWorld.java文件中onCreate() 函数如下:

  1. public
  2. void
  3. onCreate(Bundle savedInstanceState) { super
  4. .onCreate(savedInstanceState); setContentView(R.layout.main); GridView gridview = (GridView) findViewById(R.id.gridview); gridview.setAdapter(new
  5. ImageAdapter(this
  6. )); gridview.setOnItemClickListener(new
  7. OnItemClickListener() { public
  8. void
  9. onItemClick(AdapterView<?> parent, View v, int
  10. position, long
  11. id) { Toast.makeText(HelloWorld.this
  12. , "
  13. " + position, Toast.LENGTH_SHORT).show(); } }); }

onCreate() 函数跟通常一样,首先调用超类的onCreate() 函数函数,然后通过setContentView() 为活动(Activity)加载布局文件。紧接着是,通过GridView的id获取布局文件中的gridview,然后调用它的setListAdapter(ListAdapter) 函数填充它,它的参数是一个我们自定义的ImageAdapter。后面的工作跟列表布局中一样,为监听网格中的元素被点击的事件而做的工作。

4)、实现我们自定义ImageAdapter,新添加一个类文件,它的代码如下:

  1. package
  2. skynet.com.cnblogs.www;import
  3. android.content.Context;import
  4. android.view.View;import
  5. android.view.ViewGroup;import
  6. android.widget.BaseAdapter;import
  7. android.widget.GridView;import
  8. android.widget.ImageView;public
  9. class
  10. ImageAdapter extends
  11. BaseAdapter { private
  12. Context mContext; public
  13. ImageAdapter(Context c) { mContext = c; } public
  14. int
  15. getCount() { return
  16. mThumbIds.length; } public
  17. Object getItem(int
  18. position) { return
  19. null
  20. ; } public
  21. long
  22. getItemId(int
  23. position) { return
  24. 0; } // create a new ImageView for each item referenced by the Adapter
  25. public
  26. View getView(int
  27. position, View convertView, ViewGroup parent) { ImageView imageView; if
  28. (convertView == null
  29. ) { // if it's not recycled, initialize some attributes
  30. imageView = new
  31. ImageView(mContext); imageView.setLayoutParams(new
  32. GridView.LayoutParams(85, 85)); imageView.setScaleType(ImageView.ScaleType.CENTER_CROP); imageView.setPadding(8, 8, 8, 8); } else
  33. { imageView = (ImageView) convertView; } imageView.setImageResource(mThumbIds[position]); return
  34. imageView; } // references to our images
  35. private
  36. Integer[] mThumbIds = { R.drawable.linearlayout1, R.drawable.linearlayout2, R.drawable.linearlayout3, R.drawable.listview, R.drawable.relativelayout, R.drawable.tablelayout };}

ImageAdapter类扩展自BaseAdapter ,所以首先得实现它所要求必须实现的方法。构造函数和getcount()函数很好理解,而getItem(int)应该返回实际对象在适配器中的特定位置,但是这里我们不需要。类似地,getItemId(int)应该返回元素的行号,但是这里也不需要。

这里重点要介绍的是getView()方法,它为每个要添加到ImageAdapter的图片都创建了一个新的View。当调用这个方法时,一个View是循环再用的,因此要确认对象是否为空。如果是空的话,一个ImageView 就被实例化且配置想要的显示属性:

  • setLayoutParams(ViewGroup.LayoutParams) :设置View的高度和宽度,这确保不管drawable中图片的大小,每个图片都被重新设置大小且剪裁以适应这些尺寸。
  • setScaleType(ImageView.ScaleType) :声明图片应该向中心剪裁(如果需要的话)。
  • setPadding(int, int, int, int) :定义补距,如果图片有不同的横纵比,小的补距将导致更多的剪裁以适合设置的ImageView的高度和宽度。

如果View传到getView()不是空的,则本地的ImageView初始化时将循环再用View对象。在getView()方法末尾,position整数传入setImageResource()方法以从mThumbIds数组中选择图片。

运行程序会得到如下结果(点击第一张图片之后):

gridviewlayout

图8、网格布局

7、绝对布局 (AbsoluteLayout)

绝对布局 :是一个ViewGroup以绝对方式显示它的子视图(view)元素,即以坐标的方式来定位在屏幕上位置。

这种布局方式很好理解,在布局文件或编程地设置View的坐标,从而绝对地定位。如下所示布局文件:

  1. <
  2. AbsoluteLayout
  3. xmlns
  4. :android
  5. ="http://schemas.android.com/apk/res/android"
  6. android
  7. :id
  8. ="@+id/AbsoluteLayout01"
  9. android
  10. :layout_width
  11. ="fill_parent"
  12. android
  13. :layout_height
  14. ="fill_parent"
  15. >
  16. <
  17. TextView
  18. android
  19. :id
  20. ="@+id/txtIntro"
  21. android
  22. :text
  23. ="绝对布局"
  24. android
  25. :layout_width
  26. ="fill_parent"
  27. android
  28. :layout_height
  29. ="wrap_content"
  30. android
  31. :layout_x
  32. ="20dip"<!-- have an eye on ! -->
  33. android
  34. :layout_y
  35. ="20dip"
  36. ><!-- have an eye on ! -->
  37. </
  38. TextView
  39. >
  40. </
  41. AbsoluteLayout
  42. >

简单吧,这里不在深入了!

8、标签布局(Tab Layout)

标签布局 :是一个ViewGroup以标签的方式显示它的子视图(view)元素,就像在Firefox中的一个窗口中显示多个网页一样。

为了狂创建一个标签UI (tabbed UI),需要使用到TabHostTabWidget 。TabHost 必须是布局的根节点,它包含为了显示标签的TabWidget 和显示标签内容的FrameLayout 。

可 以有两种方式实现标签内容:使用标签在同一个活动中交换视图、使用标签在完全隔离的活动之间改变。根据你的需要,选择不同的方式,但是如果每个标签提供不 同的用户活动,为每个标签选择隔离的活动,因此你可以更好地以分离的组管理应用程序,而不是一个巨大的应用程序和布局。 下面还有一个例子来创建一个标签UI,每个标签使用隔离的活动。

1)、在项目中建立三个隔离的Activity类:ArtistisActivity、AlbumActivity、SongActivity。它们每个表示一个分隔的标签。每个通过TextView显示简单的一个消息,例如:

  1. public
  2. class
  3. ArtistsActivity extends
  4. Activity { public
  5. void
  6. onCreate(Bundle savedInstanceState) { super
  7. .onCreate(savedInstanceState); TextView textview = new
  8. TextView(this
  9. ); textview.setText("This is the Artists tab
  10. "); setContentView(textview); }}

其它两个类也类似。

2)、设置每个标签的图标,每个图标应该有两个版本:一个是选中时的,一个是未选中时的。通常的设计建议是,选中的图标应该是深色(灰色),未选中的图标是浅色(白色)。

现在创建一个state-list drawable 指定哪个图标表示标签的状态:将图片放到res/drawable目录下并创建一个新的XML文件命名为ic_tab_artists.xml ,内容如下:

  1. <?
  2. xml version="1.0" encoding="utf-8"?>
  3. <
  4. selector
  5. xmlns
  6. :android
  7. ="http://schemas.android.com/apk/res/android"
  8. >
  9. <!-- When selected, use grey -->
  10. <
  11. item
  12. android
  13. :drawable
  14. ="@drawable/ic_tab_artists_grey"
  15. android
  16. :state_selected
  17. ="true"
  18. />
  19. <!-- When not selected, use white-->
  20. <
  21. item
  22. android
  23. :drawable
  24. ="@drawable/ic_tab_artists_white"
  25. />
  26. </
  27. selector
  28. >

3)、res/layour/main.xml 的内容置为如下:

  1. <?
  2. xml version="1.0" encoding="utf-8"?>
  3. <
  4. TabHost
  5. xmlns
  6. :android
  7. ="http://schemas.android.com/apk/res/android"
  8. android
  9. :id
  10. ="@android:id/tabhost"
  11. android
  12. :layout_width
  13. ="fill_parent"
  14. android
  15. :layout_height
  16. ="fill_parent"
  17. >
  18. <
  19. LinearLayout
  20. android
  21. :orientation
  22. ="vertical"
  23. android
  24. :layout_width
  25. ="fill_parent"
  26. android
  27. :layout_height
  28. ="fill_parent"
  29. android
  30. :padding
  31. ="5dp"
  32. >
  33. <
  34. TabWidget
  35. android
  36. :id
  37. ="@android:id/tabs"
  38. android
  39. :layout_width
  40. ="fill_parent"
  41. android
  42. :layout_height
  43. ="wrap_content"
  44. />
  45. <
  46. FrameLayout
  47. android
  48. :id
  49. ="@android:id/tabcontent"
  50. android
  51. :layout_width
  52. ="fill_parent"
  53. android
  54. :layout_height
  55. ="fill_parent"
  56. android
  57. :padding
  58. ="5dp"
  59. />
  60. </
  61. LinearLayout
  62. >
  63. </
  64. TabHost
  65. >

这个布局将显示标签和提供上面创建的活动之间的导航。TabHost 要求包含一个TabWidget 和一个FrameLayout 。TabWidget 和FrameLayout TabHost 以线性垂直地显示。

4)、HelloWorld.java文件源码如下:

  1. package
  2. skynet.com.cnblogs.www;import
  3. android.widget.TabHost;import
  4. android.app.TabActivity;import
  5. android.content.Intent;import
  6. android.content.res.Resources;import
  7. android.os.Bundle;public
  8. class
  9. HelloWorld extends
  10. TabActivity{ /** Called when the activity is first created. */
  11. @Override public
  12. void
  13. onCreate(Bundle savedInstanceState) { super
  14. .onCreate(savedInstanceState); setContentView(R.layout.main); Resources res = getResources(); // Resource object to get Drawables
  15. TabHost tabHost = getTabHost(); // The activity TabHost
  16. TabHost.TabSpec spec; // Resusable TabSpec for each tab
  17. Intent intent; // Reusable Intent for each tab
  18. // Create an Intent to launch an Activity for the tab (to be reused)
  19. intent = new
  20. Intent().setClass(this
  21. , ArtistsActivity.class
  22. ); // Initialize a TabSpec for each tab and add it to the TabHost
  23. spec = tabHost.newTabSpec("artists
  24. ").setIndicator("Artists
  25. ", res.getDrawable(R.drawable.ic_tab_artists)) .setContent(intent); tabHost.addTab(spec); // Do the same for the other tabs
  26. intent = new
  27. Intent().setClass(this
  28. , AlbumsActivity.class
  29. ); spec = tabHost.newTabSpec("albums
  30. ").setIndicator("Albums
  31. ", res.getDrawable(R.drawable.ic_tab_artists)) .setContent(intent); tabHost.addTab(spec); intent = new
  32. Intent().setClass(this
  33. , SongsActivity.class
  34. ); spec = tabHost.newTabSpec("songs
  35. ").setIndicator("Songs
  36. ", res.getDrawable(R.drawable.ic_tab_artists)) .setContent(intent); tabHost.addTab(spec); tabHost.setCurrentTab(2); }}

设置每个标签的文字和图标,并分配每个标签一个活动(这里为了方便三个标签都有相同的图标)。TabHost的引用第一次通过getTabHost() 获取。然后,为每个标签,创建TabHost.TabSpec 定义标签的属性。newTabSpec(String) 方法创建一个新的TabHost.TabSpec 以给定的字符串标识标签。调用TabHost.TabSpec , setIndicator(CharSequence, Drawable) 为每个标签设置文字和图标,调用setContent(Intent) 指定Intent 去打开合适的活动。每个TabHost.TabSpec 通过调用addTab(TabHost.TabSpec) 添加到TabHost。

最后,setCurrentTab(int) 设置打开默认显示的标签,通过索引标签的位置。

5)、打开Android的清单文件AndroidManifest.xml ,添加NoTitleBar 主题到HelloWorld的<activity> 标记。这将移除默认应用程序的标题和顶端布局,给标签腾出位置。<activity> 标记应该像这样:

  1. <
  2. activity
  3. android
  4. :name
  5. =".HelloWorld"
  6. android
  7. :label
  8. ="@string/app_name"
  9. android
  10. :theme
  11. ="@android:style/Theme.NoTitleBar"
  12. >

你运行这个程序能够得到什么结果呢?请自行检查。不过我在这里告诉你很有可能会运行不了,报“java.lang.NullPointerException ”错!我想运行这个例子的很多人都会有这个问题,不信你试试!

PS:其实这也算是Android的一个bug,而且这个bug在2.2中还没有解决,这个问题全球N多人都碰到了,并在http://code.google.com/p/android/issues 中挂号了,相关问题的编号有不止一个。

``

接着往下看……

如果你看了我这篇文章,你一定会是个幸运儿!经过我艰苦的调试+找资料,我找到了解决方法:

在清单文件AndroidManifest.xml ,添加下面三个Activity:

< activity android :name =”.AlbumsActivity” android :label =”@string/app_name” > </ activity >
< activity android :name =”.ArtistsActivity” android :label =”@string/app_name” > </ activity >
< activity android :name =”.SongsActivity” android :label =”@string/app_name” > </ activity >

现在运行可以看到如下结果:

tablayout 图9、标签布局

http://dev.10086.cn/cmdn/wiki/index.php?doc-view-3347.html

发表评论

表情:
评论列表 (有 0 条评论,517人围观)

还没有评论,来说两句吧...

相关阅读

    相关 Android布局

    Android布局             我们对[Android][] [应用程序][Link 1] 运行原理及布局文件可谓有了比较深刻的认识和理解,并且用“