Layouts(布局)

布局

布局定义了用户界面的可视话结构,比如 activity 或 widget 的UI。你可以用下面两种方式声明布局:

  • 在XML中声明UI元素. Android提供了与视图类和子类名一致的一些简单的XML词汇,比如那些窗口部件和布局。
  • 运行时初始化布局元素. 你的应用可以以编程的方式创建View和ViewGroup(并且可以修改它们的属性)。

Android框架允许你灵活的独自使用或全部使用这些方法去声明和管理应用的UI。例如,你可以在XML中声明应用的默认布局,包括会在布局中显示的屏幕元素和它们的属性。然后在运行时你可以在应用里添加代码来修改屏幕对象的状态,包括那些在XML声明的对象。

  • ADT Plugin for Eclipse 可以在布局的XML文件打开并选中Layout标签时为你提供布局的预览。
  • 你也应该尝试使用 Hierarchy Viewer 工具来调试布局,它可以获取布局属性值,使用指示器绘制出padding/margin的线框,完整的呈现你在模拟器或设备上调试时的视图。
  • layoutopt工具可以让你快速分析布局和层次的来解决低效和其他问题。 

在XML里声明UI的优势是它使应用的外观从控制它行为的代码中分离出来成为可能。用户界面的描述与应用的代码是不相关的,这意味着你可以在不修改源代码和重新编译的情况下修改或适配用户界面。例如,你可以根据不同的屏幕方向、不同的屏幕尺寸和不同的语言设置XML布局。此外,在XML中声明布局使用户界面可视化更容易,所以调试问题会更简单。照此,这篇文档集中于如何在XML中声明布局的教学。如果你对于在运行时实例化视图对象感兴趣,请参考 ViewGroup 和 View 类的参考文档。

一般来说,声明UI元素的XML词汇效仿类和方法的结构和命名,元素名与类名保持一致,属性名与方法名保持一致。实际上,你可以直接依据类的方法来猜测XML的属性,依据XML元素来猜测类名。然而,注意并不是所有的词汇都这样。有时候,它们的命名稍有不同。例如,EditText元素的 text 属性对应于 EditText.setText()

小贴士:在 Common Layout Objects 中学习更多关于不同类型布局的知识。在 Hello Views 教学指南中有构建各种布局的教学。

编写XML


学会Android的XML词汇后,你可以很快的用一系列的内联元素设计出UI布局和包含在其中的屏幕元素,就像你使用HTML创建网页一样。

每个布局文件必须恰好包含一个根元素,它必须是一个View或ViewGroup对象。一旦你定义了根元素,你可以添加额外的布局对象或窗口部件作为子元素来逐渐的构建那个定义你布局的视图层次。例如,下面是使用垂直的 LinearLayout 来包含一个 TextView 和一个 Button 的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="vertical" >
    <TextView android:id="@+id/text"
              android:layout_width="wrap_content"
              android:layout_height="wrap_content"
              android:text="Hello, I am a TextView" />
    <Button android:id="@+id/button"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="Hello, I am a Button" />
</LinearLayout>

在XML中声明好你布局后,使用.xml扩展名把这个文件保存到你的Android工程里的res/layout/目录中,这样它才会正确的编译。

更多关于布局的XML文件中语法的信息可以从 Layout Resources 文档中获得。

加载XML资源


编译应用时,每个XML布局文件会被编译进一个 View 资源中。你应该在应用的 Activity.onCreate() 回调实现的代码里加载布局资源。可以通过调用 setContentView() 来加载布局资源,需要把布局资源的引用以R.layout.layout_file_name格式传递给这个方法。例如,如果你的XML布局保存为main_layout.xml,你应该像这样为你的Activity加载它:

public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.main_layout);
}

Activity里的 onCreate() 回调方法会在Activity启动时被Android框架调用(参考 Activities 文档中关于生命周期的讨论)。

属性


每种View和ViewGroup对象都支持它们自己的多种XML元素。有些属性是视图对象独有的(例如,TextView支持的textSize属性),但是这些属性也可以被任何继承该类的视图对象继承。有些属性是所有视图对象共有的,因为它们继承自跟视图类(比如id属性)。另外,其他用来确定视图对象布局方向的被称为“布局参数”的属性是由对象的父ViewGroup对象定义。

ID

任何视图对象都可以有一个与之关联的用来在树中唯一标识视图的整型ID。当应用被编译后,这些ID会被引用为整型,但是在布局XML文件中的id属性要指定为字符串类型。这是所有视图(View 类定义的)对象共有的XML属性,你以后会经常用到的。在XML标签里ID的语法是这样的:

android:id="@+id/my_button"

在字符串前面的at符号(@)表明XML解析器应该把剩余的ID字符串当做ID资源来解析和扩展。加号(+)表示这是一个新的资源名, 它必须被创建和添加到我们的资源中(在R.java文件中)。剩下的其他ID资源由Android框架提供。要引用一个Android资源ID时,你不需要使用加号符,但是必须添加android包命名空间,就像这样:

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

在适当的地方使用android包命名空间,我们现在可以从android.R资源类中引用ID,而不是从本地资源类。

在应用中创建视图和引用它们的大众模式是:

  1. 在布局中定义视图/部件,然后制定唯一的ID:
    <Button android:id="@+id/my_button"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="@string/my_button_text"/>
  2. 然后从布局中获取视图对象的实例(一般在 onCreate() 方法中):
    Button myButton = (Button) findViewById(R.id.my_button);

在创建 RelativeLayout 时为视图对象定义ID尤为重要。在相对布局里,同级视图可以通过唯一ID来引用其它的同级视图,并相对与它们来定义自己的布局。

ID不需要在整个树中唯一,但是应该在你正在搜索的某部分树中是唯一的(可能经常使用整个树,所以最好尽可能的完全唯一)。

布局参数

layout_something命名的XML布局属性用来为适合放入ViewGroup中的View定义布局参数的。

每个ViewGroup类都有一个继承了 ViewGroup.LayoutParams 的嵌套类。这些嵌套类包含一些用来定义ViewGroup内每个子View的大小和位置的属性类型。正如你在图1中看到的,父ViewGroup为每个子View定义了布局参数(包括子ViewGroup)。

图1. 图形化的带有每个相关联视图的布局参数的视图层级。

注意每个LayoutParams子类都有自己的一套设置属性值的语法。每个子元素必须定义适用于它父节点的LayoutParams,尽管它可能已为自己的子接口定义不同的LayoutParams。

所有的ViewGroup都包含宽度和高度属性(layout_widthlayout_height),并且所有的视图都需要定义它们。另外很多LayoutParams也包含可选的边距和边框。

你可以使用精确的尺寸来指定宽度和高度,尽管你通过可能不会这么做。更多的时候,你会使用这些常量去设置宽度或高度:

  • wrap_content 使你的视图尺寸适配它内容需要的大小
  • fill_parent (在API等级8中更名为match_parent )使你的视图与它的父ViewGroup允许的尺寸一样大

一般而言,不提倡使用诸如像素的绝对单位来指定布局的宽度和高度,而是更适合使用诸如密度无关像素(dp)的相对尺寸,wrap_content,或fill_parent,这样可以保证你的应用在不同尺寸的屏幕上显示正常。这些公认的尺码类型在 Available Resources 中有明确说明。

布局位置


视图的几何结构就是矩形。视图有位置属性,表现为左上坐标系,还有两个尺寸,表现为宽度和高度。位置和尺寸的单位是像素。

通过调用 getLeft() 和 getTop() 方法可以获得视图的位置,前一个方法返回视图距离显示视图的矩形的左或X坐标,后一个方法返回视图距离显示视图的矩形的上或Y坐标。这些方法返回的都是视图相对于他们父节点的位置。例如,getLeft()返回20就表示这个视图在距离它的直接父节点左边缘的右边20像素处。 

此外,还提供了一些便利的方法来避免不必要的计算,也就是 getRight()和 getBottom()。这些方法返回视图距离显示视图的矩形的右边距坐标和下边距坐标。例如,调用 getRight() 的结果与下面的计算结果相同:getLeft() + getWidth().

大小,内边距,外边距


视图的大小通过宽度和高度来表现。视图实际上具有两组宽度和高度值。

第一组被称为测量宽度和测量高度。这些尺寸定义了视图在它的父容器里想要表现为多大。这些测量尺寸可以通过调用 getMeasuredWidth() 和 getMeasuredHeight() 获得。

第二组简称为宽度和高度,有时也被称为绘制宽度和绘制高度。这些尺寸在绘制时或布局后定义了视图在屏幕上的实际大小。这些值可能但不一定和测量宽度和高度不同。这些宽度和高度可以通过调用 getWidth() 和 getHeight() 获得。

测量视图的尺寸就不得不考虑到它的内边距。视图的左,右,上,下部分的内边距都是用像素表示的。可以给内边距一个指定的像素值来偏移视图的内容。例如,左侧2个单位的内边距会把视图的内容从视图的左边界向右移动2个像素。可以用 setPadding(int, int, int, int) 方法来设置内边距,用 getPaddingLeft()getPaddingTop()getPaddingRight() 和 getPaddingBottom() 查询内边距。

尽管View可以定义内边距,但是对于外边距不提供任何支持,ViewGroup提供外边距的支持。请参考 ViewGroup 和 ViewGroup.MarginLayoutParams 获取更多信息。

请阅读 Dimension Values 获取更多关于尺寸的信息。

常用布局


每种 ViewGroup 类的子类都提供了唯一一种显示嵌入在其中的视图的方式。下面是Android平台内置的一些常用的布局类型。

注解:尽管为了达到你的UI设计效果你可以在一个布局中嵌套一个或多个的布局,你应该尽可能的保持浅的布局层级。如果你的布局里的嵌套布局比较少,那么它的绘制速度就会很快(宽视图层级比深视图层级要好)。

Linear Layout

这是一种把它的子节点组织到单一的水平行或垂直列中的布局。如果窗口的长度超过屏幕的长度,它会添加一个滚动条。

Relative Layout

允许你指定子节点对象相对于其它子节点(子节点A在子节点B的左边)或父节点(与父节点的顶部对齐)的相对位置。

Web View

显示网页。pages.

使用适配器构建布局


当你布局的内容是动态的或者是非预设的时候,你可以使用 AdapterView 子类,这样就能在运行时用视图去填充布局。AdapterView 类的子类使用 Adapter 把数据绑定到布局上。Adapter 在数据源和  AdapterView 布局中间扮演中间人的角色,Adapter 获取数据(从诸如数组或数据库查询结果的数据源)并且把每个条目转化成可以添加到 AdapterView 中的视图。

依赖适配器的一般布局包含:

List View

显示一个滚动的单列列表。

Grid View

显示一个滚动的网格。

用数据填充AdapterView

你可以通过把 AdapterView 的实例绑定上 Adapter 来填充诸如 ListView 或 GridView 的 AdapterViewAdapter 可以从外部数据源中获取数据并且创建代表每个数据条目的 View

Android提供了一些有用的 Adapter 子类来为 AdapterView 获取各种数据和构建视图。最常见的是这两种适配器:

ArrayAdapter
在你的数据源是一个数组时使用这种适配器。默认情况下, ArrayAdapter 通过在每个数组项上调用  toString() 并把内容放置在  TextView 内为每个数组项创建视图。

例如,如果你想在 ListView 上显示字符串数组,使用构造器实例化一个新的 ArrayAdapter 来为字符数组和每个字符串指定布局。

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

构造器的参数:

  • 你应用的 Context
  • 包含一个作为数组中的字符串容器 TextView 的布局
  • 字符数组

然后只需调用 ListView 的 setAdapter()

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

如果你想自定义每个项目的外观,你可以为数组内的对象重写 toString() 方法。或者为项目创建非 TextView 的视图(例如,ImageView),然后继承 ArrayAdapter 类,重写 getView() 为每一项返回你想要类型的视图。

SimpleCursorAdapter
在你的数据来自  Cursor 时使用这种适配器。使用  SimpleCursorAdapter 时,你必须为  Cursor 中的每行指定一个布局, Cursor 的列值应该被插入到该布局中的视图中。例如,如果你想创建一个包含用户姓名和电话号码的列表,你可以执行一个能返回包含每个用户行和姓名号码列的  Cursor 的查询。然后你可以创建字符串数组来指定  Cursor 中的哪些列你想要出现在布局中,创建整型数组来指定每一列放置在哪些相应的视图上。

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

实例化 SimpleCursorAdapter 时,需要传递每项结果需要使用的布局,包含结果的 Cursor 和这两个数组:

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

SimpleCursorAdapter 然后通过把每个fromColumns项目插入到相应的toViews视图中为使用指定布局的 Cursor 中的每一行创建视图。

假如你在应用生命周期的过程中改变了适配器使用的基本数据,那么你应该调用 notifyDataSetChanged(),这样会通知关联的视图数据已经改变而且应该刷新自己。

捕获点击事件

通过实现 AdapterView.OnItemClickListener 接口你可以响应 AdapterView 中每个项目的点击事件。例如:

// 创建一个捕获消息的匿名类对象
private OnItemClickListener mMessageClickedHandler = new OnItemClickListener() {
    public void onItemClick(AdapterView parent, View v, int position, long id) {
        // 在这里响应点击事件
    }
};

listView.setOnItemClickListener(mMessageClickedHandler); 
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值