第4章 高级用户界面设计

tb教学录像:2小时46分钟)

第3章介绍了用户界面设计中如何控制UI界面,以及布局管理器和基本组件的应用。经过前面的学习,已经可以设计出一些常用的Android界面,本章将继续学习Android开发中的用户界面设计,主要涉及一些常用的高级组件、消息提示框和对话框等,通过这些组件,可以开发出更加优秀的用户界面。

通过阅读本章,您可以:

★ 掌握自动完成文本框的使用方法

★ 掌握进度条的用途和使用方法

★ 掌握拖动条和星级评分条的使用

★ 掌握选项卡的基本应用

★ 掌握图像切换器、网格视图和画廊视图的应用

★ 掌握如何创建可以作为列表项的适配器

★ 掌握如何显示消息提示框和对话框

4.1 高级组件

tb教学录像:光盘\TM\lx\4\高级组件.exe

通过前面章节的学习,我们已经掌握了Android提供的基本界面组件,本节将介绍Android提供的常用高级组件。使用这些组件可以大大降低开发者的开发难度,为快速程序开发提供方便。

4.1.1 自动完成文本框

自动完成文本框(AutoCompleteTextView),用于实现允许用户输入一定字符后,显示一个下拉菜单,供用户从中选择,当用户选择某个选项后,按用户选择自动填写该文本框。

在屏幕中添加自动完成文本框,可以在XML布局文件中通过<AutoCompleteTextView>标记添加,基本语法格式如下:

  1. <AutoCompleteTextView
  2. 属性列表
  3. >
  4. </AutoCompleteTextView>

AutoCompleteTextView组件继承自EditText,所以它支持EditText组件提供的属性,同时,该组件还支持如表4.1所示的XML属性。

表4.1 AutoCompleteTextView支持的XML属性

XML属性 描 述
android:completionHint 用于为弹出的下拉菜单指定提示标题
android:completionThreshold 用于指定用户至少输入几个字符才会显示提示
android:dropDownHeight 用于指定下拉菜单的高度
android:dropDownHorizontalOffset 用于指定下拉菜单与文本之间的水平偏移。下拉菜单默认与文本框左对齐
android:dropDownVerticalOffset 用于指定下拉菜单与文本之间的垂直偏移。下拉菜单默认紧跟文本框
android:dropDownWidth 用于指定下拉菜单的宽度
android:popupBackground 用于为下拉菜单设置背景

下面给出一个关于自动完成文本框的实例。

例4.1 在Eclipse中创建Android项目,名称为4.1,实现带自动提示功能的搜索框。(实例位置:光盘\TM\sl\4\4.1)

(1)修改新建项目的res\layout目录下的布局文件main.xml,将默认添加的垂直线性布局管理器修改为水平线性布局管理器,并在该布局管理器中添加一个自动完成文本框和一个按钮,修改后的代码如下:

  1. <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
  2. android:orientation="horizontal"
  3. android:layout_width="fill_parent"
  4. android:layout_height="fill_parent"
  5. >
  6. <AutoCompleteTextView
  7. android:layout_height="wrap_content"
  8. android:text=""
  9. android:id="@+id/autoCompleteTextView1"
  10. android:completionThreshold="2"
  11. android:completionHint="输入搜索内容"
  12. android:layout_weight="7"
  13. android:layout_width="wrap_content">
  14. </AutoCompleteTextView>
  15. <Button
  16. android:text="搜索"
  17. android:id="@+id/button1"
  18. android:layout_weight="1"
  19. android:layout_marginLeft="10px"
  20. android:layout_width="wrap_content"
  21. android:layout_height="wrap_content"/>
  22. </LinearLayout>

说明:在上面的代码中,通过android:completionHint属性设置下拉菜单中显示的提示标题;通过android:completionThreshold属性设置用户至少输入2个字符才会显示提示。

(2)在主活动MainActivity中,定义一个字符串数组常量,用于保存要在下拉菜单中显示的列表项,具体代码如下:

  1. private static final String[] COUNTRIES = new String[] {
  2. "明日科技", "明日科技有限公司", "吉林省明日科技有限公司", "明日编程词典", "明日"};

(3)在主活动的onCreate()方法中,首先获取布局文件中添加的自动完成文本框,然后创建一个保存下拉菜单中要显示的列表项的ArrayAdapter适配器,最后将该适配器与自动完成文本框相关联,关键代码如下:

  1. //获取自动完成文本框
  2. AutoCompleteTextView textView=(AutoCompleteTextView)findViewById(R.id.autoCompleteTextView1);
  3. ArrayAdapter<String> adapter=new ArrayAdapter<String>(this,
  4. android.R.layout.simple_dropdown_item_1line,COUNTRIES); //创建一个ArrayAdapter适配器
  5. textView.setAdapter(adapter); //为自动完成文本框设置适配器

(4)获取“搜索”按钮,并为其添加单击事件监听器,在其onClick事件中通过消息提示框显示自动完成文本框中输入的内容,具体代码如下:

  1. Button button=(Button)findViewById(R.id.button1); //获取“搜索”按钮
  2. //为“搜索”按钮添加单击事件监听器
  3. button.setOnClickListener(new OnClickListener() {
  4. @Override
  5. public void onClick(View v) {
  6. Toast.makeText(MainActivity.this, textView.getText().toString(), Toast.LENGTH_SHORT).show();
  7. }
  8. });

运行本实例,在屏幕上显示由自动完成文本框和按钮组成的搜索框,输入文字“明日”后,在下方将显示符合条件的提示信息下拉菜单,如图4.1所示,双击想要的列表项,即可将选中的内容显示到自动完成文本框中。

144-1 图4.1 应用自动完成文本框实现搜索框

4.1.2 进度条

当一个应用在后台执行时,前台界面不会有任何信息,这时用户根本不知道程序是否在执行以及执行进度等,因此需要使用进度条来提示程序执行的进度。在Android中,进度条(ProgressBar)用于向用户显示某个耗时操作完成的百分比。

在屏幕中添加进度条,可以在XML布局文件中通过<ProgressBar>标记添加,基本语法格式如下:

  1. < ProgressBar
  2. 属性列表
  3. >
  4. </ProgressBar>

ProgressBar组件支持的XML属性如表4.2所示。

表4.2 ProgressBar支持的XML属性

XML属性 描 述
android:max 用于设置进度条的最大值
android:progress 用于指定进度条已完成的进度值
android:progressDrawable 用于设置进度条轨道的绘制形式

除了表4.2中介绍的属性外,进度条组件还提供了下面两个常用方法用于操作进度。

[√]setProgress(int progress)方法:用于设置进度完成的百分比。

[√]incrementProgressBy(int diff)方法:用于设置进度条的进度增加或减少。当参数值为正数时,表示进度增加;为负数时,表示进度减少。

下面给出一个关于在屏幕中使用进度条的实例。

例4.2 在Eclipse中创建Android项目,名称为4.2,实现水平进度条和圆形进度条。(实例位置:光盘\TM\sl\4\4.2)

(1)修改新建项目的res\layout目录下的布局文件main.xml,将默认添加的TextView组件删除,并添加一个水平进度条和一个圆形进度条,修改后的代码如下:

  1. <!-- 水平进度条 -->
  2. <ProgressBar
  3. android:id="@+id/progressBar1"
  4. android:layout_width="match_parent"
  5. android:max="100"
  6. style="@android:style/Widget.ProgressBar.Horizontal"
  7. android:layout_height="wrap_content"/>
  8. <!-- 圆形进度条 -->
  9. <ProgressBar
  10. android:id="@+id/progressBar2"
  11. style="?android:attr/progressBarStyleLarge"
  12. android:layout_width="wrap_content"
  13. android:layout_height="wrap_content"/>

说明:在上面的代码中,通过android:max属性设置水平进度条的最大进度值;通过style属性可以为ProgressBar指定风格,常用的style属性值如表4.3所示。

表4.3 ProgressBar的style属性的可选值

XML属性 描 述
?android:attr/progressBarStyleHorizontal 细水平长条进度条
?android:attr/progressBarStyleLarge 大圆形进度条
?android:attr/progressBarStyleSmall 小圆形进度条
@android:style/Widget.ProgressBar.Large 大跳跃、旋转画面的进度条
@android:style/Widget.ProgressBar.Small 小跳跃、旋转画面的进度条
@android:style/Widget.ProgressBar.Horizontal 粗水平长条进度条

(2)在主活动MainActivity中,定义两个ProgressBar类的对象(分别用于表示水平进度条和圆形进度条,一个int型的变量(用于表示完成进度)和一个处理消息的Handler类的对象,具体代码如下:

  1. private ProgressBar horizonP; //水平进度条
  2. private ProgressBar circleP; //圆形进度条
  3. private int mProgressStatus = 0; //完成进度
  4. private Handler mHandler; //声明一个用于处理消息的Handler类的对象

(3)在主活动的onCreate()方法中,首先获取水平进度条和圆形进度条,然后通过匿名内部类实例化处理消息的Handler类的对象,并重写其handleMessage()方法,实现当耗时操作没有完成时更新进度,否则设置进度条不显示,关键代码如下:

  1. horizonP = (ProgressBar) findViewById(R.id.progressBar1); //获取水平进度条
  2. circleP=(ProgressBar)findViewById(R.id.progressBar2); //获取圆形进度条
  3. mHandler=new Handler(){
  4. @Override
  5. public void handleMessage(Message msg) {
  6. if(msg.what==0x111){
  7. horizonP.setProgress(mProgressStatus); //更新进度
  8. }else{
  9. Toast.makeText(MainActivity.this, "耗时操作已经完成", Toast.LENGTH_SHORT).show();
  10. horizonP.setVisibility(View.GONE); //设置进度条不显示,并且不占用空间
  11. circleP.setVisibility(View.GONE); //设置进度条不显示,并且不占用空间
  12. }
  13. }
  14. };

(4)开启一个线程,用于模拟一个耗时操作。在该线程中,调用sendMessage()方法发送处理消息,具体代码如下:

  1. new Thread(new Runnable() {
  2. public void run() {
  3. while (true) {
  4. mProgressStatus = doWork(); //获取耗时操作完成的百分比
  5. Message m=new Message();
  6. if(mProgressStatus<100){
  7. m.what=0x111;
  8. mHandler.sendMessage(m); //发送信息
  9. }else{
  10. m.what=0x110;
  11. mHandler.sendMessage(m); //发送消息
  12. break;
  13. }
  14. }
  15. }
  16. //模拟一个耗时操作
  17. private int doWork() {
  18. mProgressStatus+=Math.random()*10; //改变完成进度
  19. try {
  20. Thread.sleep(200); //线程休眠200毫秒
  21. } catch (InterruptedException e) {
  22. e.printStackTrace();
  23. }
  24.  
  25. return mProgressStatus; //返回新的进度
  26. }
  27. }).start(); //开启一个线程

运行本实例,将显示如图4.2所示的运行结果。

147-1 图4.2 在屏幕中显示水平进度条和圆形进度条

4.1.3 拖动条和星级评分条

在Andriod中,提供了两种允许用户通过拖动来改变进度的组件,分别是拖动条(Seek Bar)和星级评分条(RatmgBar),下面分别进行介绍。

  1. 拖动条

拖动条与进度条类似,所不同的是,拖动条允许用户拖动滑块来改变值,通常用于实现对某种数值的调节。例如,调节图片的透明度或是音量等。

在Android中,如果想在屏幕中添加拖动条,可以在XML布局文件中通过<SeekBar>标记添加,基本语法格式如下:

  1. <SeekBar
  2. android:layout_height="wrap_content"
  3. android:id="@+id/seekBar1"
  4. android:layout_width="match_parent">
  5. </SeekBar>

SeekBar组件允许用户改变拖动滑块的外观,这可以使用android:thumb属性实现,该属性的属性值为一个Drawable对象,该Drawable对象将作为自定义滑块。

由于拖动条可以被用户控制,所以需要为其添加OnSeekBarChangeListener监听器,基本代码如下:

  1. seekbar.setOnSeekBarChangeListener(new OnSeekBarChangeListener() {
  2. @Override
  3. public void onStopTrackingTouch(SeekBar seekBar) {
  4. //要执行的代码
  5. }
  6. @Override
  7. public void onStartTrackingTouch(SeekBar seekBar) {
  8. //要执行的代码
  9. }
  10. @Override
  11. public void onProgressChanged(SeekBar seekBar, int progress,
  12. boolean fromUser) {
  13. //其他要执行的代码
  14. }
  15. });

说明:在上面的代码中,onProgressChanged()方法中的参数progress表示当前进度,也就是拖动条的值。

下面通过一个具体的实例说明拖动条的应用。

例4.3 在Eclipse中创建Android项目,名称为4.3,实现在屏幕上显示拖动条,并为其添加OnSeekBarChangeListener监听器。(实例位置:光盘\TM\sl\4\4.3)

(1)修改新建项目的res\layout目录下的布局文件main.xml,将默认添加的TextView组件的android:text属性值修改为“当前值:50”,然后添加一个拖动条,并指定拖动条的当前值和最大值,修改后的代码如下:

  1. <TextView
  2. android:text="当前值:50"
  3. android:id="@+id/textView1"
  4. android:layout_width="wrap_content"
  5. android:layout_height="wrap_content"/>
  6. <!-- 拖动条 -->
  7. <SeekBar
  8. android:layout_height="wrap_content"
  9. android:id="@+id/seekBar1"
  10. android:max="100"
  11. android:progress="50"
  12. android:padding="10px"
  13. android:layout_width="match_parent"/>

(2)在主活动MainActivity中,定义一个SeekBar类的对象,用于表示拖动条,具体代码如下:

  1. private SeekBar seekbar; //拖动条

(3)在主活动的onCreate()方法中,首先获取布局文件中添加的文本视图和拖动条,然后为拖动条添加OnSeekBarChangeListener事件监听器,并且在重写的onStopTrackingTouch()和onStartTracking Touch()方法中应用消息提示框显示对应状态,在onProgressChanged()方法中修改文本视图的值为当前进度条的进度值,具体代码如下:

  1. final TextView result=(TextView)findViewById(R.id.textView1); //获取文本视图
  2. seekbar = (SeekBar) findViewById(R.id.seekBar1); //获取拖动条
  3. seekbar.setOnSeekBarChangeListener(new OnSeekBarChangeListener() {
  4. @Override
  5. public void onStopTrackingTouch(SeekBar seekBar) {
  6. Toast.makeText(MainActivity.this, "结束滑动", Toast.LENGTH_SHORT).show();
  7. }
  8. @Override
  9. public void onStartTrackingTouch(SeekBar seekBar) {
  10. Toast.makeText(MainActivity.this, "开始滑动", Toast.LENGTH_SHORT).show();
  11. }
  12. @Override
  13. public void onProgressChanged(SeekBar seekBar, int progress,boolean fromUser) {
  14. result.setText("当前值:"+progress); //修改文本视图的值
  15. }
  16. });

运行本实例,在屏幕中将显示默认进度为60的拖动条,如图4.3所示,用鼠标拖动圆形滑块,在上方的文本视图中将显示改变后的当前进度,并且通过消息提示框显示“开始滑动”和“结束滑动”。

149-1 图4.3 在屏幕中显示拖动条

  1. 星级评分条

星级评分条与拖动条类似,都允许用户拖动来改变进度,所不同的是,星级评分条通过星星图案表示进度。通常情况下,使用星级评分条表示对某一事物的支持度或对某种服务的满意程度等。例如,淘宝网中对卖家的好评度,就是通过星级评分条实现的。

在Android中,如果想在屏幕中添加星级评分条,可以在XML布局文件中通过<RatingBar>标记添加,基本语法格式如下:

  1. <RatingBar
  2. 属性列表
  3. >
  4. </RatingBar>

RatingBar组件支持的XML属性如表4.4所示。

表4.4 RatingBar支持的XML属性

XML属性 描 述
android:isIndicator 用于指定该星级评分条是否允许用户改变,true为不允许改变
android:numStars 用于指定该星级评分条总共有多少个星
android:rating 用于指定该星级评分条默认的星级
android:stepSize 用于指定每次最少需要改变多少个星级,默认为0.5个

除了表4.4中介绍的属性外,星级评分条还提供了以下3个比较常用的方法。

[√]getRating()方法:用于获取等级,表示选中了几颗星。

[√]getStepSize():用于获取每次最少要改变多少个星级。

[√]getProgress()方法:用于获取进度,获取到的进度值为getRating()方法返回值与getStepSize()方法返回值之积。

下面通过一个具体的实例来说明星级评分条的应用。

例4.4 在Eclipse中创建Android项目,名称为4.4,实现星级评分条。(实例位置:光盘\TM\sl\4\4.4)

(1)修改新建项目的res\layout目录下的布局文件main.xml,将默认添加的TextView组件删除,并添加一个星级评分条和一个普通按钮,修改后的代码如下:

  1. <!-- 星级评分条 -->
  2. <RatingBar
  3. android:id="@+id/ratingBar1"
  4. android:numStars="5"
  5. android:rating="3.5"
  6. android:isIndicator="true"
  7. android:layout_width="wrap_content"
  8. android:layout_height="wrap_content"/>
  9. <! -- 按钮-->
  10. <Button
  11. android:text="提交"
  12. android:id="@+id/button1"
  13. android:layout_width="wrap_content"
  14. android:layout_height="wrap_content"/>

(2)在主活动MainActivity中,定义一个RatingBar类的对象,用于表示星级评分条,具体代码如下:

  1. private RatingBar ratingbar; //星级评分条

(3)在主活动的onCreate()方法中,首先获取布局文件中添加的星级评分条,然后获取提交按钮,并为其添加单击事件监听器,在重写的onClick()事件中,获取进度、等级和每次最少要改变多少个星级并显示到日志中,同时通过消息提示框显示获得的星的个数,关键代码如下:

  1. ratingbar = (RatingBar) findViewById(R.id.ratingBar1); //获取星级评分条
  2. Button button=(Button)findViewById(R.id.button1); //获取“提交”按钮
  3. button.setOnClickListener(new OnClickListener() {
  4. @Override
  5. public void onClick(View v) {
  6. int result=ratingbar.getProgress(); //获取进度
  7. float rating=ratingbar.getRating(); //获取等级
  8. float step=ratingbar.getStepSize(); //获取每次最少要改变多少个星级
  9. Log.i("星级评分条","step="+step+" result="+result+" rating="+rating);
  10. Toast.makeText(MainActivity.this, "你得到了"+rating+"颗星", Toast.LENGTH_SHORT).show();
  11. }
  12. });

运行本实例,在屏幕中将显示5颗星的星级评分条,单击第4颗星的左半边,将显示如图4.4所示的选中效果,单击“提交”按钮,将弹出如图4.5所示的消息提示框显示选择了几颗星。

150-1 150-2
图4.4 在屏幕中显示星级评分条 图4.5 单击“提交”按钮显示选择了几颗星

4.1.4 选项卡

选项卡主要由TabHost、TabWidget和FrameLayout 3个组件组成,用于实现一个多标签页的用户界面,通过它可以将一个复杂的对话框分割成若干个标签页,实现对信息的分类显示和管理。使用该组件不仅可以使界面简洁大方,还可以有效地减少窗体的个数。

在Android中,实现选项卡的一般步骤如下:

(1)在布局文件中添加实现选项卡所需的TabHost、TabWidget和FrameLayout组件。

(2)编写各标签页中要显示内容所对应的XML布局文件。

(3)在Activity中,获取并初始化TabHost组件。

(4)为TabHost对象添加标签页。

下面通过一个具体的实例来说明选项卡的应用。

例4.5 在Eclipse中创建Android项目,名称为4.5,实现模拟显示未接来电和已接来电的选项卡。(实例位置:光盘\TM\sl\4\4.5)

(1)修改新建项目的res\layout目录下的布局文件main.xml,将默认添加的布局代码删除,然后添加实现选项卡所需的TabHost、TabWidget和FrameLayout组件。具体的步骤是:首先添加一个TabHost组件,然后在该组件中添加线性布局管理器,并且在该布局管理器中添加一个作为标签组的TabWidget和一个作为标签内容的FrameLayout组件。在XML布局文件中添加选项卡的基本代码如下:

  1. <?xml version="1.0" encoding="utf-8"?>
  2. <TabHost xmlns:android="http://schemas.android.com/apk/res/android"
  3. android:id="@android:id/tabhost"
  4. android:layout_width="fill_parent"
  5. android:layout_height="fill_parent">
  6. <LinearLayout
  7. android:orientation="vertical"
  8. android:layout_width="fill_parent"
  9. android:layout_height="fill_parent">
  10. <TabWidget
  11. android:id="@android:id/tabs"
  12. android:layout_width="fill_parent"
  13. android:layout_height="wrap_content" />
  14. <FrameLayout
  15. android:id="@android:id/tabcontent"
  16. android:layout_width="fill_parent"
  17. android:layout_height="fill_parent">
  18. </FrameLayout>
  19. </LinearLayout>
  20. </TabHost>

说明:在应用XML布局文件添加选项卡时,必须使用系统的id来为各组件指定id属性,否则将出现异常。

(2)编写各标签页中要显示内容对应的XML布局文件。例如,编写一个XML布局文件,名称为tab1.xml,用于指定第一个标签页中要显示的内容,具体代码如下:

  1. <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
  2. android:id="@+id/LinearLayout01"
  3. android:orientation="vertical"
  4. android:layout_width="wrap_content"
  5. android:layout_height="wrap_content">
  6. <TextView
  7. android:layout_width="fill_parent"
  8. android:layout_height="wrap_content"
  9. android:text="简约但不简单"/>
  10. <TextView
  11. android:layout_width="fill_parent"
  12. android:layout_height="wrap_content"
  13. android:text="风铃草"/>
  14. </LinearLayout>

说明:在本实例中,除了需要编写名称为tab1.xml的布局文件外,还需要编写名称为tab2.xml的布局文件,用于指定第二个标签页中要显示的内容。

(3)在Activity中,获取并初始化TabHost组件,关键代码如下:

  1. private TabHost tabHost; //声明TabHost组件的对象
  2. tabHost=(TabHost)findViewById(android.R.id.tabhost); //获取TabHost对象
  3. tabHost.setup(); //初始化TabHost组件

(4)为TabHost对象添加标签页,这里共添加了两个标签页,一个用于模拟显示未接来电,另一个用于模拟显示已接来电,关键代码如下:

  1. LayoutInflater inflater = LayoutInflater.from(this); //声明并实例化一个LayoutInflater对象
  2. inflater.inflate(R.layout.tab1, tabHost.getTabContentView());
  3. inflater.inflate(R.layout.tab2, tabHost.getTabContentView());
  4. tabHost.addTab(tabHost.newTabSpec("tab01")
  5. .setIndicator("未接来电")
  6. .setContent(R.id.LinearLayout01)); //添加第一个标签页
  7. tabHost.addTab(tabHost.newTabSpec("tab02")
  8. .setIndicator("已接来电")
  9. .setContent(R.id.FrameLayout02)); //添加第二个标签页

运行本实例,将显示如图4.6所示的运行结果。

152-1 图4.6 在屏幕中添加选项卡

4.1.5 图像切换器

图像切换器(ImageSwitcher),用于实现类似于Windows操作系统下的“Windows照片查看器”中的上一张、下一张切换图片的功能。在使用ImageSwitcher时,必须实现ViewSwitcher.ViewFactory接口,并通过makeView()方法来创建用于显示图片的ImageView。makeView()方法将返回一个显示图片的ImageView。在使用图像切换器时,还有一个方法非常重要,那就是setImageResource()方法,该方法用于指定要在ImageSwitcher中显示的图片资源。

下面通过一个具体的实例来说明图像切换器的用法。

例4.6 在Eclipse中创建Android项目,名称为4.6,实现类似于Windows照片查看器的简单的图片查看器。(实例位置:光盘\TM\sl\4\4.6)

(1)修改新建项目的res\layout目录下的布局文件main.xml,将默认添加的垂直线性布局修改为水平线性布局,并将TextView组件删除,然后添加两个按钮和一个图像切换器ImageSwitcher,并设置图像切换器的布局方式为居中显示。修改后的代码如下:

  1. <?xml version="1.0" encoding="utf-8"?>
  2. <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
  3. android:orientation="horizontal"
  4. android:layout_width="fill_parent"
  5. android:layout_height="fill_parent"
  6. android:id="@+id/llayout"
  7. android:gravity="center" >
  8. <Button
  9. android:text="上一张"
  10. android:id="@+id/button1"
  11. android:layout_width="wrap_content"
  12. android:layout_height="wrap_content"/>
  13. <!-- 添加一个图像切换器 -->
  14. <ImageSwitcher
  15. android:id="@+id/imageSwitcher1"
  16. android:layout_gravity="center"
  17. android:layout_width="wrap_content"
  18. android:layout_height="wrap_content"/>
  19. <Button
  20. android:text="下一张"
  21. android:id="@+id/button2"
  22. android:layout_width="wrap_content"
  23. android:layout_height="wrap_content"/>
  24. </LinearLayout>

(2)在主活动中,首先声明并初始化一个保存要显示图像id的数组,然后声明一个保存当前显示图像索引的变量,再声明一个图像切换器的对象,具体代码如下:

  1. private int[] imageId = new int[] { R.drawable.img01, R.drawable.img02,
  2. R.drawable.img03, R.drawable.img04, R.drawable.img05,
  3. R.drawable.img06, R.drawable.img07, R.drawable.img08,
  4. R.drawable.img09 }; //声明并初始化一个保存要显示图像id的数组
  5. private int index = 0; //当前显示图像的索引
  6. private ImageSwitcher imageSwitcher; //声明一个图像切换器对象

(3)在主活动的onCreate()方法中,首先获取布局文件中添加的图像切换器,并为其设置淡入淡出的动画效果,然后为其设置一个ImageSwitcher.ViewFactory,并重写makeView()方法,最后为图像切换器设置默认显示的图像,关键代码如下:

  1. imageSwitcher = (ImageSwitcher) findViewById(R.id.imageSwitcher1); //获取图像切换器
  2. //设置动画效果
  3. imageSwitcher.setInAnimation(AnimationUtils.loadAnimation(this,android.R.anim.fade_in)); //设置淡入动画
  4. imageSwitcher.setOutAnimation(AnimationUtils.loadAnimation(this,android.R.anim.fade_out)); //设置淡出动画
  5. imageSwitcher.setFactory(new ViewFactory() {
  6. @Override
  7. public View makeView() {
  8. imageView = new ImageView(MainActivity.this);  //实例化一个ImageView类的对象
  9. imageView.setScaleType(ImageView.ScaleType.FIT_CENTER); //设置保持纵横比居中缩放图像
  10. imageView.setLayoutParams(new ImageSwitcher.LayoutParams(
  11. LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT));
  12. return imageView; //返回imageView对象
  13. }
  14. });
  15. imageSwitcher.setImageResource(imageId[index]); //显示默认的图片

说明:在上面的代码中,使用ImageSwitcher类的父类ViewAnimator的setInAnimation()方法和setOutAnimation()方法为图像切换器设置动画效果;调用其父类ViewSwitcher的setFactory()方法指定视图切换工厂,其参数为ViewSwitcher.ViewFactory类型的对象。

(4)获取用于控制显示图片的“上一张”和“下一张”按钮,并分别为其添加单击事件监听器,在重写的onClick()方法中改变图像切换器中显示的图片,关键代码如下:

  1. Button up = (Button) findViewById(R.id.button1); //获取“上一张”按钮
  2. Button down = (Button) findViewById(R.id.button2); //获取“下一张”按钮
  3. up.setOnClickListener(new OnClickListener() {
  4. @Override
  5. public void onClick(View v) {
  6. if (index > 0) {
  7. index--; //index的值减1
  8. } else {
  9. index = imageId.length - 1;
  10. }
  11. imageSwitcher.setImageResource(imageId[index]); //显示当前图片
  12. }
  13. });
  14. down.setOnClickListener(new OnClickListener() {
  15. @Override
  16. public void onClick(View v) {
  17. if (index < imageId.length - 1) {
  18. index++; //index的值加1
  19. } else {
  20. index = 0;
  21. }
  22. imageSwitcher.setImageResource(imageId[index]); //显示当前图片
  23. }
  24. });

运行本实例,将显示如图4.7所示的运行结果。

155-1 图4.7 简单的图片查看器

4.1.6 网格视图

网格视图(GridView)是按照行、列分布的方式来显示多个组件,通常用于显示图片或是图标等。在使用网格视图时,首先需要在屏幕上添加GridView组件,通常使用<GridView>标记在XML布局文件中添加,其基本语法如下:

  1. <GridView
  2. 属性列表
  3. >
  4. </GridView>

 

GridView组件支持的XML属性如表4.5所示。

表4.5 GridView支持的XML属性

XML属性 描 述
android:columnWidth 用于设置列的宽度
android:gravity 用于设置对齐方式
android:horizontalSpacing 用于设置各元素之间的水平间距
android:numColumns 用于设置列数,其属性值通常为大于1的值,如果只有1列,那么最好使用ListView实现
android:stretchMode 用于设置拉伸模式,其中属性值可以是none(不拉伸)、spacingWidth(仅拉伸元素之间的间距)、columnWidth(仅拉伸表格元素本身)或spacingWidthUniform(表格元素本身、元素之间的间距一起拉伸)
android:verticalSpacing 用于设置各元素之间的垂直间距

GridView与ListView类似,都需要通过Adapter来提供要显示的数据。在使用GridView组件时,通常使用SimpleAdapter或者BaseAdapter类为GridView组件提供数据。下面通过一个具体的实例演示如何通过SimpleAdapter适配器指定内容的方式创建GridView。

例4.7 在Eclipse中创建Android项目,名称为4.7,实现在屏幕中添加用于显示照片和说明文字的网格视图。(实例位置:光盘\TM\sl\4\4.7)

(1)修改新建项目的res\layout目录下的布局文件main.xml,将默认添加的TextView组件删除,然后添加一个id属性为gridView1的GridView组件,并设置其列数为4,也就是每行显示4张图片。修改后的代码如下:

  1. <GridView android:id="@+id/gridView1"
  2. android:layout_height="wrap_content"
  3. android:layout_width="match_parent"
  4. android:stretchMode="columnWidth"
  5. android:numColumns="4"></GridView>

(2)编写用于布局网格内容的XML布局文件items.xml。在该文件中,采用垂直线性布局管理器,并在该布局管理器中添加一个ImageView组件和一个TextView组件,分别用于显示网格视图中的图片和说明文字,具体代码如下:

  1. <?xml version="1.0" encoding="utf-8"?>
  2. <LinearLayout
  3. xmlns:android="http://schemas.android.com/apk/res/android"
  4. android:orientation="vertical"
  5. android:layout_width="match_parent"
  6. android:layout_height="match_parent">
  7. <ImageView
  8. android:id="@+id/image"
  9. android:paddingLeft="10px"
  10. android:scaleType="fitCenter"
  11. android:layout_height="wrap_content"
  12. android:layout_width="wrap_content"/>
  13. <TextView
  14. android:layout_width="wrap_content"
  15. android:layout_height="wrap_content"
  16. android:padding="5px"
  17. android:layout_gravity="center"
  18. android:id="@+id/title"
  19. />
  20. </LinearLayout>

(3)在主活动的onCreate()方法中,首先获取布局文件中添加的ListView组件,然后创建两个用于保存图片id和说明文字的数组,并将这些图片id和说明文字添加到List集合中,再创建一个SimpleAdapter简单适配器,最后将该适配器与GridView相关联,具体代码如下:

  1. GridView gridview = (GridView) findViewById(R.id.gridView1); //获取GridView组件
  2. int[] imageId = new int[] { R.drawable.img01, R.drawable.img02,
  3. R.drawable.img03, R.drawable.img04, R.drawable.img05,
  4. R.drawable.img06, R.drawable.img07, R.drawable.img08,
  5. R.drawable.img09, R.drawable.img10, R.drawable.img11,
  6. R.drawable.img12, }; //定义并初始化保存图片id的数组
  7. String[] title = new String[] { "花开富贵", "海天一色", "日出", "天路", "一枝独秀","云", "独占鳌头", "蒲公英花",
  8. "花团锦簇","争奇斗艳", "和谐", "林间小路" }; //定义并初始化保存说明文字的数组
  9. List<Map<String, Object>> listItems = new ArrayList<Map<String, Object>>(); //创建一个List集合
  10. //通过for循环将图片id和列表项文字放到Map中,并添加到List集合中
  11. for (int i = 0; i < imageId.length; i++) {
  12. Map<String, Object> map = new HashMap<String, Object>();
  13. map.put("image", imageId[i]);
  14. map.put("title", title[i]);
  15. listItems.add(map); //将map对象添加到List集合中
  16. }
  17. SimpleAdapter adapter = new SimpleAdapter(this,
  18. listItems,
  19. R.layout.items,
  20. new String[] { "title", "image" },
  21. new int[] {R.id.title, R.id.image }
  22. ); //创建SimpleAdapter
  23. gridview.setAdapter(adapter); //将适配器与GridView关联

运行本实例,将显示如图4.8所示的运行结果。

157-1 图4.8 通过GridView显示的照片列表

如果只想在GridView中显示照片而不显示说明性文字,可以使用BaseAdapter基本适配器为其指定内容。使用BaseAdapter为GridView组件设置内容可以分为以下两个步骤。

(1)创建BaseAdapter类的对象,并重写其中的getView()、getItemId()、getItem()和getCount()方法,其中最主要的是重写getView()方法来设置显示图片的格式。以例4.7为例,将该实例中的GridView组件修改为使用BaseAdapter类设置内容的代码如下:

  1. BaseAdapter adapter=new BaseAdapter() {
  2.  
  3. @Override
  4. public View getView(int position, View convertView, ViewGroup parent) {
  5. ImageView imageview; //声明ImageView的对象
  6. if(convertView==null){
  7. imageview=new ImageView(MainActivity.this); //实例化ImageView的对象
  8. imageview.setScaleType(ImageView.ScaleType.CENTER_INSIDE); //设置缩放方式
  9. imageview.setPadding(5, 0, 5, 0); //设置ImageView的内边距
  10. }else{
  11. imageview=(ImageView)convertView;
  12. }
  13. imageview.setImageResource(imageId[position]); //为ImageView设置要显示的图片
  14. return imageview; //返回ImageView
  15. }
  16. /*
  17. * 功能:获得当前选项的id
  18. */
  19. @Override
  20. public long getItemId(int position) {
  21. return position;
  22. }
  23. /*
  24. * 功能:获得当前选项
  25. */
  26. @Override
  27. public Object getItem(int position) {
  28. return position;
  29. }
  30. /*
  31. * 获得数量
  32. */
  33. @Override
  34. public int getCount() {
  35. return imageId.length;
  36. }
  37. };

(2)将步骤(1)创建的适配器与GridView关联,关键代码如下:

  1. gridview.setAdapter(adapter); //将适配器与GridView关联

运行修改后的程序,将显示如图4.9所示的运行结果。

159-1 图4.9 通过BaseAdapter为GridView设置要显示的图片列表

4.1.7 画廊视图

画廊视图(Gallery)表示,能够按水平方向显示内容,并且可用手指直接拖动图片移动,一般用来浏览图片,被选中的选项位于中间,并且可以响应事件显示信息。在使用画廊视图时,首先需要在屏幕上添加Gallery组件,通常使用<Gallery>标记在XML布局文件中添加,其基本语法如下:

  1. < Gallery
  2. 属性列表
  3. >
  4. </Gallery>

Gallery组件支持的XML属性如表4.6所示。

表4.6 Gallery支持的XML属性

XML属性 描 述
android:animationDuration 用于设置列表项切换时的动画持续时间
android:gravity 用于设置对齐方式
android:spacing 用于设置列表项之间的间距
android:unselectedAlpha 用于设置没有选中的列表项的透明度

使用画廊视图,也需要使用Adapter提供要显示的数据。通常使用BaseAdapter类为Gallery组件提供数据。下面通过一个具体的实例演示通过BaseAdapter适配器为Gallery组件提供要显示的图片。

例4.8 在Eclipse中创建Android项目,名称为4.8,实现在屏幕中添加画廊视图,用于浏览图片。(实例位置:光盘\TM\sl\4\4.8)

(1)修改新建项目的res\layout目录下的布局文件main.xml,将默认添加的TextView组件删除,然后添加一个id属性为gallery1的Gallery组件,并设置其列表项之间的间距为5像素,以及设置未选中项的透明度。修改后的代码如下:

  1. <Gallery
  2. android:id="@+id/gallery1"
  3. android:spacing="5px"
  4. android:unselectedAlpha="0.6"
  5. android:layout_width="match_parent"
  6. android:layout_height="wrap_content" />

(2)在主活动MainActivity中,定义一个用于保存要显示图片id的数组(需要将要显示的图片复制到res/drawable文件夹中),关键代码如下:

  1. private int[] imageId = new int[] { R.drawable.img01, R.drawable.img02,
  2. R.drawable.img03, R.drawable.img04, R.drawable.img05,
  3. R.drawable.img06, R.drawable.img07, R.drawable.img08,
  4. R.drawable.img09, R.drawable.img10, R.drawable.img11,
  5. R.drawable.img12, }; //定义并初始化保存图片id的数组

(3)在主活动的onCreate()方法中,获取在布局文件中添加的画廊视图,关键代码如下:

  1. Gallery gallery = (Gallery) findViewById(R.id.gallery1); //获取Gallery组件

(4)在res\values目录中,创建一个名称为attr.xml的文件,在该文件中定义一个styleable对象,用于组合多个属性。这里只指定了一个系统自带的android:galleryItemBackground属性,用于设置各选项的背景,具体代码如下:

  1. <resources>
  2. <declare-styleable name="Gallery">
  3. <attr name="android:galleryItemBackground" />
  4. </declare-styleable>
  5. </resources>

(5)创建BaseAdapter类的对象,并重写其中的getView()、getItemId()、getItem()和getCount()方法,其中最主要的是重写getView()方法来设置显示图片的格式,具体代码如下:

  1. BaseAdapter adapter = new BaseAdapter() {
  2. @Override
  3. public View getView(int position, View convertView, ViewGroup parent) {
  4. ImageView imageview; //声明ImageView的对象
  5. if (convertView == null) {
  6. imageview = new ImageView(MainActivity.this); //实例化ImageView的对象
  7. imageview.setScaleType(ImageView.ScaleType.FIT_XY); //设置缩放方式
  8. imageview
  9. .setLayoutParams(new Gallery.LayoutParams(180, 135));
  10. TypedArray typedArray = obtainStyledAttributes(R.styleable.Gallery);
  11. imageview.setBackgroundResource(typedArray.getResourceId(
  12. R.styleable.Gallery_android_galleryItemBackground,0));
  13. imageview.setPadding(5, 0, 5, 0); //设置ImageView的内边距
  14. } else {
  15. imageview = (ImageView) convertView;
  16. }
  17. imageview.setImageResource(imageId[position]); //为ImageView设置要显示的图片
  18. return imageview; //返回ImageView
  19. }
  20. /*
  21. * 功能:获得当前选项的id
  22. */
  23. @Override
  24. public long getItemId(int position) {
  25. return position;
  26. }
  27. /*
  28. * 功能:获得当前选项
  29. */
  30. @Override
  31. public Object getItem(int position) {
  32. return position;
  33. }
  34. /*
  35. * 获得数量
  36. */
  37. @Override
  38. public int getCount() {
  39. return imageId.length;
  40. }
  41. };

(6)将步骤(5)中创建的适配器与Gallery关联,并且让中间的图片选中,为了在用户单击某张图片时显示对应的位置,还需要为Gallery添加单击事件监听器,具体代码如下:

  1. gallery.setAdapter(adapter); //将适配器与Gallery关联
  2. gallery.setSelection(imageId.length / 2); //选中中间的图片
  3. gallery.setOnItemClickListener(new OnItemClickListener() {
  4. @Override
  5. public void onItemClick(AdapterView<?> parent, View view,int position, long id) {
  6. Toast.makeText(MainActivity.this,"您选择了第" + String.valueOf(position) + "张图片",
  7. Toast.LENGTH_SHORT).show();
  8. }
  9. });

运行本实例,将显示如图4.10所示的运行结果。

161-1 图4.10 应用画廊视图显示图片列表

4.1.8 范例1:显示在标题上的进度条

例4.9 在Eclipse中创建Android项目,名称为4.9,实现在页面载入时,先在标题上显示载入进度条,载入完毕后,显示载入后的4张图片。(实例位置:光盘\TM\sl\4\4.9)

(1)修改新建项目的res\layout目录下的布局文件main.xml,为默认添加的垂直线性布局管理器设置一个android:id属性,关键代码如下:

  1. android:id="@+id/linearlayout1"

(2)在主活动MainActivity中,定义一个用于保存要显示图片id的数组(需要将要显示的图片复制到res\drawable文件夹中)和一个垂直线性布局管理器的对象,关键代码如下:

  1. private int imageId[] = new int[] { R.drawable.img01, R.drawable.img02,
  2. R.drawable.img03, R.drawable.img04 }; //定义并初始化一个保存要显示图片id的数组
  3. private LinearLayout l; //定义一个垂直线性布局管理器的对象

(3)在主活动的onCreate()方法中,首先设置显示水平进度条,然后设置要显示的视图,这里为主布局文件main.xml,接下来再获取布局文件中添加的垂直线性布局管理器,关键代码如下:

  1. requestWindowFeature(Window.FEATURE_PROGRESS); //显示水平进度条
  2. setContentView(R.layout.main);
  3. l = (LinearLayout) findViewById(R.id.linearlayout1); //获取布局文件中添加的垂直线性布局管理器

(4)创建继承自AsyncTask的异步类,并重写onPreExecute()、doInBackground()、onProgressUpdate()和onPostExecute()方法,实现在向页面添加图片时,在标题上显示一个水平进度条,当图片载入完毕后,隐藏进度条并显示图片,具体代码如下:

  1. /**
  2. * 功能:创建异步任务,添加4张图片
  3. *
  4. */
  5. class MyTack extends AsyncTask<Void, Integer, LinearLayout> {
  6. @Override
  7. protected void onPreExecute() {
  8. setProgressBarVisibility(true); //执行任务前让进度条可见
  9. super.onPreExecute();
  10. }
  11. /*
  12. * 功能:要执行的耗时任务
  13. */
  14. @Override
  15. protected LinearLayout doInBackground(Void... params) {
  16. LinearLayout ll = new LinearLayout(MainActivity.this); //创建一个水平线性布局管理器
  17. for (int i = 1; i < 5; i++) {
  18. ImageView iv = new ImageView(MainActivity.this); //创建一个ImageView对象
  19. iv.setLayoutParams(new LayoutParams(245, 108));
  20. iv.setImageResource(imageId[i - 1]); //设置要显示的图片
  21. ll.addView(iv); //将ImageView添加到线性布局管理器中
  22. try {
  23. Thread.sleep(10); //为了更好地查看效果,这里让线程休眠10毫秒
  24. } catch (InterruptedException e) {
  25. e.printStackTrace();
  26. }
  27. publishProgress(i); //触发onProgressUpdate(Progress...)方法更新进度
  28. }
  29. return ll;
  30. }
  31. /*
  32. * 功能:更新进度
  33. */
  34. @Override
  35. protected void onProgressUpdate(Integer... values) {
  36. setProgress(values[0] * 2500); //动态更新最新进度
  37. super.onProgressUpdate(values);
  38. }
  39. /*
  40. * 功能:任务执行后
  41. */
  42. @Override
  43. protected void onPostExecute(LinearLayout result) {
  44. setProgressBarVisibility(false); //任务执行后隐藏进度条
  45. l.addView(result); //将水平线性布局管理器添加到布局文件中添加的垂直线性布局管理器中
  46. super.onPostExecute(result);
  47. }
  48. }

(5)在onCreate()方法的最后执行自定义的任务MyTack,具体代码如下:

  1. new MyTack().execute(); //执行自定义任务

运行本实例,首先显示如图4.11所示的页面内容,当图像载入完毕后,再显示如图4.12所示的完成页面。

163-1 图4.11 在标题上显示载入进度条

163-2 图4.12 页面载入完毕的效果

4.1.9 范例2:幻灯片式图片浏览器

例4.10 在Eclipse中创建Android项目,名称为4.10,实现幻灯片式图片浏览器。(实例位置:光盘\TM\sl\4\4.10)

(1)修改新建项目的res\layout目录下的布局文件main.xml,将默认添加的TextView组件删除,并且将默认的线性布局管理器设置为水平居中显示,然后添加一个图像切换器ImageSwitcher组件,并设置其顶部边距,最后添加一个画廊视图Gallery组件,并设置其各选项的间距和未选中项的透明度。修改后的代码如下:

  1. <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
  2. android:orientation="vertical"
  3. android:layout_width="fill_parent"
  4. android:layout_height="fill_parent"
  5. android:gravity="center_horizontal"
  6. android:id="@+id/llayout"
  7. >
  8. <ImageSwitcher
  9. android:id="@+id/imageSwitcher1"
  10. android:layout_weight="2"
  11. android:paddingTop="30px"
  12. android:layout_width="wrap_content"
  13. android:layout_height="wrap_content" >
  14. </ImageSwitcher>
  15. <Gallery
  16. android:id="@+id/gallery1"
  17. android:spacing="5px"
  18. android:layout_weight="1"
  19. android:unselectedAlpha="0.6"
  20. android:layout_width="match_parent"
  21. android:layout_height="wrap_content" />
  22. </LinearLayout>

(2)在主活动MainActivity中,定义一个用于保存要显示图片id的数组(需要将要显示的图片复制到res\drawable文件夹中)和一个用于显示原始尺寸的图像切换器,关键代码如下:

  1. private int[] imageId = new int[] { R.drawable.img01, R.drawable.img02,
  2. R.drawable.img03, R.drawable.img04, R.drawable.img05,
  3. R.drawable.img06, R.drawable.img07, R.drawable.img08,
  4. R.drawable.img09, R.drawable.img10, R.drawable.img11,
  5. R.drawable.img12, }; //定义并初始化保存图片id的数组
  6. private ImageSwitcher imageSwitcher; //声明一个图像切换器对象

(3)在主活动的onCreate()方法中,获取在布局文件中添加的画廊视图和图像切换器,关键代码如下:

  1. Gallery gallery = (Gallery) findViewById(R.id.gallery1); //获取Gallery组件
  2. imageSwitcher = (ImageSwitcher) findViewById(R.id.imageSwitcher1); //获取图像切换器

(4)为图像切换器设置淡入淡出的动画效果,然后为其设置一个ImageSwitcher.ViewFactory对象,并重写makeView()方法,最后为图像切换器设置默认显示的图像,关键代码如下:

  1. //设置动画效果
  2. imageSwitcher.setInAnimation(AnimationUtils.loadAnimation(this,
  3. android.R.anim.fade_in)); //设置淡入动画
  4. imageSwitcher.setOutAnimation(AnimationUtils.loadAnimation(this,
  5. android.R.anim.fade_out)); //设置淡出动画
  6. imageSwitcher.setFactory(new ViewFactory() {
  7. @Override
  8. public View makeView() {
  9. ImageView imageView = new ImageView(MainActivity.this); //实例化一个ImageView类的对象
  10. imageView.setScaleType(ImageView.ScaleType.FIT_CENTER); //设置保持纵横比居中缩放图像
  11. imageView.setLayoutParams(new ImageSwitcher.LayoutParams(
  12. LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT));
  13. return imageView; //返回imageView对象
  14. }
  15. });

(5)创建BaseAdapter类的对象,并重写其中的getView()、getItemId()、getItem()和getCount()方法,其中最主要的是重写getView()方法来设置显示图片的格式,具体代码如下:

  1. BaseAdapter adapter = new BaseAdapter() {
  2. @Override
  3. public View getView(int position, View convertView, ViewGroup parent) {
  4. ImageView imageview; //声明ImageView的对象
  5. if (convertView == null) {
  6. imageview = new ImageView(MainActivity.this); //实例化ImageView的对象
  7. imageview.setScaleType(ImageView.ScaleType.FIT_XY); //设置缩放方式
  8. imageview
  9. .setLayoutParams(new Gallery.LayoutParams(180, 135));
  10. TypedArray typedArray = obtainStyledAttributes(R.styleable.Gallery);
  11. imageview.setBackgroundResource(typedArray.getResourceId(
  12. R.styleable.Gallery_android_galleryItemBackground,
  13. 0));
  14. imageview.setPadding(5, 0, 5, 0); //设置ImageView的内边距
  15. } else {
  16. imageview = (ImageView) convertView;
  17. }
  18. imageview.setImageResource(imageId[position]); //为ImageView设置要显示的图片
  19. return imageview; //返回ImageView
  20. }
  21. /*
  22. * 功能:获得当前选项的id
  23. */
  24. @Override
  25. public long getItemId(int position) {
  26. return position;
  27. }
  28. /*
  29. * 功能:获得当前选项
  30. */
  31. @Override
  32. public Object getItem(int position) {
  33. return position;
  34. }
  35. /*
  36. * 获得数量
  37. */
  38. @Override
  39. public int getCount() {
  40. return imageId.length;
  41. }
  42. };

(6)将步骤(5)中创建的适配器与Gallery关联,并且选中中间的图片,为了将用户选择的图片显示到图像切换器中,还需要为Gallery添加OnItemSelectedListener事件监听器,在重写的onItemSelected()方法中,将选中的图片显示到图像切换器中,具体代码如下:

  1. gallery.setAdapter(adapter); //将适配器与Gallery关联
  2. gallery.setSelection(imageId.length / 2); //选中中间的图片
  3. gallery.setOnItemSelectedListener(new OnItemSelectedListener() {
  4. @Override
  5. public void onItemSelected(AdapterView<?> parent, View view,int position, long id) {
  6. imageSwitcher.setImageResource(imageId[position]); //显示选中的图片
  7. }
  8. @Override
  9. public void onNothingSelected(AdapterView<?> arg0) {}
  10. });

运行本实例,将显示如图4.13示的运行结果,单击某张图片,可以选中该图片,并且让其居中显示,也可以用手指拖动图片来移动图片,并且让选中的图片在上方显示。

166-1 图4.13 幻灯片式图片浏览器

4.2 消息提示框与对话框

tb教学录像:光盘\TM\lx\4\消息提示框与对话框.exe

在Android项目开发中,经常需要将一些临时信息显示给用户,虽然使用前面介绍的基本组件可以达到显示信息的目的,但是这样做不仅会增加代码量,而且对于用户来说也不够友好。为此,Android提供了消息提示框与对话框来显示这些信息。下面将分别介绍消息提示框与对话框的基本应用。

4.2.1 使用Toast显示消息提示框

在前面的实例中,已经应用过Toast类来显示一个简单的消息提示框了。本节将对Toast进行详细介绍。Toast类用于在屏幕中显示一个消息提示框,该消息提示框没有任何控制按钮,并且不会获得焦点,经过一定时间后自动消失。通常用于显示一些快速提示信息,应用范围非常广泛。

使用Toast来显示消息提示框比较简单,只需要经过以下3个步骤即可实现。

(1)创建一个Toast对象。通常有两种方法:一种是使用构造方式进行创建;另一种是调用Toast类的makeText()方法创建。

使用构造方法创建一个名称为toast的Toast对象的基本代码如下:

  1. Toast toast=new Toast(this);

调用Toast类的makeText()方法创建一个名称为toast的Toast对象的基本代码如下:

  1. Toast toast=Toast.makeText(this, "要显示的内容", Toast.LENGTH_SHORT);

(2)调用Toast类提供的方法来设置该消息提示框的对齐方式、页边距、显示的内容等。常用的方法如表4.7所示。

表4.7 Toast类的常用方法

方 法 描 述
setDuration(int duration) 用于设置消息提示框持续的时间,参数值通常使用Toast.LENGTH_LONG或Toast.LENGTH_SHORT
setGravity(int gravity, int xOffset, int yOffset) 用于设置消息提示框的位置,参数gravity用于指定对齐方式;xOffset和yOffset用于指定具体的偏移值
setMargin(float horizontalMargin, float verticalMargin) 用于设置消息提示的页边距
setText(CharSequence s) 用于设置要显示的文本内容
setView(View view) 用于设置将要在消息提示框中显示的视图

(3)调用Toast类的show()方法显示消息提示框。需要注意的是,一定要调用该方法,否则设置的消息提示框将不显示。

下面通过一个具体的实例说明如何使用Toast类显示消息提示框。

例4.11 在Eclipse中创建Android项目,名称为4.11,通过两种方法显示消息提示框。(实例位置:光盘\TM\sl\4\4.11)

(1)修改新建项目的res\layout目录下的布局文件main.xml,为默认添加的垂直线性布局管理器设置一个android:id属性,关键代码如下:

  1. android:id="@+id/ll"

(2)在主活动MainActivity.java的onCreate()方法中,通过makeText()方法显示一个消息提示框,关键代码如下:

  1. Toast.makeText(this, "我是通过makeText()方法创建的消息提示框", Toast.LENGTH_LONG).show();

注意:在最后一定不要忘记调用show()方法,否则该消息提示框将不显示。

(3)通过Toast类的构造方法创建一个消息提示框,并设置其持续时间、对齐方式以及要显示的内容等,这里设置其显示内容为带图标的消息,具体代码如下:

  1. Toast toast=new Toast(this);
  2. toast.setDuration(Toast.LENGTH_SHORT); //设置持续时间
  3. toast.setGravity(Gravity.CENTER, 0, 0); //设置对齐方式
  4. LinearLayout ll=new LinearLayout(this); //创建一个线性布局管理器
  5. ImageView iv=new ImageView(this); //创建一个ImageView
  6. iv.setImageResource(R.drawable.alerm); //设置要显示的图片
  7. iv.setPadding(0, 0, 5, 0); //设置ImageView的内边距
  8. ll.addView(iv); //将ImageView添加到线性布局管理器中
  9. TextView tv=new TextView(this); //创建一个TextView
  10. tv.setText("我是通过构造方法创建的消息提示框"); //为TextView设置文本内容
  11. ll.addView(tv); //将TextView添加到线性布局管理器中
  12. toast.setView(ll); //设置消息提示框中要显示的视图
  13. toast.show(); //显示消息提示框

运行本实例,首先显示如图4.14所示的消息提示框,过一段时间后,该消息提示框消失,然后显示如图4.15所示的消息提示框,再过一段时间,该消息提示框也自动显示消息。

168-1 168-2
图4.14 消息提示框(一) 图4.15 消息提示框(二)

4.2.2 使用Notification在状态栏上显示通知

在使用手机时,当有未接来电或是新短消息时,手机会给出相应的提示信息,这些提示信息通常会显示到手机屏幕的状态栏上。Android也提供了用于处理这些信息的类,它们是Notification和NotificationManager。其中,Notification代表的是具有全局效果的通知;而NotificationManager则是用于发送Notification通知的系统服务。

使用Notification和NotificationManager类发送和显示通知也比较简单,大致可以分为以下4个步骤。

(1)调用getSystemService()方法获取系统的NotificationManager服务。

(2)创建一个Notification对象,并为其设置各种属性。

(3)为Notification对象设置事件信息。

(4)通过NotificationManager类的notify()方法发送Notification通知。

下面通过一个具体的实例说明如何使用Notification在状态栏上显示通知。

例4.12 在Eclipse中创建Android项目,名称为4.12,实现在状态栏上显示通知和删除通知。(实例位置:光盘\TM\sl\4\4.12)

(1)修改新建项目的res\layout目录下的布局文件main.xml,将默认添加的TextView组件删除,然后添加两个普通按钮,一个用于显示通知,另一个用于删除通知。由于此处的布局代码比较简单,这里就不再给出。

(2)在主活动MainActivity.java的onCreate()方法中,调用getSystemService()方法获取系统的NotificationManager服务,关键代码如下:

  1. //获取通知管理器,用于发送通知
  2. final NotificationManager notificationManager =
  3. (NotificationManager) getSystemService(NOTIFICATION_SERVICE);

(3)获取“显示通知”按钮,并为其添加单击事件监听器,在重写的onClick()方法中,首先通过无参的构造方法创建一个Notification对象,并设置其相关属性,然后通过通知管理器发送该通知,接下来通过构造方法Notification(int icon, CharSequence tickerText, long when)创建一个通知,并为其设置事件信息,最后通过通知管理器发送该通知,具体代码如下:

  1. Button button1 = (Button) findViewById(R.id.button1); //获取“显示通知”按钮
  2. //为“显示通知”按钮添加单击事件监听器
  3. button1.setOnClickListener(new OnClickListener() {
  4. @Override
  5. public void onClick(View v) {
  6. Notification notify = new Notification(); //创建一个Notification对象
  7. notify.icon = R.drawable.advise;
  8. notify.tickerText = "显示第一个通知";
  9. notify.when = System.currentTimeMillis(); //设置发送时间
  10. notify.defaults = Notification.DEFAULT_ALL; //设置默认声音、默认振动和默认闪光灯
  11. notify.setLatestEventInfo(MainActivity.this, "无题", "每天进步一点点", null); //设置事件信息
  12. notificationManager.notify(NOTIFYID_1, notify); //通过通知管理器发送通知
  13. //添加第二个通知
  14. Notification notify1 = new Notification(R.drawable.advise2,
  15. "显示第二个通知", System.currentTimeMillis());
  16. notify1.flags|=Notification.FLAG_AUTO_CANCEL; //打开应用程序后图标消失
  17. Intent intent=new Intent(MainActivity.this,ContentActivity.class);
  18. PendingIntent pendingIntent=PendingIntent.getActivity(MainActivity.this, 0, intent, 0);
  19. notify1.setLatestEventInfo(MainActivity.this, "通知",
  20. "查看详细内容", pendingIntent); //设置事件信息
  21. notificationManager.notify(NOTIFYID_2, notify1); //通过通知管理器发送通知
  22. }
  23. });

注意:上面代码中加粗的部分,用于为第一个通知设置使用默认声音、默认振动和默认闪光灯。也就是说,程序中要访问系统闪光灯和振动器,需要在AndroidManifest.xml中声明使用权限,具体代码如下:

  1. <!-- 添加操作闪光灯的权限 -->
  2. <uses-permission android:name="android.permission.FLASHLIGHT"/>
  3. <!-- 添加操作振动器的权限 -->
  4. <uses-permission android:name="android.permission.VIBRATE"/>

另外,在程序中还需要启动另一个活动ContentActivity。因此,也需要在AndroidManifest.xml文件中声明该Activity,具体代码如下:

  1. <activity android:name=".ContentActivity"
  2. android:label="详细内容"
  3. android:theme="@android:style/Theme.Dialog"/>

(4)获取“删除通知”按钮,并为其添加单击事件监听器,在重写的onClick()方法中,删除全部通知,具体代码如下:

  1. Button button2 = (Button) findViewById(R.id.button2); //获取“删除通知”按钮
  2. //为“删除通知”按钮添加单击事件监听器
  3. button2.setOnClickListener(new OnClickListener() {
  4. @Override
  5. public void onClick(View v) {
  6. notificationManager.cancel(NOTIFYID_1); //清除ID号为常量NOTIFYID_1的通知
  7. notificationManager.cancelAll(); //清除全部通知
  8. }
  9. });

(5)由于在为第二个通知指定事件信息时,为其关联了一个Activity,因此,还需要创建该Activity,由于在该Activity中,只需要通过一个TextView组件显示一行具体的通知信息,所以实现起来比较容易,这里不再赘述,详细代码请参见光盘。

运行本实例,单击“显示通知”按钮,在屏幕的右下角将显示第一个通知,如图4.16所示,过一段时间后,该通知消失,并显示第二个通知,再过一段时间后,第二个通知也消失,这时在状态栏上将显示这两个通知的图标,如图4.17所示,单击通知图标,将显示如图4.18所示的通知列表,单击第一个列表项,可以查看通知的详细内容,如图4.19所示,查看后,该通知的图标将不在状态栏中显示。单击“删除通知”按钮,可以删除全部通知。

171-1 171-2
图4.16 单击“显示通知”按钮后显示的通知 图4.17 在状态栏上显示通知图标
171-3 171-4
图4.18 单击状态栏上的通知图标显示通知列表 图4.19 第二个通知的详细内容

4.2.3 使用AlertDialog创建对话框

AlertDialog类的功能非常强大,它不仅可以生成带按钮的提示对话框,还可以生成带列表的列表对话框,概括起来有以下4种:

[√]带确定、中立和取消等N个按钮的提示对话框,其中的按钮个数不是固定的,可以根据需要添加。例如,不需要中立按钮,则可以生成只带有确定和取消按钮的对话框,也可以是只带有一个按钮的对话框。

[√]带列表的列表对话框。

[√]带多个单选列表项和N个按钮的列表对话框。

[√]带多个多选列表项和N个按钮的列表对话框。

在使用AlertDialog类生成对话框时,常用的方法如表4.8所示。

表4.8 AlertDialog类的常用方法

方 法 描 述
setTitle(CharSequence title) 用于为对话框设置标题
setIcon(Drawable icon) 用于通过Drawable资源对象为对话框设置图标
setIcon(int resId) 用于通过资源ID为对话框设置图标
setMessage(CharSequence message) 用于为提示对话框设置要显示的内容
setButton() 用于为提示对话框添加按钮,可以是取消按钮、中立按钮和确定按钮。需要通过为其指定int类型的whichButton参数实现,其参数值可以是DialogInterface. BUTTON_POSITIVE(确定按钮)、BUTTON_NEGATIVE(取消按钮)或者BUTTON_NEUTRAL(中立按钮)

通常情况下,使用AlertDialog类只能生成带N个按钮的提示对话框,要生成另外3种列表对话框,需要使用AlertDialog.Builder类,AlertDialog.Builder类提供的常用方法如表4.9所示。

表4.9 AlertDialog.Builder类的常用方法

方 法 描 述
setTitle(CharSequence title) 用于为对话框设置标题
setIcon(Drawable icon) 用于通过Drawable资源对象为对话框设置图标
setIcon(int resId) 用于通过资源ID为对话框设置图标
setMessage(CharSequence message) 用于为提示对话框设置要显示的内容
setNegativeButton() 用于为对话框添加取消按钮
setPositiveButton() 用于为对话框添加确定按钮
setNeutralButton() 用于为对话框添加中立按钮
setItems() 用于为对话框添加列表项
setSingleChoiceItems() 用于为对话框添加单选列表项
setMultiChoiceItems() 用于为对话框添加多选列表项

下面通过一个具体的实例说明如何应用AlertDialog类生成提示对话框和各种列表对话框。

例4.13 在Eclipse中创建Android项目,名称为4.13,应用AlertDialog类实现带取消、中立和确定按钮的提示对话框,以及带列表、带多个单选列表项和带多个多选列表项的列表对话框。(实例位置:光盘\TM\sl\4\4.13)

(1)修改新建项目的res\layout目录下的布局文件main.xml,将默认添加的TextView组件删除,然后添加4个用于控制各种对话框显示的按钮。由于此处的布局代码比较简单,这里就不再给出。

(2)在主活动MainActivity.java的onCreate()方法中,获取布局文件中添加的第1个按钮,也就是“显示带取消、中立和确定按钮的对话框”按钮,并为其添加单击事件监听器,在重写的onClick()方法中,应用AlertDialog类创建一个带取消、中立和确定按钮的提示对话框,具体代码如下:

  1. Button button1 = (Button) findViewById(R.id.button1); //获取“显示带取消、中立和确定按钮的对话框”按钮
  2. //为“显示带取消、中立和确定按钮的对话框”按钮添加单击事件监听器
  3. button1.setOnClickListener(new View.OnClickListener() {
  4. @Override
  5. public void onClick(View v) {
  6. AlertDialog alert = new AlertDialog.Builder(MainActivity.this).create();
  7. alert.setIcon(R.drawable.advise); //设置对话框的图标
  8. alert.setTitle("系统提示:"); //设置对话框的标题
  9. alert.setMessage("带取消、中立和确定按钮的对话框!"); //设置要显示的内容
  10. //添加“取消”按钮
  11. alert.setButton(DialogInterface.BUTTON_NEGATIVE,"取消", new OnClickListener() {
  12. @Override
  13. public void onClick(DialogInterface dialog, int which) {
  14. Toast.makeText(MainActivity.this, "您单击了取消按钮",Toast.LENGTH_SHORT).show();
  15. }
  16. });
  17. //添加“确定”按钮
  18. alert.setButton(DialogInterface.BUTTON_POSITIVE,"确定", new OnClickListener() {
  19. @Override
  20. public void onClick(DialogInterface dialog, int which) {
  21. Toast.makeText(MainActivity.this, "您单击了确定按钮",Toast.LENGTH_SHORT).show();
  22. }
  23. });
  24. alert.setButton(DialogInterface.BUTTON_NEUTRAL,"中立",new OnClickListener(){
  25. @Override
  26. public void onClick(DialogInterface dialog, int which) {}
  27. }); //添加“中立”按钮
  28. alert.show(); //显示对话框
  29. }
  30. });

(3)在主活动MainActivity.java的onCreate()方法中,获取布局文件中添加的第2个按钮,也就是“显示带列表的对话框”按钮,并为其添加单击事件监听器,在重写的onClick()方法中,应用AlertDialog类创建一个带5个列表项的列表对话框,具体代码如下:

  1. Button button2 = (Button) findViewById(R.id.button2); //获取“显示带列表的对话框”按钮
  2. button2.setOnClickListener(new View.OnClickListener() {
  3. @Override
  4. public void onClick(View v) {
  5. final String[] items = new String[] { "跑步", "羽毛球", "乒乓球", "网球", "体操" };
  6. Builder builder = new AlertDialog.Builder(MainActivity.this);
  7. builder.setIcon(R.drawable.advise1); //设置对话框的图标
  8. builder.setTitle("请选择你喜欢的运动项目:"); //设置对话框的标题
  9. //添加列表项
  10. builder.setItems(items, new OnClickListener() {
  11. @Override
  12. public void onClick(DialogInterface dialog, int which) {
  13. Toast.makeText(MainActivity.this,
  14. "您选择了" + items[which], Toast.LENGTH_SHORT).show();
  15. }
  16. });
  17. builder.create().show(); //创建对话框并显示
  18. }
  19. });

注意:一定不要忘记上面代码中加粗的代码,否则将不能显示生成的对话框。

(4)在主活动MainActivity.java的onCreate()方法中,获取布局文件中添加的第3个按钮,也就是“显示带单选列表项的对话框”按钮,并为其添加单击事件监听器,在重写的onClick()方法中,应用AlertDialog类创建一个带5个单选列表项和一个“确定”按钮的列表对话框,具体代码如下:

  1. Button button3 = (Button) findViewById(R.id.button3); //获取“显示带单选列表项的对话框”按钮
  2. button3.setOnClickListener(new View.OnClickListener() {
  3. @Override
  4. public void onClick(View v) {
  5. final String[] items = new String[] { "标准", "无声", "会议", "户外","离线" };
  6. //显示带单选列表项的对话框
  7. Builder builder = new AlertDialog.Builder(MainActivity.this);
  8. builder.setIcon(R.drawable.advise2); //设置对话框的图标
  9. builder.setTitle("请选择要使用的情景模式:"); //设置对话框的标题
  10. builder.setSingleChoiceItems(items, 0, new OnClickListener() {
  11. @Override
  12. public void onClick(DialogInterface dialog, int which) {
  13. Toast.makeText(MainActivity.this,
  14. "您选择了" + items[which], Toast.LENGTH_SHORT).show(); //显示选择结果
  15. }
  16. });
  17.  
  18. builder.setPositiveButton("确定", null); //添加“确定”按钮
  19. builder.create().show(); //创建对话框并显示
  20. }
  21. });

(5)在主活动中定义一个boolean类型的数组(用于记录各列表项的状态)和一个String类型的数组(用于记录各列表项要显示的内容),关键代码如下:

  1. private boolean[] checkedItems; //记录各列表项的状态
  2. private String[] items; //各列表项要显示的内容

(6)在主活动MainActivity的onCreate()方法中,获取布局文件中添加的第4个按钮,也就是“显示带多选列表项的对话框”按钮,并为其添加单击事件监听器,在重写的onClick()方法中,应用AlertDialog类创建一个带5个多选列表项和一个“确定”按钮的列表对话框,具体代码如下:

  1. Button button4 = (Button) findViewById(R.id.button4); //获取“显示带多选列表项的对话框”按钮
  2. button4.setOnClickListener(new View.OnClickListener() {
  3. @Override
  4. public void onClick(View v) {
  5. checkedItems= new boolean[] { false, true, false,true, false }; //记录各列表项的状态
  6. //各列表项要显示的内容
  7. items = new String[] { "植物大战僵尸", "愤怒的小鸟", "泡泡龙", "开心农场", "超级玛丽" };
  8. //显示带单选列表项的对话框
  9. Builder builder = new AlertDialog.Builder(MainActivity.this);
  10. builder.setIcon(R.drawable.advise2); //设置对话框的图标
  11. builder.setTitle("请选择您喜爱的游戏:"); //设置对话框的标题
  12. builder.setMultiChoiceItems(items, checkedItems,
  13. new OnMultiChoiceClickListener() {
  14. @Override
  15. public void onClick(DialogInterface dialog, int which, boolean isChecked) {
  16. checkedItems[which]=isChecked; //改变被操作列表项的状态
  17. }
  18. });
  19. //为对话框添加“确定”按钮
  20. builder.setPositiveButton("确定", new OnClickListener() {
  21. @Override
  22. public void onClick(DialogInterface dialog, int which) {
  23. String result=""; //用于保存选择结果
  24. for(int i=0;i<checkedItems.length;i++){
  25. if(checkedItems[i]){ //当选项被选择时
  26. result+=items[i]+"、"; //将选项的内容添加到result中
  27. }
  28. }
  29. //当result不为空时,通过消息提示框显示选择的结果
  30. if(!"".equals(result)){
  31. result=result.substring(0, result.length()-1); //去掉最后面的“、”号
  32. Toast.makeText(MainActivity.this,
  33. "您选择了[ "+result+" ]", Toast.LENGTH_LONG).show();
  34. }
  35. }
  36. });
  37. builder.create().show(); //创建对话框并显示
  38. }
  39. });

运行本实例,在屏幕中将显示4个按钮,单击第1个按钮,将弹出带取消、中立和确定按钮的对话框,如图4.20所示;单击第2个按钮,将弹出如图4.21所示的带列表的对话框,单击任何一个列表项,都将关闭该对话框,并通过一个消息提示框显示选取的内容;单击第3个按钮,将显示如图4.22所示的列表对话框,单击“确定”按钮,可关闭该对话框;单击第4个按钮,将显示一个如图4.23所示的带5个多选列表项和一个“确定”按钮的列表对话框,选中多个列表项后,单击“确定”按钮,将显示如图4.24所示的消息提示框显示选取的内容。

175-1 图4.20 带取消、中立和确定按钮的对话框

176-1 176-2
图4.21 带列表的列表对话框 图4.22 带单选列表的列表对话框
176-3 176-4
图4.23 带多选列表的列表对话框 图4.24 消息提示框

4.2.4 范例1:询问是否退出的对话框

例4.14 在Eclipse中创建Android项目,名称为4.14,弹出询问是否退出的对话框。(实例位置:光盘\TM\sl\4\4.14)

(1)修改新建项目的res\layout目录下的布局文件main.xml,将默认添加的TextView组件删除,并设置居中对齐,然后添加一个ImageButton组件,并且设置背景透明,关键代码如下:

  1. <ImageButton
  2. android:id="@+id/exit"
  3. android:layout_width="wrap_content"
  4. android:layout_height="wrap_content"
  5. android:background="#0000"
  6. android:src="@drawable/exit" />

(2)在主活动MainActivity的onCreate()方法中,获取布局文件中添加的第一个按钮,也就是“退出”按钮,并为其添加单击事件监听器,在重写的onClick()方法中,应用AlertDialog类创建一个带取消、中立和确定按钮的提示对话框,具体代码如下:

  1. ImageButton button1 = (ImageButton) findViewById(R.id.exit); //获取“退出”按钮
  2. //为“退出”按钮添加单击事件监听器
  3. button1.setOnClickListener(new View.OnClickListener() {
  4. @Override
  5. public void onClick(View v) {
  6. AlertDialog alert = new AlertDialog.Builder(MainActivity.this)
  7. .create();
  8. alert.setIcon(R.drawable.advise); //设置对话框的图标
  9. alert.setTitle("退出?"); //设置对话框的标题
  10. alert.setMessage("真的要退出泡泡龙游戏吗?"); //设置要显示的内容
  11. //添加“取消”按钮
  12. alert.setButton(DialogInterface.BUTTON_NEGATIVE, "不",
  13. new OnClickListener() {
  14. @Override
  15. public void onClick(DialogInterface dialog, int which) {
  16. }
  17. });
  18. //添加“确定”按钮
  19. alert.setButton(DialogInterface.BUTTON_POSITIVE, "是的",new OnClickListener() {
  20. @Override
  21. public void onClick(DialogInterface dialog,int which) {
  22. finish(); //返回系统主界面
  23. }
  24. });
  25. alert.show(); //显示对话框
  26. }
  27. });

运行本实例,单击“退出”按钮,将弹出如图4.25所示的询问是否退出的提示对话框,单击“不”按钮,不退出游戏;单击“是的”按钮,将退出游戏。

177-1 图4.25 弹出询问是否退出的对话框

4.2.5 范例2:带图标的列表对话框

例4.15 在Eclipse中创建Android项目,名称为4.15,弹出带图标的列表对话框。(实例位置:光盘\TM\sl\4\4.15)

(1)修改新建项目的res\layout目录下的布局文件main.xml,将默认添加的TextView组件删除,然后添加一个用于打开列表对话框的按钮。由于此处的布局代码比较简单,这里就不再给出。

(2)编写用于布局列表项内容的XML布局文件items.xml,在该文件中,采用水平线性布局管理器,并在该布局管理器中添加一个ImageView组件和一个TextView组件,分别用于显示列表项中的图标和文字,具体代码如下:

  1. <?xml version="1.0" encoding="utf-8"?>
  2. <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
  3. android:orientation="horizontal"
  4. android:layout_width="match_parent"
  5. android:layout_height="match_parent">
  6. <ImageView
  7. android:id="@+id/image"
  8. android:paddingLeft="10px"
  9. android:paddingTop="20px"
  10. android:paddingBottom="20px"
  11. android:adjustViewBounds="true"
  12. android:maxWidth="72px"
  13. android:maxHeight="72px"
  14. android:layout_height="wrap_content"
  15. android:layout_width="wrap_content"/>
  16. <TextView
  17. android:layout_width="wrap_content"
  18. android:layout_height="wrap_content"
  19. android:padding="10px"
  20. android:layout_gravity="center"
  21. android:id="@+id/title" />
  22. </LinearLayout>

(3)在主活动MainActivity的onCreate()方法中,创建两个用于保存列表项图片id和文字的数组,并将这些图片id和文字添加到List集合中,然后创建一个SimpleAdapter简单适配器,具体代码如下:

  1. int[] imageId = new int[] { R.drawable.img01, R.drawable.img02,
  2. R.drawable.img03, R.drawable.img04, R.drawable.img05 }; //定义并初始化保存图片id的数组
  3. final String[] title = new String[] { "程序管理", "保密设置", "安全设置",
  4. "邮件设置","铃声设置" }; //定义并初始化保存列表项文字的数组
  5. List<Map<String, Object>> listItems = new ArrayList<Map<String, Object>>(); //创建一个List集合
  6. //通过for循环将图片id和列表项文字放到Map中,并添加到List集合中
  7. for (int i = 0; i < imageId.length; i++) {
  8. Map<String, Object> map = new HashMap<String, Object>(); //实例化map对象
  9. map.put("image", imageId[i]);
  10. map.put("title", title[i]);
  11. listItems.add(map); //将map对象添加到List集合中
  12. }
  13. final SimpleAdapter adapter = new SimpleAdapter(this, listItems,
  14. R.layout.items, new String[] { "title", "image" }, new int[] {
  15. R.id.title, R.id.image }); //创建SimpleAdapter

(4)获取布局文件中添加的按钮,并为其添加单击事件监听器,在重写的onClick()方法中,应用AlertDialog类创建一个带图标的列表对话框,并实现在单击列表项时,获取列表项的内容,具体代码如下:

  1. Button button1 = (Button) findViewById(R.id.button1); //获取布局文件中添加的按钮
  2. button1.setOnClickListener(new View.OnClickListener() {
  3. @Override
  4. public void onClick(View v) {
  5. Builder builder = new AlertDialog.Builder(MainActivity.this);
  6. builder.setIcon(R.drawable.advise); //设置对话框的图标
  7. builder.setTitle("设置:"); //设置对话框的标题
  8. //添加列表项
  9. builder.setAdapter(adapter, new OnClickListener() {
  10. @Override
  11. public void onClick(DialogInterface dialog, int which) {
  12. Toast.makeText(MainActivity.this,
  13. "您选择了[ " + title[which]+" ]", Toast.LENGTH_SHORT).show();
  14. }
  15. });
  16. builder.create().show(); //创建对话框并显示
  17. }
  18. });

运行本实例,单击“打开设置对话框”按钮,将弹出如图4.26所示的选择设置项目的对话框,单击任意列表项,都将关闭该对话框,并通过消息提示框显示选择的列表项内容。

179-1 图4.26 带图标的列表对话框

4.3 经典范例

4.3.1 实现仿Windows 7图片预览窗格效果

例4.16 在Eclipse中创建Android项目,名称为4.16,实现仿Windows 7图片预览窗格效果。(实例位置:光盘\TM\sl\4\4.16)

(1)修改新建项目的res\layout目录下的布局文件main.xml,将默认添加的垂直线性布局管理器修改为水平线性布局管理器,并将TextView组件删除,然后添加一个GridView组件和一个ImageSwitcher组件,并设置GridView组件的宽度和显示列数等。修改后的代码如下:

  1. <GridView android:id="@+id/gridView1"
  2. android:layout_height="match_parent"
  3. android:layout_width="640px"
  4. android:layout_marginTop="10px"
  5. android:horizontalSpacing="3px"
  6. android:verticalSpacing="3px"
  7. android:numColumns="4"
  8. />
  9. <!-- 添加一个图像切换器 -->
  10. <ImageSwitcher
  11. android:id="@+id/imageSwitcher1"
  12. android:padding="20px"
  13. android:layout_width="match_parent"
  14. android:layout_height="match_parent"/>
  15. </LinearLayout>

(2)在主活动MainActivity中,定义一个用于保存要显示图片id的数组(需要将要显示的图片复制到res\drawable文件夹中)和一个图像切换器对象,关键代码如下:

  1. private int[] imageId = new int[] { R.drawable.img01, R.drawable.img02,
  2. R.drawable.img03, R.drawable.img04, R.drawable.img05,
  3. R.drawable.img06, R.drawable.img07, R.drawable.img08,
  4. R.drawable.img09, R.drawable.img10, R.drawable.img11,
  5. R.drawable.img12, }; //定义并初始化保存图片id的数组
  6. private ImageSwitcher imageSwitcher; //声明一个图像切换器对象

(3)在主活动MainActivity的onCreate()方法中,首先获取布局文件中添加的图像切换器,并为其设置淡入淡出的动画效果,然后为其设置一个ImageSwitcher.ViewFactory,并重写makeView()方法,最后为图像切换器设置默认显示的图像,关键代码如下:

  1. imageSwitcher = (ImageSwitcher) findViewById(R.id.imageSwitcher1); //获取图像切换器
  2. //设置动画效果
  3. imageSwitcher.setInAnimation(AnimationUtils.loadAnimation(this,
  4. android.R.anim.fade_in)); //设置淡入动画
  5. imageSwitcher.setOutAnimation(AnimationUtils.loadAnimation(this,
  6. android.R.anim.fade_out)); //设置淡出动画
  7. imageSwitcher.setFactory(new ViewFactory() {
  8. @Override
  9. public View makeView() {
  10. ImageView imageView = new ImageView(MainActivity.this); //实例化一个ImageView类的对象
  11. imageView.setScaleType(ImageView.ScaleType.FIT_CENTER); //设置保持纵横比居中缩放图像
  12. imageView.setLayoutParams(new ImageSwitcher.LayoutParams(
  13. LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT));
  14. return imageView; //返回imageView对象
  15. }
  16. });
  17. imageSwitcher.setImageResource(imageId[6]); //设置默认显示的图像

(4)获取布局文件中添加的GridView组件,具体代码如下:

  1. GridView gridview = (GridView) findViewById(R.id.gridView1); //获取GridView组件

(5)创建BaseAdapter类的对象,并重写其中的getView()、getItemId()、getItem()和getCount()方法,其中最主要的是重写getView()方法来设置显示图片的格式,具体代码如下:

  1. BaseAdapter adapter=new BaseAdapter() {
  2. @Override
  3. public View getView(int position, View convertView, ViewGroup parent) {
  4. ImageView imageview; //声明ImageView的对象
  5. if(convertView==null){
  6. imageview=new ImageView(MainActivity.this); //实例化ImageView的对象
  7. /*************设置图像的宽度和高度******************/
  8. imageview.setAdjustViewBounds(true);
  9. imageview.setMaxWidth(150);
  10. imageview.setMaxHeight(113);
  11. /**************************************************/
  12. imageview.setPadding(5, 5, 5, 5); //设置ImageView的内边距
  13. }else{
  14. imageview=(ImageView)convertView;
  15. }
  16. imageview.setImageResource(imageId[position]); //为ImageView设置要显示的图片
  17. return imageview; //返回ImageView
  18. }
  19. /*
  20. * 功能:获得当前选项的id
  21. */
  22. @Override
  23. public long getItemId(int position) {
  24. return position;
  25. }
  26. /*
  27. * 功能:获得当前选项
  28. */
  29. @Override
  30. public Object getItem(int position) {
  31. return position;
  32. }
  33. /*
  34. * 获得数量
  35. */
  36. @Override
  37. public int getCount() {
  38. return imageId.length;
  39. }
  40. };

(6)将步骤(5)中创建的适配器与GridView关联,并且为了在用户单击某张图片时显示对应的位置,还需要为GridView添加单击事件监听器,具体代码如下:

  1. gridview.setAdapter(adapter); //将适配器与GridView关联
  2. gridview.setOnItemClickListener(new OnItemClickListener() {
  3. @Override
  4. public void onItemClick(AdapterView<?> parent, View view, int position,long id) {
  5. imageSwitcher.setImageResource(imageId[position]); //显示选中的图片
  6. }
  7. });

运行本实例,将显示类似于Windows 7提供的图片预览窗格效果,单击任意一张图片,可以在右侧显示该图片的预览效果,如图4.27所示。

182-1 图4.27 仿Windows 7图片预览窗格效果

4.3.2 状态栏中显示代表登录状态的图标

例4.17 在Eclipse中创建Android项目,名称为4.17,实现仿手机QQ登录状态显示功能。(实例位置:光盘\TM\sl\4\4.17)

(1)修改新建项目的res\layout目录下的布局文件main.xml,将默认添加的布局代码删除,然后添加一个TableLayout表格布局管理器,并且在该布局管理器中添加3个TableRow表格行,接下来在每个表格行中添加用户登录界面相关的组件,最后设置表格的第1列和第4列允许被拉伸。由于此处的代码与第3章的例3.6的布局代码基本相同,所以这里不再给出,具体的代码可以参见本书附带光盘。

(2)在主活动中,定义一个整型的常量(记录通知的id)、一个String类型的变量(记录用户名)和一个通知管理器对象,关键代码如下:

  1. final int NOTIFYID_1 = 123; //第一个通知的id
  2. private String user="匿名"; //用户名
  3. private NotificationManager notificationManager; //定义通知管理器对象

(3)在主活动的onCreate()方法中,首先获取通知管理器,然后获取“登录”按钮,并为其添加单击事件监听器,在重写的onClick()方法中获取输入的用户名并调用自定义方法sendNotification()发送通知,具体代码如下:

  1. //获取通知管理器,用于发送通知
  2. notificationManager = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
  3. Button button1 = (Button) findViewById(R.id.button1); //获取“登录”按钮
  4. //为“登录”按钮添加单击事件监听器
  5. button1.setOnClickListener(new View.OnClickListener() {
  6. @Override
  7. public void onClick(View v) {
  8. EditText etUser=(EditText)findViewById(R.id.user); //获取“用户名”编辑框
  9. if(!"".equals(etUser.getText())){
  10. user=etUser.getText().toString();
  11. }
  12. sendNotification(); //发送通知
  13. }
  14. });

(4)编写sendNotification()方法,在该方法中,首先创建一个AlertDialog.Builder对象,并为其指定要显示对话框的图标、标题等,然后创建两个用于保存列表项图片id和文字的数组,并将这些图片id和文字添加到List集合中,再创建一个SimpleAdapter简单适配器,并将该适配器作为Builder对象的适配器用于为列表对话框添加带图标的列表项,最后创建对话框并显示。sendNotification()方法的具体代码如下:

  1. //发送通知
  2. private void sendNotification() {
  3. Builder builder = new AlertDialog.Builder(MainActivity.this);
  4. builder.setIcon(R.drawable.advise); //设置对话框的图标
  5. builder.setTitle("我的登录状态:"); //设置对话框的标题
  6. final int[] imageId = new int[] { R.drawable.img1, R.drawable.img2,
  7. R.drawable.img3, R.drawable.img4 }; //定义并初始化保存图片id的数组
  8. final String[] title = new String[] { "在线", "隐身", "忙碌中", "离线" }; //定义并初始化保存列表项文字的数组
  9. List<Map<String, Object>> listItems = new ArrayList<Map<String, Object>>(); //创建一个List集合
  10. //通过for循环将图片id和列表项文字放到Map中,并添加到List集合中
  11. for (int i = 0; i < imageId.length; i++) {
  12. Map<String, Object> map = new HashMap<String, Object>(); //实例化map对象
  13. map.put("image", imageId[i]);
  14. map.put("title", title[i]);
  15. listItems.add(map); //将map对象添加到List集合中
  16. }
  17. final SimpleAdapter adapter = new SimpleAdapter(MainActivity.this,
  18. listItems, R.layout.items, new String[] { "title", "image" },
  19. new int[] { R.id.title, R.id.image }); //创建SimpleAdapter
  20. builder.setAdapter(adapter, new DialogInterface.OnClickListener() {
  21. @Override
  22. public void onClick(DialogInterface dialog, int which) {
  23. Notification notify = new Notification(); //创建一个Notification对象
  24. notify.icon = imageId[which];
  25. notify.tickerText = title[which];
  26. notify.when = System.currentTimeMillis(); //设置发送时间
  27. notify.defaults = Notification.DEFAULT_SOUND; //设置默认声音
  28. notify.setLatestEventInfo(MainActivity.this, user,
  29. title[which], null); //设置事件信息
  30. notificationManager.notify(NOTIFYID_1, notify); //通过通知管理器发送通知
  31. //让布局中的第一行不显示
  32. ((TableRow)findViewById(R.id.tableRow1)).setVisibility(View.INVISIBLE);
  33. //让布局中的第二行不显示
  34. ((TableRow)findViewById(R.id.tableRow2)).setVisibility(View.INVISIBLE);
  35. ((Button)findViewById(R.id.button1)).setText("更改登录状态"); //改变“登录”按钮上显示的文字
  36. }
  37. });
  38. builder.create().show(); //创建对话框并显示
  39. }

注意:当用户选择了登录状态列表项后,在显示通知的同时,还需要将布局中的第一行(用于输入用户名)和第二行(用于输入密码)的内容设置为不显示,并且改变“登录”按钮上显示的文字为“更改登录状态”。

(5)在onCreate()方法中,获取“退出”按钮并为其添加单击事件监听器,在重写的onClick()方法中,清除代表登录状态的通知,然后将布局中的第一行和第二行的内容显示出来,并改变“更改登录状态”按钮上显示的文字为“登录”,具体代码如下:

  1. Button button2 = (Button) findViewById(R.id.button2); //获取“退出”按钮
  2. //为“退出”按钮添加单击事件监听器
  3. button2.setOnClickListener(new OnClickListener() {
  4. @Override
  5. public void onClick(View v) {
  6. notificationManager.cancel(NOTIFYID_1); //清除通知
  7. ((TableRow)findViewById(R.id.tableRow1)).setVisibility(View.VISIBLE); //让布局中的第一行显示
  8. ((TableRow)findViewById(R.id.tableRow2)).setVisibility(View.VISIBLE); //让布局中的第二行显示
  9. ((Button)findViewById(R.id.button1)).setText("登录"); //改变“更改登录状态”按钮上显示的文字
  10. }
  11. });

运行本实例,将显示一个用户登录界面,输入用户名(bellflower)和密码(111)后,单击“登录”按钮,将弹出如图4.28所示的选择登录状态的列表对话框,单击代表登录状态的列表项,该对话框消失,并在屏幕的右下角显示代表登录状态的通知,过一段时间后该通知消失,同时在状态栏上显示代表登录状态的图标,单击该图标,将显示通知列表,如图4.29所示。单击“退出”按钮,可以删除该通知。

185-1 图4.28 选择登录状态的列表对话框

185-2 图4.29 在状态栏中显示登录状态

4.4 小 结

本章介绍了用户界面设计中的高级部分,主要分为高级组件和消息提示框与对话框两部分。在高级组件部分,主要介绍了自动完成文本框、进度条、拖动条、星级评分条、选项卡、图像切换器、网格视图和画廊视图等。其中,需要重点掌握的是图像切换器与网格视图和画廊视图的综合应用;在消息提示框与对话框中,主要介绍了如何显示消息提示框、发送并显示通知,以及如何弹出各种对话框。在实际程序开发时,消息提示框和对话框最为常用,需要读者重点掌握,并能做到融会贯通。

4.5 实践与练习

  1. 编写Android程序,实现在页面完全载入前,在标题上显示一个圆形进度条,当页面载入后,隐藏该进度条。(答案位置:光盘\TM\sl\4\4.18)

  2. 编写Android程序,实现带预览的图片浏览器。(答案位置:光盘\TM\sl\4\4.19)

  3. 编写Android程序,应用Alert Dialog实现自定义的登录对话框。(答案位置:光盘\TM\sl\4\4.20)