转贴 Android(安卓)开发之旅:view的几种布局方式及实践
16lz
2021-01-25
我们对Android应用程序运行原理及布局文件可谓有了比较深刻的认识和理解,并且用“Hello World!”程序来实践证明了。在继续深入Android开发之旅之前,有必要解决前两篇中没有介绍的遗留问题: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的布局显示概述
通过前面的学习我们知道:在一个Android应用程序中,用户界面通过View和ViewGroup对象构建。Android中有很多种View和ViewGroup,他们都继承自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"?>
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:orientation="horizontal">
从上面可以看出根LinearLayout视图组(ViewGroup)包含5个Button,它的子元素是以线性方式(horizontal,水平的)布局,运行效果如下图所示:
图2、线性布局(水平或者说是横向)
如果你在android:orientation="horizontal"设置为vertical,则是是垂直或者说是纵向的,如下图所示:
图3、线性布局(垂直或者说是纵向)
2.1、Tips:android:layout_weight="1"
这个属性很关键,如果你没有显示设置它,它默认为0。把上面布局文件(水平显示的那个)中的这个属性都去掉,运行会得出如下结果:
图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"?>
android:layout_width="fill_parent"
android:layout_height="fill_parent">
android:id="@+id/label"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="Type here:"/>
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"/>
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" />
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_toLeftOf="@id/ok"
android:layout_alignTop="@id/ok"
android:text="Cancel" />
从上面的布局文件我们知道,RelativeLayout视图组包含一个TextView、一个EditView、两个Button,注意标记了(请注意运行代码的时候,请把这些注释去掉,否则会运行出错,上面加上是为了更加醒目!)的属性,在使用相对布局方式中就是使用这些类似的属性来定位视图到你想要的位置,它们的值是你参照的视图的id。这些属性的意思很简单,就是英文单词的直译,就不多做介绍了。运行之后,得如下结果:
图5、相对布局
4、 表格布局(Table Layout)
表格布局:是一个ViewGroup以表格显示它的子视图(view)元素,即行和列标识一个视图的位置。其实Android的表格布局跟HTML中的表格布局非常类似,TableRow 就像HTML表格的标记。
用表格布局需要知道以下几点:
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"?>
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:shrinkColumns="0,1,2">
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Hello, I am a Button1"
android:layout_column="0"
/>
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Hello, I am a Button2"
android:layout_column="1"
/>
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Hello, I am a Button3"
android:layout_column="1"
/>
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Hello, I am a Button4"
android:layout_column="1"
/>
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Hello, I am a Button5"
android:layout_column="2"
/>
运行之后可以得出下面的结果:
图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"?>
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:padding="10dp"
android:textSize="16sp" >
这样就定义了元素在列表中的布局。
2)、src/skynet.com.cnblogs.www/HelloWorld.java文件的代码如下:
package skynet.com.cnblogs.www;
import android.app.ListActivity;
import android.os.Bundle;
import android.view.View;
import android.widget.AdapterView;
import android.widget.ArrayAdapter;
import android.widget.ListView;
import android.widget.TextView;
import android.widget.Toast;
import android.widget.AdapterView.OnItemClickListener;
public class HelloWorld extends ListActivity { //注意这里Helloworld类不是扩展自Acitvity,而是扩展自ListAcitivty
/** Called when the activity is first created. */
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setListAdapter(new ArrayAdapter(this, R.layout.main, COUNTRIES));
ListView lv = getListView();
lv.setTextFilterEnabled(true);
lv.setOnItemClickListener(new OnItemClickListener() {
public void onItemClick(AdapterView<?> parent, View view,
int position, long id) {
// When clicked, show a toast with the TextView text
Toast.makeText(getApplicationContext(), ((TextView) view).getText(),
Toast.LENGTH_SHORT).show();
}
});
}
static final String[] COUNTRIES = new String[] {
"1", "2", "3", "4", "5",
"6", "7", "8", "9", "10",
"11", "12", "13", "14", "15",
"16", "17", "18", "19", "20",
"21", "22", "23", "24"
};
}Note:onCreate()函数中并不像往常一样通过setContentView()为活动(Activity)加载布局文件,替代的是通过setListAdapter(ListAdapter)自动添加一个ListView填充整个屏幕的ListActivity。在此文件中这个方法以一个ArrayAdapter为参数:setListAdapter(new ArrayAdapter(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):
图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文件中的元素中,然后再源码中动态地读取。这样strings.xml的内容类似下面:
<?xml version="1.0" encoding="utf-8"?>
- 1
- 2
- 3
- 4
- 5
- 6
- 7
然而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
本文的主要内容就是分别介绍以上视图的七种布局显示方式效果及实现,大纲如下:
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的布局显示概述
通过前面的学习我们知道:在一个Android应用程序中,用户界面通过View和ViewGroup对象构建。Android中有很多种View和ViewGroup,他们都继承自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"?>
android:layout_height="fill_parent"
android:orientation="horizontal">
从上面可以看出根LinearLayout视图组(ViewGroup)包含5个Button,它的子元素是以线性方式(horizontal,水平的)布局,运行效果如下图所示:
图2、线性布局(水平或者说是横向)
如果你在android:orientation="horizontal"设置为vertical,则是是垂直或者说是纵向的,如下图所示:
图3、线性布局(垂直或者说是纵向)
2.1、Tips:android:layout_weight="1"
这个属性很关键,如果你没有显示设置它,它默认为0。把上面布局文件(水平显示的那个)中的这个属性都去掉,运行会得出如下结果:
图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"?>
android:layout_height="fill_parent">
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="Type here:"/>
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:background="@android:drawable/editbox_background"
android:layout_below="@id/label"/>
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" />
android:layout_height="wrap_content"
android:layout_toLeftOf="@id/ok"
android:layout_alignTop="@id/ok"
android:text="Cancel" />
从上面的布局文件我们知道,RelativeLayout视图组包含一个TextView、一个EditView、两个Button,注意标记了(请注意运行代码的时候,请把这些注释去掉,否则会运行出错,上面加上是为了更加醒目!)的属性,在使用相对布局方式中就是使用这些类似的属性来定位视图到你想要的位置,它们的值是你参照的视图的id。这些属性的意思很简单,就是英文单词的直译,就不多做介绍了。运行之后,得如下结果:
图5、相对布局
4、 表格布局(Table Layout)
表格布局:是一个ViewGroup以表格显示它的子视图(view)元素,即行和列标识一个视图的位置。其实Android的表格布局跟HTML中的表格布局非常类似,TableRow 就像HTML表格的
用表格布局需要知道以下几点:
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"?>
android:layout_height="fill_parent"
android:shrinkColumns="0,1,2">
android:layout_height="wrap_content"
android:text="Hello, I am a Button1"
android:layout_column="0"
/>
android:layout_height="wrap_content"
android:text="Hello, I am a Button2"
android:layout_column="1"
/>
android:layout_height="wrap_content"
android:text="Hello, I am a Button3"
android:layout_column="1"
/>
android:layout_height="wrap_content"
android:text="Hello, I am a Button4"
android:layout_column="1"
/>
android:layout_height="wrap_content"
android:text="Hello, I am a Button5"
android:layout_column="2"
/>
运行之后可以得出下面的结果:
图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"?>
android:layout_height="fill_parent"
android:padding="10dp"
android:textSize="16sp" >
这样就定义了元素在列表中的布局。
2)、src/skynet.com.cnblogs.www/HelloWorld.java文件的代码如下:
package skynet.com.cnblogs.www;
import android.app.ListActivity;
import android.os.Bundle;
import android.view.View;
import android.widget.AdapterView;
import android.widget.ArrayAdapter;
import android.widget.ListView;
import android.widget.TextView;
import android.widget.Toast;
import android.widget.AdapterView.OnItemClickListener;
public class HelloWorld extends ListActivity { //注意这里Helloworld类不是扩展自Acitvity,而是扩展自ListAcitivty
/** Called when the activity is first created. */
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setListAdapter(new ArrayAdapter
ListView lv = getListView();
lv.setTextFilterEnabled(true);
lv.setOnItemClickListener(new OnItemClickListener() {
public void onItemClick(AdapterView<?> parent, View view,
int position, long id) {
// When clicked, show a toast with the TextView text
Toast.makeText(getApplicationContext(), ((TextView) view).getText(),
Toast.LENGTH_SHORT).show();
}
});
}
static final String[] COUNTRIES = new String[] {
"1", "2", "3", "4", "5",
"6", "7", "8", "9", "10",
"11", "12", "13", "14", "15",
"16", "17", "18", "19", "20",
"21", "22", "23", "24"
};
}Note:onCreate()函数中并不像往常一样通过setContentView()为活动(Activity)加载布局文件,替代的是通过setListAdapter(ListAdapter)自动添加一个ListView填充整个屏幕的ListActivity。在此文件中这个方法以一个ArrayAdapter为参数:setListAdapter(new ArrayAdapter
setOnItemClickListener(OnItemClickListener)定义了每个元素的点击(on-click)的监听器,当ListView中的元素被点击时,onItemClick()方法被调用,在这里是即一个Toast消息——每个元素的位置将显示。
3)、运行应用程序得如下结果(点击1之后,在下面显示了1):
图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文件中的
<?xml version="1.0" encoding="utf-8"?>
String[] countries = getResources().getStringArray(R.array.countries_array);
setListAdapter(new ArrayAdapter
5.2、补充说明
首先总结一下列表布局的关键部分:
布局文件中定义ListView
Adapter用来将数据填充到ListView
要填充到ListView的数据,这些数据可以字符串、图片、控件等等
其中Adapter是ListView和数据源之间的桥梁,根据数据源的不同Adapter可以分为三类:
String[]: ArrayAdapter
List