Android UI基础
Android UI概述
Android UI由View和ViewGroup组成。
ViewGroup是不可见的,用于组织和排版View和ViewGroup。
View用户显示内容,以及响应用户的操作。
可以按照需要安排UI的叠放,不过叠放的层数越少,性能上来说越好。
Android UI可以在code中生产,不过更加方便的方式是在Android的XML文件中定义UI。
Layouts 通过XML方式实现
可以通过2种方式定义界面结构。
1. 在XML定义视图结构
2. 在运行时动态创建视图结构
通过XML定义视图结构,可以有效的做到代码与界面分离,并且提高界面结构的可读性。
XML书写方式
xml的file必须包含一个root,可以是View或者ViewGroup。在节点下面增加子界面的方式来构造界面结构。
xml的基本书写结构可以参照http://developer.android.com/guide/topics/resources/layout-resource.html
加载xml资源
在编译程序阶段,所有的XML layout文件都会编译到一个统一的View资源里面。
在需要使用layout资源的时候,需要将资源加载到程序中,一般的做法是在
Activity.onCreate()中做加载的资源的操作。
如果界面的文件名称是main_layout.xml,则可以如下方式加载。
public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main_layout); }
XML layout属性
每个View或者ViewGroup都有自己特有或者继承下来的属性。
ID
每一个View或者ViewGroup都有一个ID属性。该属性由class View定义。其定义语法为:
android:id="@+id/my_button"
@ 的意思是指示XML parser解析并且展开后面的内容,将其作为一个ID的资源。
+ 的意思是指示这是一个新的ID,需要将其加到资源定义文件R.java中去。
有一些系统自定的ID,如果引用这些系统自定义的ID,则不需要加+号,但需要加上包的命名空间,其定义的语法为:
android:id="@android:id/empty"
常用的定义一个view或者widget,并且在代码中调用的方式如下:
1.定义一个View,并且配置一个唯一的ID
<Button android:id="@+id/my_button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/my_button_text"/>
2.使用这个唯一的ID在代码中创建实例
Button myButton = (Button) findViewById(R.id.my_button);IDs在
RelativeLayout中会显的更加的重要,因为需要通过IDs来指定其旁边的View。哪个View在自己的左边,哪个View在自己的右边,或者上面或者下面。
Layout相关的参数
在XML文件中,通常使用layout_something来定义View在ViewGroup中的位置
ViewGroup类会实现一个嵌套类来扩展ViewGroup.LayoutParams.这个内嵌的子类会定义类型来指定子View的位置和大小。
如下图所示,父view group会为其子view或者子view group都定义layout参数
Layout参数对于其父节点和对于其子节点的含义都可能是不一样的,因此要区别对待。
每一个view group一般都会包含width和height参数(layout_width and layout_height),因此每个再其内的view都需要定义这俩个属性。
一般我们不会将其指定为某一个宽度或者高度,一般写为相对的,这样可以保证适应于多种屏幕大小的设备。
- wrap_content:根据内容的大小调节大小
- fill_parent:最大化达到父几点所允许的,在API level 8后名字改为match_parent
Layout的位置
View作为一个几何图形,具有4个属性对应于他所属的容器,分别是left, top, width和height,每个属性的单位是pixel
参考API文档,可以很多函数获取位置以及View的大小信息。getLeft(),getTop(),getRight(),getBottom()。
获取的值一般都是相对应与父节点的位置和大小信息
Size,Padding和Margins
Size由View的width和height来表示。
width和height有2种类型,一种是对应于父容器的measured width和measured height,其是相对于父容器的高度和宽度。可以由getMeasuredWidth()和getMeasuredHeight()获取。
另外一种是针对于整个界面的实际width和height,可以由getWidth()和getHeight()获取。
Padding也会被计算入measure
size内,Padding,顾名思义,是内容与View空间直接的间隔。可以由函数setPadding(int,
int, int, int)进行设置。可由getPaddingLeft(),getPaddingTop(),getPaddingRight(),
getPaddingBottom()获取相对应额值。
View并未提供Margins属性,该属性一般由ViewGroup设置。
Layout的通常模式
每一个ViewGroup都会提供一种特有的排列方式。下面是几种常看见的方式。
Note:尽管可以通过在layout中嵌入其他的layout方式来设计一个结构复杂的layout,但是这样会导致layout的结构变的复杂。不利于UI的性能。尽量保持UI嵌套的层数少些。
Linear Layout |
Relative Layout |
Web View |
将内容排列成横列或者竖列显示,如果超出屏幕,则显示滚动条。 | 可以灵活的设置子view的位置,已经子view之间的位置。 | 像浏览器一样显示HTML文档 |
绑定数据源
如果需要在界面上显示的内容是动态获取的话,可以使用使用Adapter和继承AdapterView的View来动态显示。
Adapter是数据源和AdapterView之前的桥梁,由他从数据源获取数据,然后转换为一组实体,填充到View。
一般的数据显示模式如下:
List View |
Grid View |
可以上下滚动的单行列表 | 可以滚动的行和列的表格 |
在Adapter中填入数据
可以简单的使用继承自AdapterView的View来绑定Adapter,来获取外部数据源的数据。
Andorid也提供了一些继承自Adapter的子类用于处理不同的数据形式来建立View,下面是3种比较常见的Adapter:
当数据源是一个数组的时候,可以使用这个Adapter,默认,ArrayAdapter在调用toString()后会为每个Item创建一个TextView。
举个例子,如果想在ListView中显示一个字符串数组,需要实例化一个ArrayAdapter,指定其Layout,每个String的名称,和String列表
ArrayAdapter adapter = new ArrayAdapter<String>(this,
android.R.layout.simple_list_item_1, myStringArray);
参数分别为:app Context,含义显示String的TextView的layout,String列表
第二步:在ListView上设置Adapter
ListView listView = (ListView) findViewById(R.id.listview);
listView.setAdapter(adapter);
如果需要定义String的输出格式,可以重载toString(),或者可以不用TextView,换做其他可以显示丰富内容的控件,比如ImageView。
可以方便的扩展ArrayAdapter
的getView()
来满足不同的显示样式。
如果数据源是来自于游标(Cursor)的时候,使用这个Adapter。使用这个Adapter的时候,需要指定Cursor的哪个行,哪个列插入Layout的View。
举例来说,有一个游标包含了People的数据,People包含name和number字段。
这时候,需要创建一个字符串数组用于指定哪些字段需要显示。一个整形数组,用于指定字段需要显示到哪个控件上
String[] fromColumns = {ContactsContract.Data.DISPLAY_NAME,
ContactsContract.CommonDataKinds.Phone.NUMBER};
int[] toViews = {R.id.display_name, R.id.phone_number};
当实例化SimpleCursorAdapter时候,传入这些参数
SimpleCursorAdapter adapter = new SimpleCursorAdapter(this,
R.layout.person_name_and_number, cursor, fromColumns, toViews, 0);
ListView listView = getListView();
listView.setAdapter(adapter);
SimpleCursorAdapter
会将fromColumns
的内容填入toViews
的View中。
如果,在程序的周期内,如果在Adapter内的数据被改变,那么必须调用notifyDataSetChanged(),这个函数将会通知与这个adapter相关的View并且刷新自己。
处理点击事件
可以通过实现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