您的位置:首页 > 移动开发 > Android开发

Android Layouts

2015-12-03 14:49 513 查看

概述

Android中所有的用户界面都是由View和ViewGroup对象构成的. View是可以显示在屏幕上的一些控件, 它们可以跟用户交互. ViewGroup则是”包含”其它View和ViewGroup的容器, 用于定义界面的布局.

Android提供了很多现成的View(比如Button和TextView等)和ViewGroup(LinearLayout和RelativeLayout等)可以使用.

View和ViewGroup之间的协作如下图:



每个ViewGroup都是不可见的容器, 它可以包含其它的ViewGroup和View. View则用来处理用户的输入输出,显示等, 负责与用户交互. 上图中的tree可以很复杂也可以很简单, 但是建议不要太复杂, 否则在绘制的时候会影响性能.

为了构建这样的一棵tree, 我们可以在代码里实例化View来实现, 但是最简单和常用的方法还是在XML文件中构建, XML提供了易读的标签给我们, 更加便于实现这样的结构, 就好像HTML那样. 每个XML中的标签都对应一个Android类, 比如<TextView>对应一个TextView类, <LinearLayout>对应一个LinearLayout的ViewGroup. Layout为用户界面定义了虚拟的结构, 比如activity和widget的UI. 我们有两种方法可以定义一个layout:

1.      在XMl文件中声明一个layout. Android为View类和其子类提供了一个简单的关键字对照表. 这样在XML文件中就可以直接声明一个View的类或者子类.

2.      在运行时实例化一个layout. APP可以通过编码在运行时实例化View或者ViewGroup.

两种方法可以灵活交叉运用. 比如可以在XML文件中定义默认的layout, 然后可以在代码中增加或者修改它们. 这样做的好处有一大把, 比如将UI的定义和操作分开来, 以达到降低耦合的目的. 还可以在不需要重新编译的情况下使用新的XML文件支持不同的屏幕尺寸, 配置等.

构建一个XML:

使用Android XML的关键词, 可以很快的构建出一个UI layout和它包含的元素. 这一点跟HTML有些类似. 每个layout文件必须包含一个根标签, 它必须是一个View或者ViewGroup的对象. 有了根标签之后就可以在其内部添加其它的layout标签或者widget标签作为子项. 比如下面这段代码是一个包含TextView和Button的垂直LinearLayout:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"

              android:layout_width="match_parent"

              android:layout_height="match_parent"

              android:orientation="vertical">

    <TextView android:id="@+id/text"

              android:layout_width="wrap_content"

              android:layout_height="wrap_content"

              android:text="Hello, Iam a TextView"/>

    <Button android:id="@+id/button"

            android:layout_width="wrap_content"

            android:layout_height="wrap_content"

            android:text="Hello, Iam a Button"/>
</LinearLayout>

该文件必须以.xml为扩展名, 并且保存在/res/layout下, 才能被系统正常识别并且编译.

加载一个XML文件资源:

当我们编译工程的时候, 每个XML layout文件都会被编译成一个view资源. 我们应该在Activity.onCreate()方法中调用setContentView()方法来加载一个layout资源文件. 假如文件名是main_layout.xml, 那么加载该xml文件的代码如下:

public
void onCreate(BundlesavedInstanceState){

    super.onCreate(savedInstanceState);

    setContentView(R.layout.main_layout);
}

onCreate由Android framework在activity加载的时候调用.

属性:

每个View和ViewGroup都支持自己的XML属性. 有些是指定给特定属性的(比如TextView的textSize属性), 有些属性则可以应用于所有的View对象(比如id属性).

ID:

任何一个View对象都可以包含一个整型的ID与其关联, 以便于识别该对象. 这是一个极为常用的属性, 下面是它的语法:

android:id="@+id/my_button"

“@”表示XML解析器应该展开这个ID字符串的剩余部分, 作为一个ID资源处理它. “+”表示这是一个新的资源名称,必须新建并且添加到资源文件(R.java)中. Android framework提供了一些ID资源, 使用这些ID资源的时候, 不需要使用”+”, 但是需要指定android的命名空间, 比如:

android:id="@android:id/empty"

当使用android的命名空间的时候, 我们需要使用android.R资源类而不是本地的资源类.

我们通常这样让xml中的view与APP中的代码关联起来:

1.      在layout文件中定义一个view或者widget, 为其指定一个ID:

<Button
android:id="@+id/my_button"

        android:layout_width="wrap_content"

        android:lay
4000
out_height="wrap_content"

        android:text="@string/my_button_text"/>

2.      在代码中创建实例, 并且将其与layout文件中的对象关联起来(通常在onCreate()方法中):

Button myButton = (Button) findViewById(R.id.my_button);


在RelativeLayout中定义ID十分重要, 因为同级的view之间可以通过ID指定它们相对的布局关系. 

Layout参数:

XML layout使用layout_name格式的属性为layout内部的View指定参数. 每个ViewGroup都实现了一个ViewGroup.LayoutParams.这个类包含一些定义子View的尺寸和位置的属性. 如下图, 每个ViewGroup为其子View定义了layout参数:



注意图中的每个LayoutParams都有其自己的语法, 所以子View中LayoutParam的语法是由其父ViewGroup决定的.

所有的ViewGroup都包含宽和高属性(layout_width和layout_height), 并且每个view都需要定义它们. 很多LayoutParams都指定了自己的边距和边界格式. 宽高可以通过精确的数值指定, 也可以通过相对常量指定, 比如:

warp_content指定view的尺寸由它的内容决定.

match_parent(API8之前叫fill_parent)指定其尺寸跟父ViewGroup一样.

通常我们不推荐使用绝对的尺寸单位比如像素, 推荐使用密度无关的像素单位(dp), 或者warp_content或者match_parent, 这些值会让我们的APP在不同尺寸的屏幕下具有更好的兼容性.

Layout位置:

View的几何形状是矩形, Android通过指定左上角的坐标和宽高来确定一个View的位置. 坐标和宽高的单位是像素. 可以通过调用getLeft()和getTop()方法来获取到View的X, Y坐标. getRight()相当于getLeft()+getWidth(), getBottom()相当于getTop()+getHeight().

尺寸, 填充和边距:

View的尺寸由宽高决定. 事实上View有两对宽高.

第一对是测量宽高: 这对宽高指定View想要在父容器里所占的尺寸大小. 可以通过getMeasuredWidth()和getMeasuredHeight()获取.

第二对是前文提到的普通的width和height, 即实际尺寸, 可以跟测量宽高不同. 通过getWidth()和getHeight()方法获得.

测试尺寸的时候还应该考虑填充的问题, 可以使用setPadding(int, int, int, int)方法来设置填充. 比如左填充2pixel表示将view的内容从左边缘向右推2个像素. 查询填充尺寸则可以使用getPaddingLeft(),getPaddingTop(), getPaddingRight()和getPaddingBottom()这些方法.

View可以定义自己的填充值, 但是不能定义边距, 边距是由ViewGroup定义的.

普通Layout:

每个ViewGroup的子类都提供了子View不同的排列规则, 下面是几个常见的ViewGroup类型:

Linear layout:



线性布局, 将其内部的子模块按照水平或者垂直方向排列, 如果超出了屏幕尺寸, 就会产生一个滚动条.

Relative layout:



相对布局, 可以指定子模块相对于其它子模块或者父模块的位置(比如A在B的下面, 或者与父模块顶部对其等).

Web View:



显示一个网页.

嵌套ViewGroup可以实现更加复杂的布局, 但是也会加重绘制的负担, 所以应该尽量少嵌套ViewGroup.

通过Adapter构建一个layout:

当我们的布局需要在运行时确定, 可以使用ViewGroup的子类AdapterView来解决这一问题. AdapterView使用Adapter来绑定数据与layout, Adapter相当于数据与layout之间的搬运工, Adapter检索数据(通常是从Array或者数据库中获取数据)并转换为AdapterView认识的条目添加到AdapterView中. 常见的支持Adapter的布局有:

ListView:



显示一个可以滚动的单列列表.

GridView:



显示一个可以滚动的多列列表.

 

使用数据填充一个Adapter:

我们可以通过绑定AdapterView和Adapter为一个AdapterView(比如ListView和GridView)填充数据, Adapter从外部数据源检索数据, 然后创建一个View, 填充数据到View中, 再把View和AdapterView关联起来.

根据数据源的不同, Android提供了两种常用的Adapter:

1.      ArrayAdapter:

当数据源是一个Array的时候, 可以使用这种ArrayAdapter, 默认情况下ArrayAdapter通过Array中的每条数据的toString()方法获取字符串, 然后将其放入一个TextView中. 比如如果想在一个ListView中显示一个字符串Array中的内容, 那么可以像如下这样通过构造方法创建一个ArrayAdapter:

ArrayAdapter<String> adapter = new ArrayAdapter<String>(this,
        android.R.layout.simple_list_item_1, myStringArray);


其中的三个参数分别是:APP的Context, 为Array的每条数据指定一个TextView的layout, 字符串Array.

然后在ListView中调用setAdapter():

ListView listView = (ListView) findViewById(R.id.listview);
listView.setAdapter(adapter);


如果想要自定义每个Item的样子, 可以通过重写Array中的对象的toString()方法. 或者为ListView的每个Item创建View, 典型的就是我们的聊天程序, 我们经常需要在Text旁边放上一个图像代表头像. 只需要扩展ArrayAdapter类, 重写它的getView()方法, 返回想要的View即可.

2.      SimpleCursorAdapter:

当我们的数据来源是一个Cursor的时候, 我们可以使用SimpleCursorAdapter. 在使用SimpleCursorAdapter的时候需要为Cursor中的每一行指定对应的layout中的view. 比如如果我们想要创建一个电话簿的list, 那么我们就需要人名和对应的号码, 我们可以提供一个返回Cursor的查询, 然后创建一个string数组, 用来保存想要显示的字段, 还有一个整型数组, 用来保存要显示的View的ID:

String[] fromColumns = {ContactsContract.Data.DISPLAY_NAME,
                        ContactsContract.CommonDataKinds.Phone.NUMBER};
int[] toViews = {R.id.display_name, R.id.phone_number};


然后实例化一个SimpleCursorAdapter, 并传入layout, cursor和两个数组:

SimpleCursorAdapter adapter = new SimpleCursorAdapter(this,
        R.layout.person_name_and_number, cursor, fromColumns, toViews, 0);
ListView listView = getListView();
listView.setAdapter(adapter);


SimpleCursorAdapter会用传入的layout为cursor中的每行创建一个view,然后将fromColumns中的每个元素与toViews中的view对应.

如果在运行期间更改了Adapter的数据, 那么需要调用notifyDataSetChanged()来告知Adapter, 这样它才会更新自己的界面.

处理点击事件:

我们可以通过实现AdapterView.OnItemClickListener()方法来监听每一个AdapterView上的点击事件:

// Create a message handling object as an anonymous class.
private OnItemClickListener mMessageClickedHandler = new OnItemClickListener() {
    public void onItemClick(AdapterView parent, View v, int position, long id) {
        // Do something in response to the click
    }
};

listView.setOnItemClickListener(mMessageClickedHandler);


 

 

参考: http://developer.android.com/guide/topics/ui/declaring-layout.html
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  android layouts