本文是我从Declaring Layout翻译而来的文章,如果有不当之处请指出
布局决定了Activity所展现的样子,他决定了布局的结构和控制着你展现给用户所有的元素,你可以通过两种方式来声明你的布局.
①在xml文件中定义UI 元素:android提供了与View 类及其子类相关的简单易懂的标签。
②在运行时期定义你的布局,即采用代码的方式完成布局。你可以在程序中创建View和ViewGroup对象,并且可以操作他们。
android的框架可以让你灵活的使用一种或者两中方式来控制你的布局。例如,你可以在布局文件中声明应用默认的布局方式,包括屏幕中会出现的元素以及这些元素的属性,但是你可以在程序运行的时候,修改这些元素的属性。
采用xml文件布局的好处就是你可以将需要显示元素从你控制层的代码中分离出来,你描述UI的部分和应用的代码是分离的,这让你想修改这些布局文件时不需要考虑去修改应用的代码并且重新编译。例如你为不同方向的屏幕,不同大小、语言的设备,创建了不同的xml布局文件,你都不需要修改源码。此外通过布局文件的方式,你可以更加方便的想象你布局文件的结构,这样也方便了你来解决其中的问题,如果你坚持使用代码的方式来控制UI,请看View和ViewGroup的说明。
一般来说,布局xml的标签与UI元素的含义十分接近,标签的属性和相应类的属性也是一致的,实际上你可以根据xml标签猜出这个标签对应了那个类,并且根据属性来猜出与之对应的类的相应方法了。但是需要注意的是并不是所有的标签都是等同的。在一些情况下,有一些轻微的命名区别。例如EditText标签有text属性,与这个属性对应的方法是Edit.setText()。
ps:通过 Common Layout Objects可以学习到更多的不同布局类型,同时通过开发手册的Hello Views!也可以学习到布局文件的使用。
通过android布局文件的标签,你可以快速的设计出用户界面的布局,和布局文件中包含的元素,正如你使用html设计你的布局一样。
每一个布局文件都只能有一个根元素,并且与这个根元素对应的类是View或者是ViewGroup。在你定义了根元素之后,你可以通过添加其他的布局对象或者视图组件作为子元素来完成你的布局。例如下面的布局文件中就包含了一个TextVivew或者一个Button.
在你完成了布局文件的声明之后,把他作为一个xml文件保存在项目的res/layout文件夹下面,系统会自动完成编译。我们在稍后会讨论每一个出现的属性和标签。
当你完成了布局文件的声明之后,每一个xml布局文件都会被编译到一个View对象里面,你应该在你代码的onCreate方法中中来加载得到这个View对象。做法是通过调用setContentView()方法将R.layout.your_layout_name作为一个int类型的参数传递进去。例如你保存的xml文件名是main_layout.xml.你需要按照下面的方式来加载你的Activity
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView.(R.layout.main_layout);
}
onCreate方法会在Activity启动的时候被系统的调用。
每一个View对象都有一个与之关联的int类型的id,作为区别其他对象的根据,当应用被编译完成的时候,id会作为一个int类型的数值,但是在xml布局文件中它是android:id的值,作为一个字符串类型存在。这是所有的View 对象都会有的属性,这个属性是被View所定义的,所有继承于这个类的子类都会有id属性,你会经常需要使用它。声明id属性的语法如下
android:id="@+id/my_button"
@符号表示xml应该将这个id字符串后面的作为一个id来解析,+号表示这是一个新定义的资源,应该被创建并且添加我们项目的R.java文件中,同时android系统也会提供一些其他的id资源,当需要引用android系统的id时,不要使用 + 号,但是需要使用android,如下
android:id="@android:id/empty"
当使用了@android来引用一个资源的时候,我们应用的就是一个系统提供的资源而不是本地的资源。为了能够创建一个view对象,并且能够在代码中引用到这些定义的资源,一个通常的模式如下图。
1.首先定义一个布局文件并且给他们一个唯一的id
2.然后创建一个相应类的实例。
Button myButton = (Button) findViewById(R.id.my_button);
注意:在相对布局中使用id来区别对象是十分重要的,元素之间确定相对的位置都是用id来引用的。
名称为layout_*的布局文件属性,让视图在包含其的容器内有一个相对合理位置。每一个ViewGroup 类都包含了一个继承于ViewGroup.LayoutParams的嵌套类,这个子类包含了定义子视图位置和大小的属性,正如你看到的图,每个父类视图都为子视图定义了布局参数。
需要注意的是:每一个LayoutParams的子类都有它自己的设定值的语法,每一个子类使用这些布局参数都应该语气父类相匹配(例如,线性布局中就没有每个元素之间的相对位置)。每一个view都要求去定义layout_width和layout_height属性,许多布局文件都有可以选择定义边框和内框距离,你可以通过设定具体的数字来指定view的大小,但是你可能更多的会使用下面的常量来定义这些值。
wrap_content 让view包裹其中的子视图,其中子视图的大小决定了view的大小
fill_parent 填充父类的大小,父类有多大,view就有多大。
一般来说,使用绝对的像素值类确定view的大小是不被推荐的。你应该使用一些相对的数字来替代,例如dp或者wrap_content ,fill_parent。这将帮助你的应用能够适用于不同大小的设备。
一个视图的几何形状是矩形的,每个视图都有位置,表示为坐标,同时还有两个尺寸,表示为宽和高,坐标和尺寸的单位都是像素。
如果需要得到视图的位置,可以通过getLeft和getTop两个方法得到,返回的值可以分别作为视图左上角的坐标。这些方法返回的值都是相对于其父类的,例如,当getLeft返回的值是20,这说明view距离它的直接父容器的左边20
此外,还有一些简单的方法能够让你免于计算,例如getRight和getBottom;这些方法分别返回其右边的x坐标,和底边的Y坐标,例如 getRight相当于 getLeft + getWidth
视图的大小实际上表示为宽和高,一个视图实际上拥有了两个宽度值和高度值。
第一对值作为测量宽和测量高。这些数值表示了这个视图想在其父类中占有多大的位置。这个数据可以通过getMeasuredWidth和getMeasuredHeight
第二对 数据值作为width和 height ,这个数据定义了视图在屏幕上的实际大小,这些数据不需要和measured width与measured height完全不一样,这些数据可以通过getWidth 和 getHeight得到。
为了测量其尺寸,视图将它的填充数据(padding)计算在内了。尽管view提供了对padding的支持,但是并没有提供对margins的支持,但是ViewGroup却提供了。