第5讲 Android用户界面
计算机学院
本讲学习目标
了解各种用户界面的控件的使用方法
掌握各种界面布局的特点和使用方法
掌握选项菜单、子菜单和快捷菜单的使用方法
掌握按键事件和触摸事件的处理方法
用户界面基础
用户界面(User Interface,UI)是系统和用户
之间进行信息交换的媒介,实现信息的内部形
式与人类可以接受形式之间的转换
目前,流行图形用户界面(Graphical User
Interface,GUI),大部分程序采用图形方式与用户
进行交互的界面
未来的用户界面将更多的运用虚拟现实技术,使用户
能够摆脱键盘与鼠标的交互方式,而通过动作、语
言,甚至是脑电波来控制计算机
用户界面基础
设计手机用户界面应解决的问题
需要界面设计与程序逻辑完全分离,这样不仅有利于应
用的并行开发,而且在后期修改界面时,也不用再次修
改程序的逻辑代码
用户界面基础
设计手机用户界面应解决的问题
根据不同型号手机的屏幕解析度、尺寸和纵横比各不相
同,自动调整界面上部分控件的位置和尺寸,避免因为
屏幕信息的变化而出现显示错误
用户界面基础
设计手机用户界面应解决的问题
能够合理利用较小的屏幕显示空间,构造出符合人机交
互规律的用户界面,避免出现凌乱、拥挤的用户界面
用户界面基础
设计手机用户界面应解决的问题
Android已经解决了前两个问题,使用XML文件描述用
户界面;资源资源文件独立保存在资源文件夹中;对界
用户面描述非常灵活,允许不明确定义界面元素的位置
和尺寸,仅声明界面元素的相对位置和粗略尺寸
用户界面基础
Android用户界面框架
Android用户界面框架(
Android UI Framework)
采用MVC(Model-View-
Controller)模型
提供了处理用户输入的
控制器(Controller)
显示用户界面和图像的
视图(View),以及保
存数据和代码的模型(
Model)
这个模型即包括输入-存
储-输出三个部分
模型
控制器视图
键盘等输入
绘制界面 更新
用户界面基础
Android用户界面框架
MVC模型
MVC模型中的控制器能够接受并响应程序的外部动作,
如按键动作或触摸屏动作等
控制器使用队列处理外部动作,每个外部动作作为一个独
立的事件被加入队列中,然后Android用户界面框架按照“
先进先出”的规则从队列中获取事件,并将这个事件分配
给所对应的事件处理函数
用户界面基础
Android用户界面框架
Android用户界面框架(
Android UI Framework)
采用视图树(View Tree)
模型
用户界面基础
Android用户界面框架
Android用户界面框架中的
界面元素以一种树型结构组
织在一起,称为视图树
Android系统会依据视图树
的结构从上至下绘制每一个
界面元素。每个元素负责对
自身的绘制,如果元素包含
子元素,该元素会通知其下
所有子元素进行绘制
用户界面基础
Android用户界面框架
视图树
视图树由View和ViewGroup构成
View是界面的最基本的可视单元,存储了屏幕上特定矩
形区域内所显示内容的数据结构,并能够实现所占据区域
的界面绘制、焦点变化、用户输入和界面事件处理等功能
View也是一个重要的基类,所有在界面上的可见元素都
是View的子类
用户界面基础
Android用户界面框架
视图树
视图树由View和ViewGroup构成
ViewGroup是一种能够承载含多个View的显示单元
ViewGroup功能:一个是承载界面布局,另一个是承载具
有原子特性的重构模块
用户界面基础
Android用户界面框架
单线程用户界面
在单线程用户界面中,控制器从队列中获取事件和视图在
屏幕上绘制用户界面,使用的都是同一个线程
特点:处理函数具有顺序性,能够降低应用程序的复杂程
度,同时也能减低开发的难度
缺点:如果事件处理函数过于复杂,可能会导致用户界面
失去响应
界面控件
Android系统的界面控件分为系统控件和定制
控件
系统控件是Android系统提供给用户已经封装的界面控
件。提供在应用程序开发过程中常见功能控件。系统控
件更有利于帮助用户进行快速开发,同时能够使
Android系统中应用程序的界面保持一致性
界面控件
Android系统的界面控件分为定制控件和系统
控件
定制控件是用户独立开发的控件,或通过继承并修改系
统控件后所产生的新控件。能够为用户提供特殊的功能
或与众不同的显示需求方式
界面控件
Android系统的界面控件分为定制控件和系统
控件
常见的系统控件包括TextView、EditText、
Button、ImageButton、Checkbox、RadioButton
、Spinner、ListView和TabHost
这些系统控件通常包含在包中
import ;
import ;
界面控件
TextView和EditText
TextView是一种用于显示字符串的控件
EditText则是用来输入和编辑字符串的控件
EditText是一个具有编辑功能的TextView
界面控件
TextView和EditText
建立一个“TextViewDemo”的程序,包含TextView和
EditText两个控件
上方“用户名”部分使用的是TextView,下方的文字输入框
使用的是EditText
界面控件
TextView和EditText
TextViewDemo在XML文件中的代码
这部分代码是设计的App的界面
1. <TextView android:id="@+id/TextView01"
2. android:layout_width="wrap_content"
3. android:layout_height="wrap_content"
4. android:text="TextView01" >
5. </TextView>
6. <EditText android:id="@+id/EditText01"
7. android:layout_width="fill_parent"
8. android:layout_height="wrap_content"
9. android:text="EditText01" >
10. </EditText>
界面控件
TextView和EditText
第1行android:id属性声明了TextView的ID,这个ID主要
用于在代码中引用这个TextView对象
“@+id/TextView01”表示所设置的ID值
@表示后面的字符串是ID资源
加号(+)表示需要建立新资源名称,并添加到文
件中
斜杠后面的字符串(TextView01)表示新资源的名称
如果资源不是新添加的,或属于Android框架的ID资源,
则不需要使用加号(+),但必须添加Android包的命名空
间,例如android:id="@android:id/empty"
界面控件
TextView和EditText
第2行的android:layout_width属性用来设置TextView的
宽度,wrap_content表示TextView的宽度只要能够包含
所显示的字符串即可
第3行的android:layout_height属性用来设置TextView
的高度
第4行表示TextView所显示的字符串,在后面将通过代
码更改TextView的显示内容
第7行中“fill_parent”表示EditText的宽度将等于父控件
的宽度
每个控件的各个属性可以查docs
界面控件
TextView和EditText
文件中代码的修改
第1行代码的findViewById()函数能够通过ID引用界面上的任
何控件,只要该控件在XML文件中定义过ID即可
TextView textView表示声明一个TextView对象textView
(int id) 是的Public
Methods
Finds a view that was identified by the id attribute from
the XML that was processed in .
1. TextView textView = (TextView)findViewById();
2. EditText editText = (EditText)findViewById();
3. ("用户名:");
4. ("");
View findViewById
onCreate(Bundle)
界面控件
TextView和EditText
文件中代码的修改
第3行代码的setText()函数用来设置TextView所显示的内
容
setText()是TextView的Public Methods
1. TextView textView = (TextView)findViewById();
2. EditText editText = (EditText)findViewById();
3. ("用户名:");
4. ("");
界面控件
Button和ImageButton
Button是一种按钮控件,用户能够在该控件上点击,并
后引发相应的事件处理函数
ImageButton用以实现能够显示图像功能的控件按钮
界面控件
Button和ImageButton
建立一个“ButtonDemo”的程序,包含Button和
ImageButton两个按钮,上方是“Button按钮”,下方是
一个ImageButton控件
界面控件
Button和ImageButton
ButtonDemo在XML文件中的代码
定义Button控件的高度、宽度和内容
定义ImageButton控件的高度和宽度,但是没定义显示的
图像,在后面的代码中进行定义
1. <Button android:id="@+id/Button01"
2. android:layout_width="wrap_content"
3. android:layout_height="wrap_content"
4. android:text="Button01" >
5. </Button>
6. <ImageButton android:id="@+id/ImageButton01"
7. android:layout_width="wrap_content"
8. android:layout_height="wrap_content">
9. </ImageButton>
界面控件
Button和ImageButton
引入资源
将文件拷贝到/res/drawable文件夹
下
菜单命令Project--Build All
文件内容也得到了更新
界面控件
Button和ImageButton
更改Button内容
引入
第1行代码用于引用在XML文件中定义的Button控件
第3行代码将Button的显示内容更改为“Button按钮”
1. Button button = (Button)findViewById();
2. ImageButton imageButton = (ImageButton)findViewById();
3. ("Button按钮");
4. ();
界面控件
Button和ImageButton
更改ImageButton内容
引入
第2行代码用于引用在XML文件中定义的ImageButton控件
第4行代码利用setImageResource()函数,将新加入的png
文件传递给ImageButton
1. Button button = (Button)findViewById();
2. ImageButton imageButton = (ImageButton)findViewById();
3. ("Button按钮");
4. ();
界面控件
Button和ImageButton
按钮响应点击事件:添加点击事件的监听器
可以参考docs中的例子和说明
下面详细解释
界面控件
Button和ImageButton
手机界面上的每一个界面控件,都可以接收点击事件,触
摸事件等界面操作事件.
每一类事件,都有相应的事件的监听器(见docs主要接口)
public static interface
public static interface
public static interface
public static interface
接口:是预先已经定义好的函数.
界面控件是继承于View(见docs),同样继承了这些public
接口
界面控件
Button和ImageButton
()用于点击事件
()是View定义的点击事件的监听器
接口,并在接口中仅定义了onClick()函数
abstract void ( v)
Called when a view has been clicked.
onClick View
界面控件
Button和ImageButton
按钮响应点击事件:添加点击事件的监听器
可以在onClick(View v) 函数中添加处理代码
1. buttonListener = new (){
2. @Override
3. public void onClick(View v) {
4.
5. }
6. };
界面控件
Button和ImageButton
界面控件要注册事件的监听器
View用于注册事件的监听器的函数
void ( l) Register a callback
to be invoked when this view is clicked.
void ( l) Register a callback to
be invoked when a key is pressed in this view.
void ( l) Register
a callback to be invoked when this view is clicked and held.
void ( l) Register a
callback to be invoked when a touch event is sent to this view.
setOnClickListener
setOnKeyListener
setOnLongClickListener
setOnTouchListener
界面控件
Button和ImageButton
按钮响应点击事件:添加点击事件的监听器
注册完成后,当button上有点击事件时,将执行事件的监
听器中的onClick(View v) 函数
1. Button button = (Button)findViewById();
2. ("Button按钮");
3. (buttonListener);
界面控件
Button和ImageButton
添加点击事件的监听器和注册工作也可以一次完成
public class MyActivity extends Activity
{
protected void onCreate(Bundle icicle)
{
(icicle);
setContentView(_layout_id);
final Button button = (Button) findViewById(_id);
(new ()
{
public void onClick(View v) { // Perform action on click }
}
);
}
}
界面控件
Button和ImageButton
按钮响应点击事件:添加点击事件的监听器
第2行代码中button对象通过调用setOnClickListener()函
数,注册一个点击(Click)事件的监听器
()
第4行代码是点击事件的回调函数
第6行代码将TextView的显示内容更改为“Button按钮”
1. final TextView textView = (TextView)findViewById();
2. (new () {
3. @Override
4. public void onClick(View v) {
5. // TODO Auto-generated method stub
6. ("Button按钮");
7. }
8. });
界面控件
Button和ImageButton
按钮响应点击事件:添加点击事件的监听器
第1行代码中imageButton对象通过调用
setOnClickListener()函数,注册一个点击(Click)事件
的监听器()
第2行代码是点击事件的回调函数
第3行代码将TextView的显示内容更改为“ImageButton按
钮”
1. (new () {
2. public void onClick(View view) {
3. ("ImageButton按钮");
4. }
5. });
界面控件
Button和ImageButton
当Button从Android界面框架中接收到事件后,首先检查
这个事件是否是点击事件,如果是点击事件,同时Button
又注册了监听器,则会调用该监听器中的onClick()函数
每个View仅可以注册一个点击事件的监听器,如果使用
setOnClickListener()函数注册第二个点击事件的监听器,
之前注册的监听器将被自动注销
界面控件
Button和ImageButton
多个按钮注册到同一个点击事件的监听器上,代码
如下
界面控件
Button和ImageButton
第1行至第12行代码定义了一个名为buttonListener的点击
事件监听器
第13行代码将该监听器注册到Button上
第14行代码将该监听器注册到ImageButton上
1. buttonListener = new (){
2. @Override
3. public void onClick(View v) {
4. switch(()){
5. case :
6. ("Button按钮");
7. return;
8. case :
9. ("ImageButton按钮");
10. return;
11. }
12. }};
13. (buttonListener);
14. (buttonListener);
界面控件
CheckBox
CheckBox是一个同时可以选择多个选项的控件
又叫复选框
界面控件
RadioButton
RadioButton是只可以选择一个选项的控件
又叫单选框
RadioGroup是RadioButton的承载体,程序运行时不可
见,应用程序中可能包含一个或多个RadioGroup
一个RadioGroup包含多个RadioButton,在每个
RadioGroup中,用户仅能够选择其中一个RadioButton
界面控件
CheckboxRadiobuttonDemo例子
建立一个“CheckboxRadiobuttonDemo”程序,包含五个
控件,从上至下分别是TextView01、CheckBox01、
CheckBox02、RadioButton01、RadioButton02
当选择RadioButton01, RadioButton02则无法选择
界面控件
CheckBox和RadioButton
CheckboxRadiobuttonDemo在XML文件中的代码
1. <TextView android:id="@+id/TextView01“
2. android:layout_width="fill_parent"
3. android:layout_height="wrap_content"
4. android:text="@string/hello"/>
5. <CheckBox android:id="@+id/CheckBox01"
6. android:layout_width="wrap_content"
7. android:layout_height="wrap_content"
8. android:text="CheckBox01" >
9. </CheckBox>
10. <CheckBox android:id="@+id/CheckBox02"
11. android:layout_width="wrap_content"
12. android:layout_height="wrap_content"
13. android:text="CheckBox02" >
14. </CheckBox>
界面控件
CheckBox和RadioButton
第15行<RadioGroup>标签声明了一个RadioGroup
在第18行和第23行分别声明了两个RadioButton,这两个
RadioButton是RadioGroup的子元素
15. <RadioGroup android:id="@+id/RadioGroup01"
16. android:layout_width="wrap_content"
17. android:layout_height="wrap_content">
18. <RadioButton android:id="@+id/RadioButton01"
19. android:layout_width="wrap_content"
20. android:layout_height="wrap_content“
21. android:text="RadioButton01" >
22. </RadioButton>
23. <RadioButton android:id="@+id/RadioButton02"
24. android:layout_width="wrap_content"
25. android:layout_height="wrap_content“
26. android:text="RadioButton02" >
27. </RadioButton>
28. </RadioGroup>
界面控件
CheckBox和RadioButton
引用CheckBox和RadioButton的方法参考下面的代码
CheckBox设置点击事件监听器的简要代码
与Button设置点击事件监听器中介绍的方法相似,唯一不
同在于将换成了
1. CheckBox checkBox1= (CheckBox)findViewById();
2. RadioButton radioButton1 =(RadioButton)findViewById();
1. checkboxListener = new (){
2. @Override
3. public void onClick(View v) {
4. //过程代码
5. }};
6. (checkboxListener);
7. (checkboxListener);
界面控件
CheckBox和RadioButton
RadioButton设置点击事件监听器的方法
1. radioButtonListener = new (){
2. @Override
3. public void onClick(View v) {
4. //过程代码
5. }};
6. (radioButtonListener);
7. (radioButtonListener);
界面控件
Spinner
Spinner是一种能够从
多个选项中选一选项的
控件,类似于桌面程序
的组合框(ComboBox
),但没有组合框的下
拉菜单,而是使用浮动
菜单为用户提供选择
建立一个程序
“SpinnerDemo”包含3个
子项Spinner控件
界面控件
Spinner
SpinnerDemo在XML文件中的代码
第5行使用<Spinner>标签声明了一个Spinner控件
第6行代码中指定了该控件的宽度为300dip
1. <TextView android:id="@+id/TextView01"
2. android:layout_width="fill_parent"
3. android:layout_height="wrap_content"
4. android:text="@string/hello"/>
5. <Spinner android:id="@+id/Spinner01"
6. android:layout_width="300dip"
7. android:layout_height="wrap_content">
8. </Spinner>
界面控件
Spinner
在文件中,定义一个ArrayAdapter适
配器,在ArrayAdapter中添加需要在Spinner中可以选
择的内容,需要在代码中引入
和
1. Spinner spinner = (Spinner) findViewById();
2. List<String> list = new ArrayList<String>();
3. list .add("Spinner子项1");
4. list .add("Spinner子项2");
5. list .add("Spinner子项3");
6. ArrayAdapter<String> adapter = new ArrayAdapter<String>(this,
_spinner_item, list );
7. (_spinner_dropdown_item);
8. (adapter);
界面控件
Spinner
第2行代码建立了一个字符串数组列表(ArrayList),这
种数组列表可以根据需要进行增减
(这是Java的知识)
<String>表示数组列表中保存的是字符串类型的数据
在代码的第3、4、5行中,使用add()函数分别向数组列表
中添加3个字符串
界面控件
Spinner
第6行代码建立了一个ArrayAdapter的数组适配器,数组
适配器能够将界面控件和底层数据绑定在一起,第二个参
数_spinner_item浮动菜单,第三个
参数list说明适配器的数据源为数组列表
第7行代码设定了Spinner的浮动菜单的显示方式,其中,
_spinner_dropdown_item是
Android系统内置的一种浮动菜单
第8行代码实现绑定过程,适配器绑定界面控件Spinner和
底层数据list,所有ArrayList中的数据,将显示在Spinner的
浮动菜单中,如果底层数据更改了,用户界面也相应修改
显示内容
界面控件
Spinner
显示结果如图
界面控件
ListView(不讲)
ListView是一种用于垂直显示的列表控件,如果显示内
容过多,则会出现垂直滚动条
ListView能够通过适配器将数据和自身绑定,在有限的
屏幕上提供大量内容供用户选择,所以是经常使用的用
户界面控件
ListView支持点击事件处理,用户可以用少量的代码实
现复杂的选择功能
界面控件
ListView
建立一个“ListViewDemo”程序,包含四个控件,从上至
下分别为TextView01、ListView01、 ListView02和
ListView03
界面控件
ListView
ListViewDemo在XML文件中的代码
1. <TextView android:id="@+id/TextView01"
2. android:layout_width="fill_parent"
3. android:layout_height="wrap_content"
4. android:text="@string/hello" />
5. <ListView android:id="@+id/ListView01"
6. android:layout_width="wrap_content"
7. android:layout_height="wrap_content">
8. </ListView>
界面控件
ListView
在文件中,首先需要为ListView创
建适配器,并添加ListView中所显示的内容
第2行代码通过ID引用了XML文件中声明的ListView
第7行代码声明了适配器ArrayAdapter,第三个参数list说
明适配器的数据源为数组列表
第8行代码将ListView和适配器绑定
1. final TextView textView = (TextView)findViewById();
2. ListView listView = (ListView)findViewById();
3. List<String> list = new ArrayList<String>();
4. ("ListView子项1");
5. ("ListView子项2");
6. ("ListView子项3");
7. ArrayAdapter<String> adapter = new ArrayAdapter<String>(this,
_list_item_1, list );
8. (adapter);
界面控件
ListView
声明一个ListView子项的点击事件监听器,用以确定用
户在ListView中,选择的是哪一个子项
1. listViewListener = new
(){
2. @Override
3. public void onItemClick(AdapterView<?> arg0, View arg1, int arg2, long arg3) {
4. String msg =””;
5. (msg);
6. }};
7. (listViewListener);
界面控件
ListView
第1行的是ListView子
项的点击事件监听器,同样是一个接口,需要实现
onItemClick()函数。在ListView子项被选择后,
onItemClick()函数将被调用
第3行的onItemClick()函数中一共有四个参数,参数0表示
适配器控件,就是ListView;参数1表示适配器内部的控
件,是ListView中的子项;参数2表示适配器内部的控件
,也就是子项的位置;参数3表示子项的行号
第4行和第5行代码用于显示信息,选择子项确定后,在
TextView中显示子项父控件的信息、子控件信息、位置信
息和ID信息
界面控件
TabHost
Tab标签页是界面设计时经常使用的界面控件,可以实
现多个分页之间的快速切换,每个分页可以显示不同的
内容
界面控件
TabHost
如图是Android系统内置
的Tab标签页,
点击“呼出/接听键”后出现,
用于电话呼出和查看拨号记录、
联系人
界面控件
TabHost
Tab标签页的使用
设计所有的分页的界面布局
分页设计完成后,使用代码建立Tab标签页,给每个分页
添加标识和标题
确定每个分页所显示的界面布局
每个分页建立一个XML文件,用来编辑和保存分页的界
面布局
界面控件
TabHost
建立一个“TabDemo”程序,包含三个XML文件,分别为
、和,这3个文件分别使用线
性布局、相对布局和绝对布局,布局的ID分别定义为
layout01、layout02和layout03
界面控件
TabHost(演示)
文件代码
文件代码
文件代码
1. <?xml version="" encoding="utf-8"?>
2. <LinearLayout android:id = "@+id/layout01"
3. ……
4. ……
5. </LinearLayout>
1. <?xml version="" encoding="utf-8"?>
2. <AbsoluteLayout android:id="@+id/layout02"
3. ……
4. ……
5. </AbsoluteLayout>
1. <?xml version="" encoding="utf-8"?>
2. <RelativeLayout android:id="@+id/layout03"
3. ……
4. ……
5. </RelativeLayout>
界面控件
TabHost
在文件中键入下面的代码,创建Tab标
签页,并建立子页与界面布局直接的关联关系
要注意,这时Activity改变为TabActivity
1. package ;
2.
3. import ;
4. import ;
5. import ;
6. import ;
7.
8. public class TabDemo extends TabActivity {
9. @Override
界面控件
TabHost
10. public void onCreate(Bundle savedInstanceState) {
11. (savedInstanceState);
12. TabHost tabHost = getTabHost();
13. (this).inflate(,
(),true);
14. (this).inflate(,
(),true);
15. (this).inflate(,
(),true);
16. (("TAB1")
17. .setIndicator("线性布局").setContent());
18. (("TAB2")
19. .setIndicator("绝对布局").setContent());
20. (("TAB3")
21. .setIndicator("相对布局").setContent());
22. }
23. }
界面控件
TabHost(代码解释)
第8行代码的声明TabDemo类继承与TabActivity,与以往
继承Activity不同,TabActivity支持内嵌多个Activity或
View
1. package ;
2.
3. import ;
4. import ;
5. import ;
6. import ;
7.
8. public class TabDemo extends TabActivity {
9. @Override
界面控件
TabHost (代码解释)
第12行代码通过getTabHost()函数获得了Tab标签页的容
器,用以承载可以点击的Tab标签和分页的界面布局。
10. public void onCreate(Bundle savedInstanceState) {
11. (savedInstanceState);
12. TabHost tabHost = getTabHost();
13. (this).inflate(,
(),true);
14. (this).inflate(,
(),true);
15. (this).inflate(,
(),true);
16. (("TAB1")
17. .setIndicator("线性布局").setContent());
18. (("TAB2")
19. .setIndicator("绝对布局").setContent());
20. (("TAB3")
21. .setIndicator("相对布局").setContent());
22. }
23. }
界面控件
TabHost (代码解释)
第13、 14、15行代码通过LayoutInflater将、
tab2.xml、 tab3.xml文件中的布局转换为Tab标签页可
以使用的View对象
10. public void onCreate(Bundle savedInstanceState) {
11. (savedInstanceState);
12. TabHost tabHost = getTabHost();
13. (this).inflate(,
(),true);
14. (this).inflate(,
(),true);
15. (this).inflate(,
(),true);
16. (("TAB1")
17. .setIndicator("线性布局").setContent());
18. (("TAB2")
19. .setIndicator("绝对布局").setContent());
20. (("TAB3")
21. .setIndicator("相对布局").setContent());
22. }
23. }
界面控件
TabHost (代码解释)
第16(18,20)行代码使用addTab()函数添加了第1个分页,
("TAB1")表明在第12行代码中建立
的tabHost上,添加一个标识为TAB1的Tab分页
10. public void onCreate(Bundle savedInstanceState) {
11. (savedInstanceState);
12. TabHost tabHost = getTabHost();
13. (this).inflate(,
(),true);
14. (this).inflate(,
(),true);
15. (this).inflate(,
(),true);
16. (("TAB1")
17. .setIndicator("线性布局").setContent());
18. (("TAB2")
19. .setIndicator("绝对布局").setContent());
20. (("TAB3")
21. .setIndicator("相对布局").setContent());
22. }
23. }
界面控件
TabHost (代码解释)
第17(19,21)行代码使用setIndicator()函数设定分页显示的
标题,使用setContent()函数设定分页所关联的界面布局
10. public void onCreate(Bundle savedInstanceState) {
11. (savedInstanceState);
12. TabHost tabHost = getTabHost();
13. (this).inflate(,
(),true);
14. (this).inflate(,
(),true);
15. (this).inflate(,
(),true);
16. (("TAB1")
17. .setIndicator("线性布局").setContent());
18. (("TAB2")
19. .setIndicator("绝对布局").setContent());
20. (("TAB3")
21. .setIndicator("相对布局").setContent());
22. }
23. }
界面控件
TabHost
TabDemo示例的运行结果如图
界面控件
TabHost
在使用Tab标签页时,可以将不同分页的界面布局保存
在不同的XML文件中,也可以将所有分页的布局保存在
同一个XML文件中
第一种方法有利于在Eclipse开发环境中进行可视化设计
,并且不同分页的界面布局在不同的文件中更加易于管理
第二种方法则可以产生较少的XML文件,同时编码时的代
码也会更加简洁
界面布局
界面布局
界面布局(Layout)是用户界面结构的描述,定义了界
面中所有的元素、结构和相互关系
声明Android程序的界面布局有两种方法
使用XML文件描述界面布局
在程序运行时动态添加或修改界面布局
用户既可以独立使用任何一种声明界面布局的方式,也
可以同时使用两种方式
界面布局
界面布局
使用XML文件声明界面布局的特点
将程序的表现层和控制层分离
在后期修改用户界面时,无需更改程序的源代码
用户还能够通过可视化工具直接看到所设计的用户界面,
有利于加快界面设计的过程,并且为界面设计与开发带来
极大的便利性
界面布局
线性布局
线性布局(LinearLayout)是一种重要的界面布局中,
也是经常使用到的一种界面布局
在线性布局中,所有的子元素都按照垂直或水平的顺序
在界面上排列
如果垂直排列,则每行仅包含一个界面元素
如果水平排列,则每列仅包含一个界面元素
界面布局
线性布局
创建Android工程
工程名称是LinearLayout
包名称是
Activity名称为LinearLayout
为了能够完整体验创建线性布局的过程,首先删除
Eclipse自动建立的/res/layout/文件,然后建立
用于显示垂直排列线性布局的XML文件
界面布局
线性布局
右击/res/layout文件夹
选择New → File打开新
文件建立向导
文件名为
保存位置为
LinearLayout/res/layout
界面布局
线性布局
双击新建立的/res/layout/文件,
Eclipse将打开界面布局的可视化编辑器
界面布局
线性布局
可视化编辑器顶部是资源配置清单,可以根据手机的配
置不同选择不同的资源,主要用来实现应用软件的本地
化
下部左侧是界面布局和界面控件,用户可以将需要的布
局和控件拖拽到右面的可视化界面中,并修改布局和控
件的属性
右侧是可视化的用户界面,能够实时的呈现用户界面,
但对无法正确显示中文。左下角的“Layout”和
“”能够在可视化编辑器和XML文件编
辑器之间切换
界面布局
线性布局
在Eclipse的Outline中,双击LinearLayout,打开线性布
局的属性编辑器
线性布局的排列方法主要由Orientation属性进行控制,
vertical表示垂直排列,horizontal表示水平排列
选择Orientation的值为vertical,表示该线性布局为垂直
排列
界面布局
线性布局
缺省情况下,Layout height的值为wrap_content,表示
线性布局高度等于所有子控件的高度总和,也就是线性
布局的高度会刚好将所有子控件包含其中
将Layout width属性的值改为fill_parent,表示线性布局
宽度等于父控件的宽度,就是将线性布局在横向上占据
父控件的所有空间
界面布局
线性布局
打开XML文件编辑器,文件的代码如
下
第2行代码是声明XML文件的根元素为线性布局
第4、5、6行代码是在属性编辑器中修改过的宽度、高度
和排列方式的属性
用户在可视化编辑器和属性编辑器中的任何修改,都会同
步的反映在XML文件中;反之,也是如此
1. <?xml version="" encoding="utf-8"?>
2. <LinearLayout
3. xmlns:android="
4. android:layout_width="fill_parent"
5. android:layout_height="wrap_content"
6. android:orientation="vertical">
7. </LinearLayout>
界面布局
线性布局
将四个界面控件TextView、EditText、Button、Button
先后拖拽到可视化编辑器中
所有控件都自动获取控件名称,并把该名称显示在控件上
,如TextView01、EditText01、Button01和Button02
界面布局
线性布局
修改界面控件的属性
所有界面控件都有一个共同的属性ID
ID是一个字符串,编译时被转换为整数,可以用来在代码
中引用界面元素,一般仅在代码中需要动态修改的界面元
素时才为界面元素设置ID,反之则不需要设置ID
编号 类型 属性 值
Id @+id/label1 TextVie
w Text 用户名:
Id @+id/entry
Layout width fill_parent
2 EditTex
t
Text [null]
Id @+id/ok3 Button
Text 确认
Id @+id/cancel4 Button
Text 取消
界面布局
线性布局
打开XML文件编辑器查看文件代码,
发现在属性编辑器内填入的文字已经正常写入到XML文
件中,例如第11、20、25行代码
1. <?xml version="" encoding="utf-8"?>
2. <LinearLayout
3. xmlns:android="
4. android:layout_width="fill_parent"
5. android:layout_height="wrap_content"
6. android:orientation="vertical">
7.
8. <TextView android:id="@+id/label"
9. android:layout_width="wrap_content"
10. android:layout_height="wrap_content"
11. android:text="用户名:" >
界面布局
线性布局
12. </TextView>
13. <EditText android:id="@+id/entry"
14. android:layout_height="wrap_content"
15. android:layout_width="fill_parent">
16. </EditText>
17. <Button android:id="@+id/ok"
18. android:layout_width="wrap_content"
19. android:layout_height="wrap_content"
20. android:text="确认">
21. </Button>
22. <Button android:id="@+id/cancel"
23. android:layout_width="wrap_content"
24. android:layout_height="wrap_content"
25. android:text="取消" >
26. </Button>
27. </LinearLayout>
界面布局
线性布局
将文件中的
setContentView(),更改为
setContentView(_vertical)。运行后的结
果如图
界面布局
线性布局
建立横向线性布局与纵向线性布局相似,只需注意以下
几点
建立main_ 文件
线性布局的Orientation属性的值设置为horizontal
将EditText的Layout width 属性的值设置为
wrap_content
将文件中的
setContentView(_vertical) 修改为
setContentView(_ horizontal)
界面布局
框架布局
框架布局(FrameLayout)是最简单的界面布局,是用
来存放一个元素的空白空间,且子元素的位置是不能够
指定的,只能够放置在空白空间的左上角
如果有多个子元素,后放置的子元素将遮挡先放置的子
元素
界面布局
框架布局
Android SDK中的层级观察器(Hierarchy Viewer)可
以分析界面布局
层级观察器能够对用户界面进行分析和调试,并以图形
化的方式展示树形结构的界面布局
还提供了一个精确的像素级观察器(Pixel Perfect View
),以栅格的方式详细观察放大后的界面界面
界面布局
框架布局
在层级观察器中获得示例界面布局的树形结构图
界面布局
框架布局
示意图
界面布局
框架布局
结合界面布局的树形结构图和示意图,分析不同界面布
局和界面控件的区域边界
用户界面的根节点(#0@43599ee0)是线性布局,其边
界是整个界面,也就是示意图的最外层的实心线
根节点右侧的子节点(#0@43599a730)是框架布局,
仅有一个节点元素(#0@4359ad18),这个子元素是
TextView控件,用来显示Android应用程序名称,其边界
是示意图中的区域1。因此框架布局元素#0@43599a730
的边界是同区域1的高度相同,宽带充满整个根节点的区
域。这两个界面元素是系统自动生成的,一般情况下用户
不能够修改和编辑
界面布局
框架布局
根节点左侧的子节点(#1@4359b858)也是框架布局,
边界是区域2到区域7的全部空间
界面布局
框架布局
子节点(#1@4359b858)下仅有一个子节点(
#0@4359bd60)元素是线性布局,因为线性布局的
Layout width属性设置为fill_parent,Layout height属性设
置为wrap_content,因此该线性布局的宽度就是其父节点
#1@4359b858的宽带,高度等于所有子节点元素的高度
之和
线性布局#0@4359bd60的四个子节点元素#0@4359bfa8
、#1@4359c5f8、#2@4359d5d8和#3@4359de18的边
界,分别是界面布局示意图中的区域2、区域3、区域4和
区域5
界面布局
表格布局
表格布局(TableLayout)也是一种常用的界面布局,
它将屏幕划分网格,通过指定行和列可以将界面元素添
加的网格中
网格的边界对用户是不可见的
表格布局还支持嵌套,可以将另一个表格布局放置在前一
个表格布局的网格中,也可以在表格布局中添加其他界面
布局,例如线性布局、相对布局等等
表格布局
表格布局示意图 表格布局效果图
界面布局
界面布局
表格布局
建立表格布局要注意以下几点
向界面中添加一个表格布局,无需修改布局的属性值。其
中,Id属性为TableLayout01,Layout width和Layout
height属性都为wrap_content
向TableLayout01中添加两个TableRow。TableRow代表
一个单独的行,每行被划分为几个小的单元,单元中可以
添加一个界面控件。其中,Id属性分别为TableRow01和
TableRow02,Layout width和Layout height属性都为
wrap_content
界面布局
表格布局
通过Outline,向TableRow01中添加TextView和EditText
界面布局
编号 类型 属性 值
Id @+id/labe
l
Text 用户名:
Gravity right
Padding 3dip
1 TextVie
w
Layout
width
160dip
Id @+id/entr
y
Text [null]
Padding 3dip
2 EditTex
t
Layout
width
160dip
Id @+id/ok
Text 确认
3 Button
Padding 3dip
Id @+id/canc
el
Text 取消
4 Button
Padding 3dip
表格布局
通过Outline,向
TableRow02中添加
两个Button
参考下表设置
TableRow中四个界面
控件的属性值
界面布局
表格布局
文件的完整代码如下
1. <?xml version="" encoding="utf-8"?>
2.
3. <TableLayout android:id="@+id/TableLayout01"
4. android:layout_width="fill_parent"
5. android:layout_height="fill_parent"
6. xmlns:android="
7. <TableRow android:id="@+id/TableRow01"
8. android:layout_width="wrap_content"
9. android:layout_height="wrap_content">
10. <TextView android:id="@+id/label"
11. android:layout_height="wrap_content"
12. android:layout_width="160dip"
13. android:gravity="right"
14. android:text="用户名:"
15. android:padding="3dip" >
16. </TextView>
界面布局
表格布局
17. <EditText android:id="@+id/entry"
18. android:layout_height="wrap_content"
19. android:layout_width="160dip“
20. android:padding="3dip" >
21. </EditText>
22. </TableRow>
23. <TableRow android:id="@+id/TableRow02"
24. android:layout_width="wrap_content"
25. android:layout_height="wrap_content">
26. <Button android:id="@+id/ok"
27. android:layout_height="wrap_content"
28. android:padding="3dip"
29. android:text="确认">
30. </Button>
界面布局
表格布局
第3行代码使用了<TableLayout>标签声明表格布局
第7行和第23行代码声明了两个TableRow元素
第12行设定宽度属性android:layout_width:160dip
第13行设定属性android:gravity,指定文字为右对齐
第15行使用属性android:padding,声明TextView元素与
其他元素的间隔距离为3dip
31. <Button android:id="@+id/Button02"
32. android:layout_width="wrap_content"
33. android:layout_height="wrap_content"
34. android:padding="3dip"
35. android:text="取消">
36. </Button>
37. </TableRow>
38. </TableLayout>
界面布局
相对布局
相对布局(RelativeLayout)是一种非常灵活的布局方
式,能够通过指定界面元素与其他元素的相对位置关系
,确定界面中所有元素的布局位置
特点:能够最大程度保证在各种屏幕类型的手机上正确
显示界面布局
界面布局
相对布局
相对布局示例说明
添加TextView控件(“用户名”),相对布局会将TextView
控件放置在屏幕的最上方
然后添加EditText控件(输入框),并声明该控件的位置
在TextView控件的下方,相对布局会根据TextView的位
置确定EditText控件的位置
之后添加第一个Button控件(“取消”按钮),声明在
EditText控件的下方,且在父控件的最右边
最后,添加第二个Button控件(“确认”按钮),声明该控
件在第一个Button控件的左方,且与第一个Button控件处
于相同的水平位置
界面布局
相对布局
相对布局在文件的完整代码如下
1. <?xml version="" encoding="utf-8"?>
2.
3. <RelativeLayout android:id="@+id/RelativeLayout01"
4. android:layout_width="fill_parent"
5. android:layout_height="fill_parent"
6. xmlns:android="
7. <TextView android:id="@+id/label"
8. android:layout_height="wrap_content"
9. android:layout_width="fill_parent"
10. android:text="用户名:">
11. </TextView>
12. <EditText android:id="@+id/entry"
13. android:layout_height="wrap_content"
14. android:layout_width="fill_parent"
15. android:layout_below="@id/label">
16. </EditText>
界面布局
相对布局
17. <Button android:id="@+id/cancel"
18. android:layout_height="wrap_content"
19. android:layout_width="wrap_content"
20. android:layout_alignParentRight="true"
21. android:layout_marginLeft="10dip"
22. android:layout_below="@id/entry"
23. android:text="取消" >
24. </Button>
25. <Button android:id="@+id/ok"
26. android:layout_height="wrap_content"
27. android:layout_width="wrap_content"
28. android:layout_toLeftOf="@id/cancel"
29. android:layout_alignTop="@id/cancel“
30. android:text=“确认”>、
31. </Button>
32. </RelativeLayout>
界面布局
相对布局
第3行使用了<RelativeLayout>标签声明一个相对布局
第15行使用位置属性android:layout_below,确定
EditText控件在ID为label的元素下方
第20行使用属性android:layout_alignParentRight,声明
该元素在其父元素的右边边界对齐
第21行设定属性android:layout_marginLeft,左移10dip
第22行声明该元素在ID为entry的元素下方
第28行声明使用属性android:layout_toLeftOf,声明该元
素在ID为cancel元素的左边
第29行使用属性android:layout_alignTop,声明该元素与
ID为cancel的元素在相同的水平位置
界面布局
绝对布局
绝对布局(AbsoluteLayout)能通过指定界面元素的坐
标位置,来确定用户界面的整体布局
绝对布局是一种不推荐使用的界面布局,因为通过X轴
和Y轴确定界面元素位置后,Android系统不能够根据不
同屏幕对界面元素的位置进行调整,降低了界面布局对
不同类型和尺寸屏幕的适应能力
界面布局
绝对布局
每一个界面控件都必须指定坐标(X,Y),例如“确认”
按钮的坐标是(40,120),“取消”按钮的坐标是(120
,120)。坐标原点(0,0)在屏幕的左上角
界面布局
绝对布局
绝对布局示例在文件的完整代码
1. <?xml version="" encoding="utf-8"?>
2.
3. <AbsoluteLayout android:id="@+id/AbsoluteLayout01"
4. android:layout_width="fill_parent"
5. android:layout_height="fill_parent"
6. xmlns:android="
7. <TextView android:id="@+id/label"
8. android:layout_x="40dip"
9. android:layout_y="40dip"
10. android:layout_height="wrap_content"
11. android:layout_width="wrap_content"
12. android:text="用户名:">
13. </TextView>
14. <EditText android:id="@+id/entry"
15. android:layout_x="40dip"
16. android:layout_y="60dip"
界面布局
绝对布局
17. android:layout_height="wrap_content"
18. android:layout_width="150dip">
19. </EditText>
20. <Button android:id="@+id/ok"
21. android:layout_width="70dip"
22. android:layout_height="wrap_content"
23. android:layout_x="40dip"
24. android:layout_y="120dip"
25. android:text="确认">
26. </Button>
27. <Button android:id="@+id/cancel"
28. android:layout_width="70dip"
29. android:layout_height="wrap_content"
30. android:layout_x="120dip"
31. android:layout_y="120dip"
32. android:text="取消">
33. </Button>
34. </AbsoluteLayout>
菜单
菜单是应用程序中非常重要的组成部分,能够
在不占用界面空间的前提下,为应用程序提供
了统一的功能和设置界面,并为程序开发人员
提供了易于使用的编程接口
菜单
Android系统支持三种菜单
选项菜单(Option Menu)
子菜单(Submenu)
快捷菜单(Context Menu)
菜单
选项菜单
选项菜单是一种经常被使用的Android系统菜单
打开方式:通过“菜单键”(MENU key)打开
选项菜单分类
图标菜单(Icon Menu)
扩展菜单(Expanded Menu)
菜单
选项菜单
图标菜单能够同时显示文字和图标的菜单,最多支持6
个子项
图标菜单不支持单选框和复选框
菜单
选项菜单
扩展菜单是在图标菜单
子项多余6个时才出现
,通过点击图标菜单最
后的子项“More”才能打
开
扩展菜单是垂直的列表
型菜单
不能够显示图标
支持单选框和复选框
菜单
选项菜单
重载Activity的onCreateOptionMenu()函数,才能够在
Android应用程序中使用选项菜单
初次使用选项菜单时,会调用onCreateOptionMenu()
函数,用来初始化菜单子项的相关内容
设置菜单子项自身的子项的ID和组ID
菜单子项显示的文字和图片等
onCreateOptionMenu()的具体用法请参考docs
菜单
选项菜单
第1行和第2行代码将菜单子项ID定义成静态常量,并使用
静态常量(整数类型,值为1)定义第一个
菜单子项,以后的菜单子项仅需在增加相应
的数值即可
第7行代码是onCreateOptionsMenu()函数返回值,函数
的返回值类型为布尔型
返回true将显示在函数中设置的菜单,否则不能够显示菜单
1. final static int MENU_DOWNLOAD = ;
2. final static int MENU_UPLOAD = +1;
3. @Override
4. public boolean onCreateOptionsMenu(Menu menu){
5. (0,MENU_DOWNLOAD,0,"下载设置");
6. (0,MENU_UPLOAD,1,"上传设置");
7. return true;
8. }
菜单
选项菜单
第4行代码Menu对象作为一个参数被传递到函数内部,因
此在onCreateOptionsMenu()函数中,用户可以使用
Menu对象的add()函数添加菜单子项
add()函数的语法
第1个参数groupId是组ID,用以批量的对菜单子项进行处理
和排序
第2关参数itemId是子项ID,是每一个菜单子项的唯一标识,
通过子项ID使应用程序能够定位到用户所选择的菜单子项
第3个参数order是定义菜单子项在选项菜单中的排列顺序
第4个参数title是菜单子项所显示的标题
MenuItem (int groupId, int itemId, int order, CharSequence title)
菜单
选项菜单
添加菜单子项的图标和快捷键:使用setIcon()函数和
setShortcut()函数
MENU_DOWNLOAD菜单设置图标和快捷键的代码
第2行代码中使用了新的图像资源,用户将需要使用的图
像文件拷贝到/res/drawable目录下
setShortcut()函数第一个参数是为数字键盘设定的快捷键
第二个参数是为全键盘设定的快捷键,且不区分字母的大
小写
1. (0,MENU_DOWNLOAD,0,"下载设置")
2. .setIcon()
3. .setShortcut(’,’d’);
菜单
选项菜单
重载onPrepareOptionsMenu()函数,能够动态的添加
、删除菜单子项,或修改菜单的标题、图标和可见性等
内容
onPrepareOptionsMenu()函数的返回值的含义与
onCreateOptionsMenu()函数相同
返回true则显示菜单
返回false则不显示菜单
菜单
选项菜单
下面的代码是在用户每次打开选项菜单时,在菜单子项
中显示用户打开该子项的次数
第1行代码设置一个菜单子项的计数器,用来统计用户打
开“上传设置”子项的次数
第4行代码是通过将菜单子项的ID传递给()
函数,获取到菜单子项的对象
第5行代码是通过MenuItem的setTitle()函数修改菜单标题
1. static int MenuUploadCounter = 0;
2. @Override
3. public boolean onPrepareOptionsMenu(Menu menu){
4. MenuItem uploadItem = (MENU_UPLOAD);
5. ("上传设置:" +(MenuUploadCounter));
6. return true;
7. }
菜单
选项菜单
onOptionsItemSelected ()函数能够处理菜单选择事件
,且该函数在每次点击菜单子项时都会被调用
下面的代码说明了如何通过菜单子项的子项ID执行不同
的操作
1. @Override
2. public boolean onOptionsItemSelected(MenuItem item){
3. switch(()){
4. case MENU_DOWNLOAD:
5. MenuDownlaodCounter++;
6. return true;
7. case MENU_UPLOAD:
8. MenuUploadCounter++;
9. return true;
10. }
11. return false;
12. }
菜单
选项菜单
onOptionsItemSelected ()的
返回值表示是否对菜单的选择
事件进行处理
如果已经处理过则返回true,
否则返回false
第2行的()
函数可以获取到被选择菜单子
项的ID
完整代码请参考OptionsMenu
程序
程序运行后,通过点击“菜单
键”可以调出程序设计的两个
菜单子项
菜单
子菜单
子菜单是能够显示更加详细信息的菜单子项
菜单子项使用了浮动窗体的显示形式,能够更好适应小
屏幕的显示方式
菜单
子菜单
Android系统的子菜单使用非常灵活,可以在选项菜单
或快捷菜单中使用子菜单,有利于将相同或相似的菜单
子项组织在一起,便于显示和分类
子菜单不支持嵌套
子菜单的添加是使用addSubMenu()函数实现
1. SubMenu uploadMenu = (SubMenu) (0,MENU_UPLOAD,1,"上传设置")
.setIcon();
2. ();
3. ("上传参数设置");
4. (0,SUB_MENU_UPLOAD_A,0,"上传参数A");
5. (0,SUB_MENU_UPLOAD_B,0,"上传参数B");
菜单
子菜单
第1行代码在onCreateOptionsMenu()函数传递的menu对
象上调用addSubMenu()函数,在选项菜单中添加一个菜
单子项,用户点击后可以打开子菜单
addSubMenu()函数与选项菜单中使用过的add()函数支持
相同的参数,同样可以指定菜单子项的ID、组ID和标题等
参数,并且能够通过setIcon()函数菜单所显示的图标
第2行代码使用setHeaderIcon ()函数,定义子菜单的图标
第3行定义子菜单的标题,若不规定子菜单的标题,子菜
单将显示父菜单子项标题,即第1行代码中 “上传设置”
第4行和第5行在子菜单中添加了两个菜单子项,菜单子项
的更新函数和选择事件处理函数,仍然使用
onPrepareOptionsMenu()函数和onOptionsItemSelected
()函数
菜单
子菜单
以上小节的代码为基础,
将“上传设置”改为子菜单
,并在子菜单中添加“上
传参数A”和“上传参数B”
两个菜单子项。完整代码
请参考MySubMenu程序
,运行结果如图
菜单
快捷菜单
快捷菜单同样采用了动窗体的显示方式,与子菜单的实
现方式相同,但两种菜单的启动方式却截然不同
启动方式:快捷菜单类似于普通桌面程序中的“右键菜
单”,当用户点击界面元素超过2秒后,将启动注册到该
界面元素的快捷菜单
使用方法:与使用选项菜单的方法非常相似,需要重载
onCreateContextMenu()函数和
onContextItemSelected()函数
onCreateContextMenu()函数主要用来添加快捷菜单所
显示的标题、图标和菜单子项等内容
菜单
快捷菜单
选项菜单中的onCreateOptionsMenu()函数仅在选项菜
单第一次启动时被调用一次
快捷菜单的onCreateContextMenu()函数每次启动时都
会被调用一次
1. final static int CONTEXT_MENU_1 = ;
2. final static int CONTEXT_MENU_2 = +1;
3. final static int CONTEXT_MENU_3 = +2;
4. @Override
5. public void onCreateContextMenu(ContextMenu menu, View v,
ContextMenuInfo menuInfo){
6. ("快捷菜单标题");
7. (0, CONTEXT_MENU_1, 0,"菜单子项1");
8. (0, CONTEXT_MENU_2, 1,"菜单子项2");
9. (0, CONTEXT_MENU_3, 2,"菜单子项3");
10. }
菜单
快捷菜单
ContextMenu类支持add()函数(代码第7行)和
addSubMenu()函数,可以在快捷菜单中添加菜单子项和
子菜单
第5行代码的onCreateContextMenu()函数中的参数
第1个参数menu是需要显示的快捷菜单
第2个参数v是用户选择的界面元素
第3个参数menuInfo是所选择界面元素的额外信息
菜单
快捷菜单
菜单选择事件的处理需要重载onContextItemSelected()
函数,该函数在用户选择快捷菜单中的菜单子项后被调
用,与onOptionsItemSelected ()函数的使用方法基本
相同
菜单
快捷菜单
1. @Override
2. public boolean onContextItemSelected(MenuItem item){
3. switch(()){
4. case CONTEXT_MENU_1:
5. ("菜单子项1");
6. return true;
7. case CONTEXT_MENU_2:
8. ("菜单子项2");
9. return true;
10. case CONTEXT_MENU_3:
11. ("菜单子项3");
12. return true;
13. }
14. return false;
15. }
菜单
快捷菜单
使用registerForContextMenu()函数,将快捷菜单注册到
界面控件上(下方代码第7行)。这样,用户在长时间点
击该界面控件时,便会启动快捷菜单
为了能够在界面上直接显示用户所选择快捷菜单的菜单子
项,在代码中引用了界面元素TextView(下方代码第6行
),通过更改TextView的显示内容(上方代码第5、8和
11行),显示用户所选择的菜单子项
1. TextView LabelView = null;
2. @Override
3. public void onCreate(Bundle savedInstanceState) {
4. (savedInstanceState);
5. setContentView();
6. LabelView = (TextView)findViewById();
7. registerForContextMenu(LabelView);
8. }
菜单
快捷菜单
下方代码是/src/layout/文件的部分内容,第1
行声明了TextView的ID为label,在上方代码的第6行中
,通过将ID传递给findViewById()函数,这样
用户便能够引用该界面元素,并能够修改该界面元素的
显示内容
1. <TextView android:id="@+id/label"
2. android:layout_width="fill_parent"
3. android:layout_height="fill_parent"
4. android:text="@string/hello"
5. />
菜单
快捷菜单
需要注意的一点,上方代码的第2行,将
android:layout_width设置为fill_parent,这样TextView
将填充满父节点的所有剩余屏幕空间,用户点击屏幕
TextView下方任何位置都可以启动快捷菜单
如果将android:layout_width设置为wrap_content,则用
户必须准确点击TextView才能启动快捷菜单
菜单
快捷菜单
完整代码参考MyContextMenu程序,运行结果如图所
示
菜单
快捷菜单
在Android系统中,菜单不仅能够在代码中定义,而且
可以像界面布局一样在XML文件中进行定义
使用XML文件定义界面菜单,将代码与界面设计分类,
有助于简化代码的复杂程度,并且更有利于界面的可视
化
下面将快捷菜的示例程序MyContextMen改用XML实现
,新程序的工程名称为MyXLMContoxtMenu
菜单
快捷菜单
首先需要创建保存菜单内容的XML文件
在/src目录下建立子目录menu,并在menu下建立
文件,代码如下
在描述菜单的XML文件中,必须以<menu>标签(代码第1行)
作为根节点,<item>标签(代码第2行)用来描述菜单中的子项
,<item>标签可以通过嵌套实现子菜单的功能
1. <menu xmlns:android="
2. <item android:id="@+id/contextMenu1"
3. android:title="菜单子项1"/>
4. <item android:id="@+id/contextMenu2"
5. android:title="菜单子项2"/>
6. <item android:id="@+id/contextMenu3"
7. android:title="菜单子项3"/>
8. </menu>
菜单
快捷菜单
XML菜单的显示结果如图所示
菜单
快捷菜单
在XML文件中定义菜单后,在onCreateContextMenu()
函数中调用()方法,将XML资源文件传递
给菜单对象
第4行代码中的getMenuInflater()为当前的Activity返回
MenuInflater
第5行代码将XML资源文件_menu,传递
给menu这个快捷菜单对象
1. @Override
2. public void onCreateContextMenu(ContextMenu menu,
3. View v, ContextMenuInfo menuInfo){
4. MenuInflater inflater = getMenuInflater();
5. (_menu, menu);
6. }
界面事件
在Android系统中,存在多种界面事件,如点
击事件、触摸事件、焦点事件和菜单事件等等
当这些界面事件发生时,Android界面框架调
用界面控件的事件处理函数对事件进行处理
界面事件
按键事件
在MVC模型中,控制器根据界面事件(UI Event)类型
不同,将事件传递给界面控件不同的事件处理函数。
按键事件(KeyEvent)将传递给onKey()函数进行处理
触摸事件(TouchEvent)将传递给onTouch()函数进行处
理
界面事件
按键事件
Android系统界面事件的传递和处理遵循一的规则
如果界面控件设置了事件监听器,则事件将先传递给事件
监听器
如果界面控件没有设置事件监听器,界面事件则会直接传
递给界面控件的其他事件处理函数
即使界面控件设置了事件监听器,界面事件也可以再次传
递给其他事件处理函数
界面事件
按键事件
Android系统界面事件的传递和处理遵循一的规则
是否继续传递事件给其他处理函数是由事件监听器处理函
数的返回值决定的
如果监听器处理函数的返回值为true,表示该事件已经完
成处理过程,不需要其他处理函数参与处理过程,这样事
件就不会再继续进行传递
如果监听器处理函数的返回值为false,则表示该事件没有
完成处理过程,或需要其他处理函数捕获到该事件,事件
会被传递给其他的事件处理函数
界面事件
按键事件
以EditText控件中的按键事件为例,说明Android系统界
面事件传递和处理过程,假设EditText控件已经设置了
按键事件监听器
当用户按下键盘上的某个按键时,控制器将产生
KeyEvent按键事件
Android系统会首先判断EditText控件是否设置了按键事件
监听器,因为EditText控件已经设置按键事件监听器
OnKeyListener,所以按键事件先传递到监听器的事件处
理函数onKey()中
界面事件
按键事件
事件能够继续传递给EditText控件的其他事件处理函数,
完全根据onKey()函数的返回值来确定
如果onKey()函数返回false,事件将继续传递,这样
EditText控件就可以捕获到该事件,将按键的内容显示在
EditText控件中
如果onKey()函数返回true,将阻止按键事件的继续传递
,这样EditText控件就不能够捕获到按键事件,也就不能
够将按键内容显示在EditText控件中
界面事件
按键事件
Android界面框架支持对按键事件的监听,并能够将按
键事件的详细信息传递给处理函数
为了处理控件的按键事件,先需要设置按键事件的监听
器,并重载onKey()函数
示例代码如下
1. (new OnKeyListener(){
2. @Override
3. public boolean onKey(View view, int keyCode, KeyEvent keyEvent) {
4. //过程代码……
5. return true/false;
6. }
界面事件
按键事件
第1行代码是设置控件的按键事件监听器
第3行代码的onKey ()函数中的参数
第1个参数view表示产生按键事件的界面控件
第2个参数keyCode表示按键代码
第3个参数keyEvent则包含了事件的详细信息,如按键的重
复次数、硬件编码和按键标志等
第5行代码是onKey ()函数的返回值
返回true,阻止事件传递
返回false,允许继续传递按键事件
界面事件
按键事件
KeyEventDemo是一个说明
如何处理按键事件的示例
KeyEventDemo用户界面
最上方的EditText控件是输
入字符的区域
中间的CheckBox控件用来
控制onKey()函数的返回值
最下方的TextView控件用来
显示按键事件的详细信息,
包括按键动作、按键代码、
按键字符、Unicode编码、
重复次数、功能键状态、硬
件编码和按键标志
界面事件
按键事件
界面的XML文件的代码如下
1. <EditText android:id="@+id/entry"
2. android:layout_width="fill_parent"
3. android:layout_height="wrap_content">
4. </EditText>
5. <CheckBox android:id="@+id/block"
6. android:layout_width="wrap_content"
7. android:layout_height="wrap_content"
8. android:text="返回true,阻止将按键事件传递给界面元素" >
9. </CheckBox>
10. <TextView android:id="@+id/label"
11. android:layout_width="wrap_content"
12. android:layout_height="wrap_content"
13. android:text="按键事件信息" >
14. </TextView>
界面事件
按键事件
在EditText中,每当任何一个键子按下或抬起时,都会
引发按键事件
为了能够使EditText处理按键事件,需要使用
setOnKeyListener ()函数在代码中设置按键事件监听器
,并在onKey()函数添加按键事件的处理过程
1. (new OnKeyListener(){
2. @Override
3. public boolean onKey(View view, int keyCode, KeyEvent keyEvent) {
4. int metaState = ();
5. int unicodeChar = ();
6. String msg = "";
界面事件
按键事件
7. msg +="按键动作:" + (())+"\n";
8. msg +="按键代码:" + (keyCode)+"\n";
9. msg +="按键字符:" + (char)unicodeChar+"\n";
10. msg +="UNICODE:" + (unicodeChar)+"\n";
11. msg +="重复次数:" + (())+"\n";
12. msg +="功能键状态:" + (metaState)+"\n";
13. msg +="硬件编码:" + (())+"\n";
14. msg +="按键标志:" + (())+"\n";
15. (msg);
16. if (())
17. return true;
18. else
19. return false;
20. }
界面事件
按键事件
第4行代码用来获取功能键状态。功能键包括左Alt键、右
Alt键和Shift键,当这三个功能键被按下时,功能键代码
metaState值分别为18、34和65;但没有功能键被按下时
,功能键代码metaState值分别为0
第5行代码获取了按键的Unicode值,在第9行中,将
Unicode转换为字符,显示在TextView中
第7行代码获取了按键动作,0表示按下按键,1表示抬起
按键。第7行代码获取按键的重复次数,但按键被长时间
按下时,则会产生这个属性值
第13行代码获取了按键的硬件编码,不同硬件设备的按键
硬件编码都不相同,因此该值一般用于调试
第14行获取了按键事件的标志符
界面事件
触摸事件
Android界面框架支持对触摸事件的监听,并能够将触
摸事件的详细信息传递给处理函数
需要设置触摸事件的监听器,并重载onTouch ()函数
第1行代码是设置控件的触摸事件监听器
在代码第3行的onTouch()函数中,第1个参数View表示产
生触摸事件的界面控件;第2个参数MontionEvent表示触
摸事件的详细信息,如产生时间、坐标和触点压力等
第5行是onTouch()函数的返回值
1. (new (){
2. @Override
3. public boolean onTouch(View v, MotionEvent event) {
4. //过程代码……
5. return true/false;
6. }
界面事件
触摸事件
TouchEventDemo是一个说
明如何处理触摸事件的示例
TouchEventDemo用户界面
浅蓝色区域是可以接受触摸
事件的区域,用户可以在
Android模拟器中使用鼠标
点击屏幕,用以模拟触摸手
机屏幕
下方黑色区域是显示区域,
用来显示触摸事件的类型、
相对坐标、绝对坐标、触点
压力、触点尺寸和历史数据
量等信息
界面事件
触摸事件
在用户界面中使用了线性布局,并加入了3个TextView
控件
第1个TextView(ID为touch_area)用来标识触摸事件的
测试区域
第2个TextView(ID为history_label)用来显示触摸事件
的历史数据量
第3个TextView(ID为event_label)用来触摸事件的详细
信息,包括类型、相对坐标、绝对坐标、触点压力和触点
尺寸
界面事件
触摸事件
XML文件的代码如下
1. <?xml version="" encoding="utf-8"?>
2. <LinearLayout xmlns:android="
3. android:orientation="vertical"
4. android:layout_width="fill_parent"
5. android:layout_height="fill_parent">
6. <TextView android:id="@+id/touch_area"
7. android:layout_width="fill_parent"
8. android:layout_height="300dip"
9. android:background="#0FF"
10. android:textColor="#FFFFFF"
11. android:text="触摸事件测试区域">
12. </TextView>
界面事件
触摸事件
第9行代码定义了TextView的背景颜色,#80A0FF是颜色
代码
第10行代码定义了TextView的字体颜色
13. <TextView android:id="@+id/history_label"
14. android:layout_width="wrap_content"
15. android:layout_height="wrap_content"
16. android:text="历史数据量:" >
17. </TextView>
18. <TextView android:id="@+id/event_label"
19. android:layout_width="wrap_content"
20. android:layout_height="wrap_content"
21. android:text="触摸事件:" >
22. </TextView>
23. </LinearLayout>
界面事件
触摸事件
在代码中为了能够引用XML文件中声明的界面元素,使
用了下面的代码
1. TextView labelView = null;
2. labelView = (TextView)findViewById(_label);
3. TextView touchView = (TextView)findViewById(_area);
4. final TextView historyView = (TextView)findViewById(_label);
界面事件
触摸事件
当手指接触到触摸屏、在触摸屏上移动或离开触摸屏时
,分别会引发ACTION_DOWN、ACTION_UP和
ACTION_MOVE触摸事件,而无论是哪种触摸事件,
都会调用onTouch()函数进行处理
事件类型包含在onTouch()函数的MotionEvent参数中,
可以通过getAction()函数获取到触摸事件的类型,然后
根据触摸事件的不同类型进行不同的处理
为了能够使屏幕最上方的TextView处理触摸事件,需要
使用setOnTouchListener()函数在代码中设置触摸事件
监听器,并在onTouch()函数添加触摸事件的处理过程
界面事件
触摸事件
1. (new (){
2. @Override
3. public boolean onTouch(View v, MotionEvent event) {
4. int action = ();
5. switch (action) {
6. case (_DOWN):
7. Display("ACTION_DOWN",event);
8. break;
9. case (_UP):
10. int historySize = ProcessHistory(event);
11. ("历史数据量:"+historySize);
12. Display("ACTION_UP",event);
13. break;
14. case (_MOVE):
15. Display("ACTION_MOVE",event);
16. break;
17. }
界面事件
触摸事件
第7行代码的Display()是一个自定义函数,主要用来显示
触摸事件的详细信息,函数的代码和含义将在后面进行介
绍
第10行代码的ProcessHistory()也是一个自定义函数,用
来处理触摸事件的历史数据,后面进行介绍
第11行代码是使用TextView显示历史数据的数量
18. return true;
19. }
20. });
界面事件
触摸事件
MotionEvent参数中不仅有触摸事件的类型信息,还触
点的坐标信息,获取方法是使用getX()和getY()函数,
这两个函数获取到的是触点相对于父界面元素的坐标信
息。如果需要获取绝对坐标信息,则可使用getRawX()
和getRawY()函数
触点压力是一个介于0和1之间的浮点数,用来表示用户
对触摸屏施加压力的大小,接近0表示压力较小,接近1
表示压力较大,获取触摸事件触点压力的方式是调用
getPressure()函数
触点尺寸指用户接触触摸屏的接触点大小,也是一个介
于0和1之间的浮点数,接近0表示尺寸较小,接近1表
示尺寸较大,可以使用getSize()函数获取
界面事件
触摸事件
Display()将MotionEvent参数参数中的事件信息提取出
来,并显示在用户界面上
1. private void Display(String eventType, MotionEvent event){
2. int x = (int)();
3. int y = (int)();
4. float pressure = ();
5. float size = ();
6. int RawX = (int)();
7. int RawY = (int)();
8.
9. String msg = "";
10. msg += "事件类型:" + eventType + "\n";
11. msg += "相对坐标:"+(x)+","+(y)+"\n";
12. msg += "绝对坐标:"+(RawX)+","+(RawY)+"\n";
13. msg += "触点压力:"+(pressure)+", ";
14. msg += "触点尺寸:"+(size)+"\n";
15. (msg);
16. }
界面事件
触摸事件
一般情况下,如果用户将手指放在触摸屏上,但不移动
,然后抬起手指,应先后产生ACTION_DOWN和
ACTION_UP两个触摸事件
但如果用户在屏幕上移动手指,然后再抬起手指,则会
产生这样的事件序列:ACTION_DOWN →
ACTION_MOVE → ACTION_MOVE →
ACTION_MOVE →……→ ACTION_UP
界面事件
触摸事件
在手机上运行的应用程序,效率是非常重要的。如果
Android界面框架不能产生足够多的触摸事件,则应用
程序就不能够很精确的描绘触摸屏上的触摸轨迹
如果Android界面框架产生了过多的触摸事件,虽然能
够满足精度的要求,但却降低了应用程序效率
Android界面框架使用了“打包”的解决方法。在触点移动
速度较快时会产生大量的数据,每经过一定的时间间隔
便会产生一个ACTION_MOVE事件,在这个事件中,
除了有当前触点的相关信息外,还包含这段时间间隔内
触点轨迹的历史数据信息,这样既能够保持精度,又不
至于产生过多的触摸事件。
界面事件
触摸事件
通常情况下,在ACTION_MOVE的事件处理函数中,
都先处理历史数据,然后再处理当前数据
1. private int ProcessHistory(MotionEvent event)
2. {
3. int historySize = ();
4. for (int i = 0; i < historySize; i++) {
5. long time = (i);
6. float pressure = (i);
7. float x = (i);
8. float y = (i);
9. float size = (i);
10.
11. // 处理过程......
12. }
13. return historySize;
14. }
界面事件
触摸事件
第3行代码获取了历史数据的数量
然后在第4行至12行中循环处理这些历史数据
第5行代码获取了历史事件的发生时间
第6行代码获取历史事件的触点压力
第7行和第8行代码获取历史事件的相对坐标
第9行获取历史事件的触点尺寸
在第14行返回历史数据的数量,主要是用于界面显示
Android模拟器并不支持触点压力和触点尺寸的模拟,
所有触点压力恒为,触点尺寸恒为
同时Android模拟器上也无法产生历史数据,因此历史
数据量一直显示为0
第5讲 Android用户界面
主讲介绍:
本讲学习目标
用户界面基础
用户界面基础
用户界面基础
用户界面基础
用户界面基础
用户界面基础
用户界面基础
用户界面基础
用户界面基础
用户界面基础
用户界面基础
用户界面基础
界面控件
界面控件
界面控件
界面控件
界面控件
界面控件
界面控件
界面控件
界面控件
界面控件
界面控件
界面控件
界面控件
界面控件
界面控件
界面控件
界面控件
界面控件
界面控件
界面控件
界面控件
界面控件
界面控件
界面控件
界面控件
界面控件
界面控件
界面控件
界面控件
界面控件
界面控件
界面控件
界面控件
界面控件
界面控件
界面控件
界面控件
界面控件
界面控件
界面控件
界面控件
界面控件
界面控件
界面控件
界面控件
界面控件
界面控件
界面控件
界面控件
界面控件
界面控件
界面控件
界面控件
界面控件
界面控件
界面控件
界面控件
界面控件
界面控件
界面控件
界面控件
界面布局
界面布局
界面布局
界面布局
界面布局
界面布局
界面布局
界面布局
界面布局
界面布局
界面布局
界面布局
界面布局
界面布局
界面布局
界面布局
界面布局
界面布局
界面布局
界面布局
界面布局
界面布局
界面布局
界面布局
界面布局
界面布局
界面布局
界面布局
界面布局
界面布局
界面布局
界面布局
界面布局
界面布局
界面布局
界面布局
界面布局
界面布局
界面布局
界面布局
菜单
菜单
菜单
菜单
菜单
菜单
菜单
菜单
菜单
菜单
菜单
菜单
菜单
菜单
菜单
菜单
菜单
菜单
菜单
菜单
菜单
菜单
菜单
菜单
菜单
菜单
菜单
菜单
菜单
菜单
界面事件
界面事件
界面事件
界面事件
界面事件
界面事件
界面事件
界面事件
界面事件
界面事件
界面事件
界面事件
界面事件
界面事件
界面事件
界面事件
界面事件
界面事件
界面事件
界面事件
界面事件
界面事件
界面事件
界面事件
界面事件
界面事件
界面事件
界面事件