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
相关文章推荐
- 使用C++实现JNI接口需要注意的事项
- Android IPC进程间通讯机制
- Android Manifest 用法
- [转载]Activity中ConfigChanges属性的用法
- Android之获取手机上的图片和视频缩略图thumbnails
- Android之使用Http协议实现文件上传功能
- Android学习笔记(二九):嵌入浏览器
- android string.xml文件中的整型和string型代替
- i-jetty环境搭配与编译
- android之定时器AlarmManager
- android wifi 无线调试
- Android Native 绘图方法
- Android java 与 javascript互访(相互调用)的方法例子
- android 代码实现控件之间的间距
- android FragmentPagerAdapter的“标准”配置
- Android"解决"onTouch和onClick的冲突问题
- android:installLocation简析
- android searchView的关闭事件
- SourceProvider.getJniDirectories