Android平板电脑开发秘籍

978-7-115-34906-4
作者: 【印度】B.M. Harwani
译者: 戴旭
编辑: 杨海玲

图书目录:

详情

本书虽然名为“平板电脑开发”,其实涵盖了Android开发的方方面面。大部分内容都是讲解Android系统通用的特性,而不区分手机还是平板电脑。在遇到平板电脑和手机的不同点时,作者会特别强调一下。 全书由浅及深,前后连贯性不错,后面章节在用到前面章节已介绍的知识点时会反复提醒,帮助你加深对整个知识体系的理解。所有的示例程序都是可以直接运行的,且会充分利用前面章节已有的代码。

图书摘要

PEARSON

Android平板电脑开发秘籍

The AndroidTM Tablet Developer’s Cookbook

[印度]B.M.Harwani 著

戴旭 译

人民邮电出版社

北京

图书在版编目(CIP)数据

Android平板电脑开发秘籍/(印度)哈瓦尼(Harwani,B.M)著;戴旭译.--北京:人民邮电出版社,2014.6

ISBN 978-7-115-34906-4

Ⅰ.①A… Ⅱ.①哈…②戴… Ⅲ.①移动终端—应用程序—程序设计 Ⅳ.①TN929.53

中国版本图书馆CIP数据核字(2014)第058126号

内容提要

本书虽然名为“平板电脑开发”,其实涵盖了Android开发的方方面面。大部分内容都是讲解Android系统通用的特性,而不区分手机还是平板电脑,如Activity及其生命周期、Intent、Fragment、ActionBar、ContentProvider、Widegt、Notefication、传感器、JSON、Wi-Fi、蓝牙、动画、OpenGL、系统剪贴板、NFC、拍照录音录像、调试和跟踪等。在遇到平板电脑和手机的不同点时,作者会特别强调。

全书由浅及深,前后连贯性很好,后面章节在用到前面章节已介绍的知识点时会反复提醒,帮助读者加深对整个知识体系的理解。书中所有的示例程序都是可以直接运行的,且会充分利用前面章节已有的代码。

作者对很多知识点未做详细解释,所以本书不适合没有任何开发基础的读者阅读。阅读本书需要读者拥有基本的操作系统知识,至少掌握一门面向对象编程语言,了解Androed的基本概念。

◆著 [印度]B.M.Harwani

译 戴旭

责任编辑 杨海玲

责任印制 彭志环 杨林杰

◆人民邮电出版社出版发行  北京市丰台区成寿寺路11号

邮编 100164  电子邮件 315@ptpress.com.cn

网址 http://www.ptpress.com.cn

三河市海波印务有限公司印刷

◆开本:800×1000 1/16

印张:26.75

字数:613千字  2014年6月第1版

印数:1-3500册  2014年6月河北第1次印刷

著作权合同登记号 图字:1-2013-5718号

定价:69.00元

读者服务热线:(010)81055410 印装质量热线:(010)81055316

反盗版热线:(010)81055315

版权声明

Authorized translation from the English language edition,entitled The Android Tablet Develop’s Cookbook,9780321885302 by B.M.Harwani,published by Pearson Education,Inc.,publishing as Addison-Wesley,Copyright © 2013 by Pearson Education,Inc.

All rights reserved.No part of this book may be reproduced or transmitted in any form or by any means,electronic or mechanical, including photocopying,recording or by any information storage retrieval system,without permission from Pearson Education,Inc.

CHINESE SIMPLIFIED language edition published by PEARSON EDUCATION ASIA LTD.and POSTS & TELECOM PRESS Copyright © 2014.

本书中文简体字版由Pearson Education Asia Ltd.授权人民邮电出版社独家出版。未经出版者书面许可,不得以任何方式复制或抄袭本书内容。

本书封面贴有Pearson Education(培生教育出版集团)激光防伪标签,无标签者不得销售。

版权所有,侵权必究。

其他

献给我的母亲Nita Harwani夫人和Martin Cooper博士。

妈妈:您是一位伟大的老师。只要见到您,我就能感受到无上的爱、耐心、奉献、勤奋和感动。

Martin Cooper博士——现代蜂窝电话的发明者——已经给通信技术带来了一场革命。他所投身的研究令人惊叹,推动了手机的发展,让我们在移动中也能联通世界。现在,我们已经无法想象没有手机的日子了,对吧?

前言

Android是Google公司的移动开发平台,它是基于Java的开源、免费平台。作为介于智能手机和电脑之间的产品,平板电脑现在越来越流行。平板电脑的处理器性能优于智能手机,但与电脑相比还是有很大差距。它们比较轻巧,便于携带,你可以用它看视频、听音乐、上网、通过Wi-Fi网络打电话、看电子书、玩游戏、运行App。

Android平板电脑是指那些带有触摸屏、运行Android操作系统的移动设备。随着Android 3.0 SDK的发布,Google加速了Android平板电脑的开发。实际上,Android 3.0 SDK就是专为平板电脑(大屏设备)而设计的。Android 3.0 SDK的诞生促使全球的制造商都来生产Android平板电脑。随着市场上的Android平板电脑蜂拥而至,开发人员也逐渐专注于开发适用于Android平板电脑的App。正是看到了开发Android平板电脑专用App的巨大需求,我才备受鼓舞写下此书。

本书面向的读者

与其他很棒的书一样,本书面向中高级开发人员,为解决实际问题,本书给出了一些易于重用的代码。本书涉及的内容简繁不一,涵盖了开发人员经常碰到的问题。本书适用于想要学习 Android 平板电脑编程的开发人员,以及从事 Android 平板电脑编程教学的教师。总之,如果你想了解有关 Android 平板电脑编程的所有关键领域,或是要迅速解决在开发 Android 应用程序时遇到的各种棘手问题,那么本书将是一本实用的参考手册。

本书的主要内容

本书覆盖面广泛,所有内容都力求深入细节。主要包括以下内容。

Activity及其生命周期。

用Intent启动Activity并在Activity间传送数据。

ListFragment、DialogFragment、PreferenceFragment的显示和使用。

创建Tab式、下拉列表式的ActionBar。

创建自定义Content Provider。

创建逐帧式及补间式动画。

使用加速度传感器、接近度传感器和陀螺仪传感器。

用JSON作为数据交换格式。

开启和关闭Wi-Fi、使用Wi-Fi Direct。

用RemoteView创建并更新主屏幕Widget。

用OpenGL新建并渲染图形。

用系统剪贴板剪切、复制和粘贴文本。

读写NFC电子标签。

用Android Beam传递数据。

实现图形的渐变色填充、旋转、缩放和平移。

用系统内置Intent或自建Java代码进行拍照、录音和录像。

用EasyTracker库和Google Analytics单例(Singleton)对Android应用程序进行跟踪分析。

本书Android已更新至Jelly Bean 4.2。

本书的主要价值

读完本书你将精通以下技能。

根据设备的方向添加和删除Fragment。

实现Fragment间的通信。

在ActionBar中显示Action项、Action View和子菜单。

用StackView创建一堆图片。

用ListPopupWindow和PopupMenu显示选项列表。

拖放文字和图片。

创建和使用状态栏通知。

创建并使用PendingIntent启动Activity。

用Loader访问数据。

用ValueAnimator和ObjectAnimator动画显示View。

用AnimatorSet实现多个动画效果叠加显示。

实现Layout动画。

利用硬件加速提高图形系统的性能。

利用View层和SurfaceView提高图形应用的性能。

用TextureView实现图像变换。

通过蓝牙传输文件。

使用线程和多线程。

使用WebView、WebViewClient类、WebViewFragment显示Web页面。

支持各种不同的Android版本。

支持低版本的Android。

自适应屏幕方向。

Android平板电脑App与手机App的差异。

小屏幕的手机App和平板电脑App间的相互移植。

本书的组织结构

本书由六部分构成。

第一部分:用户界面技术

第1章介绍各种Android平板电脑的尺寸和特点。你将学习Android虚拟设备的创建,了解 Android 项目的目录结构。此外,你还将了解 Activity 及其生命周期中的各个状态,学习用Intent启动Activity、在Activity之间传输数据。

第 2 章重点关注对 Fragment 的理解。你将了解 Fragment 的生命周期,学习创建前台Fragment,还将了解前台 Fragment 和后台 Fragment 的差异,学习根据设备方向添加/删除Fragment,理解FragmentManager和FragmentTransaction如何处理Fragment。此外,你还将学习在运行时动态创建 Fragment,并实现 Fragment 间的通信。最后,你将学习用ListFragment显示可选项、用DialogFragment显示对话框、用PreferenceFragment进行用户设置。

第3章着重理解Android应用程序中ActionBar的使用。你将了解菜单和ActionBar的不同,学习显示/隐藏ActionBar,理解其中各种组件,了解在ActionBar中显示Action项的过程,学习在ActionBar中显示ActionView和子菜单。最后,你将学习在ActionBar中创建Tab式和下拉式列表。

第 4 章着重介绍新 Widget 的使用。你将学习在 Android 应用程序中显示日历、利用NumberPicker显示并选择数字、用StackView创建一堆图片、用ListPopupWindow和PopupMenu显示选项列表。

第二部分:内容管理

第5章将介绍拖放文本和图片以及利用系统剪贴板完成文本的剪切、复制和粘贴。

第6章将介绍Pending Intent以及系统如何广播Intent。你将理解Android的通知系统,学习创建状态栏通知、使用Notification.Builder、获取NotificationManager。最后,你将创建通知并用Pending Intent来启动一个Activity。

第 7 章着重介绍 Loader 的概念。你还将学习内容提供器(Content Provider),学习用CursorLoader访问通信录的内容提供器。最后,你将学习创建一个自定义的Content Provider。

第三部分:多媒体技术

第8章介绍各种不同的动画类型。你将学习用ValueAnimator和ObjectAnimator动画显示 View,用 AnimatorSet 实现多种动画。你还将了解逐帧动画和补间动画。学习应用Layout动画,用AnimationSet来存放和编排动画的步骤。

第9章介绍硬件加速的使用。你将学习View层的使用,用SurfaceView来提高图形类应用程序的性能。最后,你将学习用TextureView来实现图像变换。

第10章介绍了显示图形所需的各种API。你将学习用OpenGL创建并渲染一个矩形。你还将了解顶点着色和打光的区别。此外,你还将学习如何对图形进行渐变色填充、旋转、缩放和平移。

第11章介绍利用系统内置Intent或Java代码来捕获图像的技术。你将学习利用内置Intent或通过Java代码进行录音、录像,了解CamcorderProfile、MediaRecorder对象及其方法。

第四部分:网络和硬件接口

第 12 章着重介绍如何在设备之间建立无线连接。你将学习把两个开启蓝牙的设备配对、用蓝牙在设备之间传输文件、将蓝牙设备与Window PC配对,以及开启蓝牙设备、显示已配对的设备、通过蓝牙传输文件。最后,你将了解Wi-Fi的概念,学习开启/关闭Wi-Fi、使用Wi-Fi Dircet。

第13章介绍多核处理器架构的机制、垃圾回收机制(GC)、线程及多线程、AsyncTask类。

第14章介绍如何改变Android键盘和输入法、了解传感器并显示设备支持的传感器列表,最后学习加速度传感器、接近度传感器和陀螺仪传感器。

第五部分:Web浏览

第 15 章将介绍 JSON 的概念,学习 JSONObject 的使用、JSONObject 的嵌套、用JSONArray存放数据、JsonReader及JsonWriter的使用。

第16章介绍用WebView显示Web页面,以及WebViewClient类和WebViewFragment的使用。

第六部分:Android高级技术

第17章介绍支持多种屏幕和分辨率所要考虑的因素。你将学习Android应用程序如何支持各个版本的系统、Android Support Library如何对低版本Android提供支持,还将学习利用可锚定控件自适应屏幕方向以及定义替代的Layout来应对屏幕方向的变化。

第18章将介绍RemoteView、App Widget和主屏幕Widget,理解App Widget的生命周期方法,学习创建一个主屏幕Widget并通过一个按钮进行刷新,学习用AlarmManager更新主屏幕Widget。

第19章介绍近场通信(NFC)和NFC电子标签(Tag)的功能,了解与NFC电子标签交换信息时所用到的数据结构,学习读写NFC电子标签。最后,你将了解Android Beam并用它传递数据。

第20章介绍应用程序跟踪分析的概念,学习用EasyTracker库和Google Analytics单例跟踪分析Android应用程序。

本书的示例代码

本书提到的所有 Android 技巧都可以在出版商网站 http://www.informit.com/title/9780321885302中下载。下载站点给出的代码包并解压,按照以下步骤来使用这些代码。

(1)启动Eclipse。

(2)选择File>Import,打开Import对话框,然后选择Existing Projects into Workspace,点击Next按钮。

(3)在下一个对话框中,单击Browse按钮找到已解压代码包所在的文件夹。

(4)选中代码包,里面的Android项目将会在Project框中全部列出。默认情况下,所有的项目都会被勾选。你也可以不勾选那些不需导入的项目,然后单击Finish按钮。这样,这些项目就被导入到Eclipse中并可以运行了。

约定

本书所涉及的开发技巧约定了以下3个条件。

除非明确声明,书中所有App的android:minSdkVersion和android:targetSdk-Version属性都约定为11和17。API 级别11和17分别对应Android 3.0(Honeycomb)和Android 4.2(Jelly Bean)。也就是说,本书所有的应用程序需要API级别11以上才能运行,并且编译目标版本是API级别17。

假定res/values文件夹下存在XML文件dimens.xml,其内容如下:

<?xml version="1.0" encoding="utf-8"?>

<resources>

<dimen name="text_size">14sp</dimen>

</resources>

假定res文件夹下存在两个子文件夹:values-sw600dp和values-sw720dp。并且res/values文件夹下的dimens.xml文件已复制到这两个子文件夹中。为了适应 7 英寸和 10 英寸屏幕的平板电脑,在 values-sw600dp 和 values-sw720dp文件夹中的dimens.xml文件内,假定text_size值已设为24sp和32sp。详情请参阅第1章中的“将Android手机应用程序转换为Android平板电脑应用程序”。

致谢

感谢执行编辑Laura Lewin对我的信任,给予我机会写下此书。

感谢开发部编辑Songlin Qiu反馈给我的章节规划,她对改善本书结构、提高本书质量起到了至关重要的作用。

还必须感谢技术校对人员James Becwar、Romin Irani、Prashant Thakkar (Pandhi),感谢他们出色、细致的校对,以及有益的注释和建议。

特别感谢文稿编辑Karen Gill一流的组织和文字编辑工作,感谢她的努力,让本书品质更佳、琅琅上口。

非常感谢助理编辑Olivia Basegio的辛勤工作,并真诚地感谢整个出版团队,是他们让本书得以按时出版。

非常感谢Pearson Technology Group(皮尔森技术集团)的编辑和出版团队,正是他们孜孜不倦的努力才使得本书得以问世。真的很高兴能与他们一起工作。

还要感谢我的家人:我的妻子Anushka、我的孩子Chirag和Naman,他们是我的个人世界,感谢他们给我的鼓舞和激励,感谢他们体谅我在电脑上耗费了大把的时间。

我必须提一下我亲爱的学生,他们已经成了我的好老师。他们那些有趣的问题帮助我理解了读者的需求,启发我在写书时能更加贴近实际。

第3章 Action中的ActionBar

应用程序中绝大多数常用的关键性动作都是通过ActionBar展现出来的。ActionBar可以显示应用程序的Logo、Action项和Action View。ActionBar的显示形式可以是Tab页,也可以是下拉列表。在本章中,我们将学习在Android应用程序中使用ActionBar,并理解它与菜单之间的区别,了解如何启用、显示及隐藏 ActionBar,了解各种 ActionBar 组件,还将学习如何在ActionBar中显示Action项、如何利用程序图标跳转至应用程序的首页,学习显示Action View和ActionBar中的子菜单(Submenu),最后将学习创建Tab页式和下拉列表式的ActionBar。

3.1 技巧:理解菜单和ActionBar之间的区别

ActionBar是一种窗口特性,它替代了Activity顶部的标题栏,可以显示导航栏和重要的程序功能。它为应用程序提供了连贯一致的用户界面。它可以帮助你显示那些常用的关键性Action,这些Action是你需要在程序运行过程中始终保持可见状态的。

菜单也可以帮助你执行应用程序的各种功能,但它有一个缺点:菜单要在按下AVD和设备的Menu按钮之后才会显示并执行。但很多Android设备已不再提供专用的菜单按钮了,因此ActionBar是更合适的替代者。显示在ActionBar内的Action项可以立即被访问到,不需要按下Menu按钮。

默认情况下,ActionBar里左侧是应用程序Logo,右侧是Activity标题和Action项(如果有的话)。Action项与应用程序的菜单项一致。应用程序Logo可以链接到应用程序首页。也就是说,无论位于应用程序中的哪个位置,只要轻点一下Logo,就能跳转到主页。

只要应用程序使用了默认的主题Theme.Holo,且目标(或最低)SDK版本是11以上,ActionBar就是启用状态了。

示例:

<uses-sdk android:targetSdkVersion="11" />

注意 要使用ActionBar,应用程序的minSdkVersion必须大于或等于11,否则会发生编译错误。

3.2 技巧:显示或隐藏ActionBar

为了在运行时显示或隐藏ActionBar,可以使用其show和hide方法,如下所示:

ActionBar actionBar = getActionBar();

actionBar.hide(); // It hides the ActionBar

actionBar.show(); // It makes the ActionBar visible

这里,调用getActionBar()方法获取了ActionBar对象。它的hide()和show()方法将分别实现ActionBar的显示及隐藏。

要隐藏 Activity 中的 ActionBar,还可以通过应用不支持 ActionBars 的主题来实现。在AndroidManifest.xml文件中,可以将Activity的主题设置为Theme.Holo.NoActionBar,如下所示:

<activity android:label="@string/app_name"

android:name=".ActionBarApp"

android:theme="@android:style/Theme.Holo.NoActionBar">

ActionBar 的隐藏和显示将会导致 Layout 的重绘。可以用 android:windowActionBar Overlay属性来避免重绘。如果用了自定义的Theme,可以把android:windowActionBar属性设置为False,以移除ActionBar。

ActionBar中的图标和Logo是否可见,可由setDisplayShowHomeEnabled()方法传入Boolean值来控制。传入False将隐藏ActionBar中的Logo或图标,同理,传入True则会把它们显示出来。如下所示:

actionBar.setDisplayShowHomeEnabled(true);

通过给 setDisplayShowTitleEnabled()方法传入 Boolean 值,可以控制 ActionBar标题的可见性。例如,以下语句将会隐藏ActionBar的标题。

actionBar.setDisplayShowTitleEnabled(false);

3.3 技巧:理解ActionBar组件

ActionBar可由以下组件组成。

应用程序的图标/Logo——显示在ActionBar的左上角。

Activity标题——显示ActionBar的标题。

Tab——如果导航模式设置为Tab,则显示ActionBar Tab(见图3-1中)。

下拉列表——如果导航模式设置为 list navigation,则以下拉列表的方式显示Action项(见图3-1下)。

Action项——显示应用程序的各种功能。为了调用一个模块或者执行一项任务,可以在ActionBar中点击相应的Action项。你还可以把一组相关的Action项整合到一个子菜单中去。

Action View——在ActionBar中显示自定义View。图3-1中以搜索Widget的形式显示了一个Action View。

折叠菜单——显示ActionBar容纳不下的Action项。

折叠菜单按钮——显示为3个竖排的圆点(见图3-1中)。点选后,隐藏的Action项目显示在折叠菜单里。

子菜单——代表一组与某主菜单项相关的菜单项。当某个菜单项时被点击时,它的子菜单(如果存在的话)就会弹出。

3.4 技巧:在ActionBar中显示Action项

为了在ActionBar中显示Action项,需要给菜单项添加android:showAsAction属性,菜单项定义于Menu文件中。showAsAction属性决定了如何显示Action项。showAsAction属性可以是以下值。

always——在ActionBar中显示此Action项。

ifRoom——仅当空间允许时,才在ActionBar中显示此Action项。如果没有足够的空间,此项将显示在Overflow菜单中。

never——总是在Overflow菜单中显示此菜单项。要显示Overflow菜单,请按下AVD的Menu按钮或物理设备的Overflow菜单按钮。

withText——此Action项的标题将与图标(如果有的话)一起显示出来。此属性值可以与其他值组合在一起设置,中间用管道符号“|”分隔。

collapseActionView——使得与Action项关联的Action View可以折叠显示。也就是说,Action View折叠为一个正常Action项的大小。

现在通过运行一个应用程序来学习 ActionBar 的概念。创建一个名为 ActionItemsApp的Android项目。将minSdkVersion和targetSdkVersion属性分别设为14和17。在此应用程序中,将显示两个名为Create和Update的Action项。这两个Action项将显示为ActionBar中的可点击项。可以在菜单文件activity_ action_items_app. xml(文件名由Android项目名称决定)中定义 Action 项。定义完两个 Action 项 Create 和 Update 后,菜单文件activity_action_items_app.xml应该如代码清单3-1所示。

代码清单3-1 写入菜单文件activity_action_items_app.xml的代码

<menu xmlns:android="http://schemas.android.com/apk/res/android" >

<item android:id="@+id/create "

android:title="Create"

android:icon="@drawable/create"

android:orderInCategory="0"

android:showAsAction="ifRoom|withText" />

<item android:id="@+id/update"

android:title="Update"

android:icon="@drawable/update"

android:showAsAction="always" />

</menu>

可以看到,Action项Create被设置为ActionBar空间足够时才显示,且显示标题Create。Action项Update则设为始终显示于ActionBar中。因为要用图标来表示Create和Update项,请把图片文件create.png和update.png复制到应用程序的res/ drawable文件夹中。

现在应用程序可以运行了。不需要在activity_action_items_app.xml Layout文件和ActionItemsAppActivity.java Java Activity文件中添加任何代码。

运行此程序后,将看到两个Action项,如图3-2所示。

如果 Action 项只显示了图标,可以长按(按住不放)此项,由 android:title 属性指定的文字将会以提示信息的形式显示出来。

随着Action项数量的增加,ActionBar中能容纳得下的项将会显示为Action项,其余的会隐藏起来。只要有Action项是不可见的,ActionBar的右侧就会出现一个Overflow菜单按钮。点击这个Overflow菜单按钮后,隐藏的Action项将会就近显示出来。要看到这一现象,请在菜单文件activity_action_items_app.xml中增加Action项的数量,如代码清 单3-2所示。

代码清单3-2 写入菜单文件activity_action_items_app.xml的代码

<menu xmlns:android="http://schemas.android.com/apk/res/android">

<item android:id="@+id/create"

android:title="Create"

android:icon="@drawable/create"

android:orderInCategory="0"

android:showAsAction="ifRoom|withText" />

<item android:id="@+id/update"

android:title="Update"

android:icon="@drawable/update"

android:showAsAction="always" />

<item android:id="@+id/list_rows"

android:title="List Rows"

android:showAsAction="ifRoom" />

<item android:id="@+id/search_row"

android:title="Search"

android:showAsAction="ifRoom" />

<item android:id="@+id/delete_row"

android:title="Delete"

android:showAsAction="never" />

<item android:id="@+id/insert_row"

android:title="Insert"

android:showAsAction="always" />

</menu>

可以看到,这里向ActionBar里添加了4个Action项:List Rows、Search、Delete和Insert。List Row和Search被设为ActionBar空间足够时才显示;否则它们就在Overflow菜单里显示。Delete 项将不会显示在 ActionBar 中,即使有足够的空间也不显示,而是始终显示在 Overflow菜单中。Insert项被设置为一直显示在ActionBar中。

运行此应用程序后,会发现6个Action项中的4个在ActionBar中显示出来了,Overflow菜单按钮显示在右侧。ActionBar中可见的Action项是Create、Update、List Rows和Insert(参见图3-3上)。在点击Overflow菜单按钮之后,隐藏的Action项Search和Delete将会显示在Overflow菜单中(见图3-3下)。

showAsAction属性的collapseActionView值将在“在ActionBar中显示Action View”一节中解释。

3.5 技巧:点击应用程序图标后跳转至应用程序首页

如果用户点击了ActionBar内的Logo或图标,将会跳转至应用程序首页。应用程序首页的意思是应用程序的主Activity,即Activity栈的根成员。

默认情况下,显示在ActionBar中的Logo或图标是不能被点击的。为了让Logo或图标能被点击,必须调用ActionBar的setHomeButtonEnabled()方法,并把Boolean值True传入,如下所示:

actionBar.setHomeButtonEnabled(true);

点击 Logo 或图标意味着点击了一个菜单项,将由 Activity 的事件处理方法(Handler) onOptionsItemSelected来处理。当点击Logo或图标时,将被视作点击了ID为android. R.id.home的菜单项。换句话说,当点击Logo或者图标时,将会调用onOptionItemSelected()方法,android.R.id.home将作为参数被传入。假设当前Activity是CreateActivity,点击图标后要跳转的主Activity或根Activity为ActionItemsAppActivity,代码清单3-3给出了代码。

代码清单3-3 写入Activity文件CreateActivity.java的代码

package com.androidtablet.actionitemsapp;

import android.app.ActionBar;

import android.app.Activity;

import android.content.Intent;

import android.os.Bundle;

import android.view.MenuItem;

public class CreateActivity extends Activity {

@Override

protected void onCreate(Bundle savedInstanceState){

super.onCreate(savedInstanceState);

setContentView(R.layout.create);

ActionBar actionBar = getActionBar();

actionBar.setHomeButtonEnabled(true);

}

@Override

public boolean onOptionsItemSelected(MenuItem item) {   #1

switch (item.getItemId()) {

case (android.R.id.home) :

Intent intent = new Intent(this,

ActionItemsAppActivity.class);

intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);

startActivity(intent);

break;

default:

return super.onOptionsItemSelected(item);

}

return true;

}

}

上述代码假定名为create.xml的Layout文件已存在于res/layout文件夹中。为了能跳转到主Activity,使用了一个名为FLAG_ACTIVITY_CLEAR_TOP的Intent标记,用以关闭所有在主Activity之后启动的Activity。在上述代码中可以看到,通过调用getActionBar()方法获得了ActionBar对象actionBar,Boolean值True被传入了setHomeButtonEnabled()方法,这使得应用程序的Logo可被点击了。点击应用程序的Logo,将会在ID为android.R.id.home的菜单项上生成一个点击事件。在事件处理方法 onOptionsItemSelected()中,将检查 ID 为android.R.id.home的菜单项是否被点击了,也即应用程序的Logo是否被点击。如果是应用程序Logo被点击了,将会跳转至应用程序的主Activity ActionItemsAppActivity.class中,跳转操作是通过清除栈顶所有其他Activity(如果存在的话)来实现的。

在Android 4.1以上的版本中,上述代码中语句#1代表的onOptionsItemSelected方法可以整个去掉。也就是说,只要在 AndroidManifest.xml 文件中加入以下语句,就可以跳转至主Activity中了:

<activity android:name=".CreateActivity" android:label="@string/app_name"

android:parentActivityName="ActionItemsAppActivity"/>

3.6 技巧:在ActionBar中显示Action View

为了更便捷地执行Action,Action View提供了内嵌的控件。从本质上说,Action View允许在ActionBar内放入一个自定义View。Android应用程序最常用的Action View就是SearchView。SearchView提供了一个用户界面,以便输入搜索请求并提交给搜索Provider。如果存在可用的建议项或者结果项,它还能把它们列出来,以便用户能够从中选择。为了能侦测到SearchView中发生的事件,将 setOnQueryTextListener 设为侦听器(Listener),以便在用户输入或改变文本时做出响应。OnQueryTextListener中需要实现两个方法:onQueryTextChange和onQueryTextSubmit。一旦用户改变了搜索文本,onQueryTextChange 方法就会被调用。onQueryTextSubmit则会在用户输入回车或按下搜索按钮时被调用。

为了理解Android应用程序中Action View的使用,请新建一个名为ActionViewApp的Android项目。在此应用程序中,将把SearchView作为Action View显示,用户可以在其中输入要搜索的文本。要显示 SearchView,请把代码清单 3-4 给出的代码写入菜单文件activity_action_view_app.xml,此文件位于res/menu文件夹中。

代码清单3-4 写入菜单文件activity_action_view_app.xml的代码

<menu xmlns:android="http://schemas.android.com/apk/res/android" >

<item android:id="@+id/action_search"

android:title="Search"

android:showAsAction="ifRoom"

android:actionViewClass="android.widget.SearchView"/>

</menu>

通过这段代码,SearchView 将会显示为一个图标,如图 3-4 上所示。通过把android:showAsAction属性做如下设置,还可以让SearchView显示成一个Action项。

android:showAsAction="ifRoom|collapseActionView"

还记得吧,collapseActionView使得与Action项关联的Action View可折叠显示,也就是说,它能让Action View折叠成一个正常Action项显示。现在,SearchView将会显示为一个Action项,如图3-4中所示。不管用图标还是Action项方式,在点击SearchView之后,将会打开一个搜索框,用户可以在其中输入需要搜索的文字(见图3-4下)。

为了理解事件侦听器 setOnQueryTextListener 是如何工作的,将把用户在搜索框中输入或修改的文字显示在日志信息栏(Log Message)中。还会把搜索框中最终录入的文本显示出来。要实现这些任务,请把代码清单 3-5 给出的代码写入 Java Activity 文件 ActionView AppActivity.java。

代码清单3-5 写入Java Activity 文件ActionViewAppActivity.java的代码

package com.androidtablet.actionviewapp;

import android.os.Bundle;

import android.app.Activity;

import android.view.Menu;

import android.view.MenuInflater;

import android.widget.SearchView;

import android.widget.SearchView.OnQueryTextListener;

import android.util.Log;

public class ActionViewAppActivity extends Activity {

@Override

public void onCreate(Bundle savedInstanceState) {

super.onCreate(savedInstanceState);

setContentView(R.layout.activity_action_view_app);

}

@Override

public boolean onCreateOptionsMenu(Menu menu) {

MenuInflater inflater = getMenuInflater();

inflater.inflate(R.menu.activity_action_view_app, menu);

SearchView searchView = (SearchView) menu.findItem(

R.id.action_search).getActionView();

searchView.setOnQueryTextListener(new

OnQueryTextListener(){

@Override

public boolean onQueryTextChange(String newText) {

Log.d("New Text:", newText);

return false;

}

@Override

public boolean onQueryTextSubmit(String query) {

Log.d("Final Text:", query);

return false;

}

});

return true;

}

}

可以看到,这里从菜单文件中获取了ID为action_search 的SearchView Widget,并赋给了SearchView对象searchView。把setOnQueryTextListener与SearchView对象searchView关联起来,这样用户在搜索框中输入或提交文本时,将会采取必要的处理。一旦用户在搜索框中输入或修改文本,onQueryTextChange()方法就会被调用。在onQueryTextChange()方法中,将把搜索框中修改过的文本以日志的方式显示出来。当用户按下回车或搜索按钮完成输入后,将会调用 onQueryTextSubmit()方法,将把搜索框中录入的完整文本通过日志信息显示出来。

运行此应用程序后,将看到以图标方式显示在ActionBar中的SearchView(见图3-5上)。当用户按下ActionBar 中的SearchView时,将会出现一个搜索框,提示需要搜索的文本(见图3-5中)。搜索框中的完整文本将显示在日志信息页中,见图3-5下。

3.7 技巧:在ActionBar中显示子菜单

为了能在ActionBar中显示显示子菜单,需要将子菜单项分组后放入一个<menu>标签中,并将其嵌入欲与子菜单关联的Action项中。让我们假定,你需要创建Create和Update两个Action项。当用户点击Create项时,将会弹出一个子菜单,显示3个子菜单项Create Invoice、Create Customer 和 Create Product。为了理解如何定义 Action 项的子菜单,请新建一个名为ActionBarSubmenu的Android项目。要创建Action项Create和Update,以及Create项中的子菜单,请把代码清单 3-6 中给出的代码写入菜单文件 activity_action_bar_submenu.xml中,此文件位于/res/menu文件夹下。

代码清单3-6 写入菜单文件activity_action_bar_submenu.xml的代码

<menu

xmlns:android="http://schemas.android.com/apk/res/android">

<item android:id="@+id/create"

android:title="Create"

android:orderInCategory="0"

android:showAsAction="ifRoom" >

<menu>

<item android:id="@+id/create_invoice"

android:title="Create Invoice" />

<item android:id="@+id/create_customer"

android:title="Create Customer" />

<item android:id="@+id/create_product"

android:title="Create Product" />

</menu>

</item>

<item android:id="@+id/update"

android:title="Update"

android:showAsAction="always" />

</menu>

可以看到,上述代码包括了android:showAsAction属性,空间足够时将显示ActionBar中的菜单项。Action 项 Create 中的 <menu>元素定义了包含三个菜单项的子菜单:Create Invoice、Create Customer和Create Product。

为了把点击 Action 或菜单项之后的反馈信息显示出来,需要在 Layout 文件 activity_action_bar_submenu.xml中定义一个TextView控件。TextView将会显示文字,标示是哪个Action菜单或Action项被选中了。定义完TextView控件后,Layout文件activity_action_bar_submenu.xml应该如代码清单3-7所示。

代码清单 3-7 写入Layout 文件activity_action_bar_submenu.xml的代码

<LinearLayout

xmlns:android="http://schemas.android.com/apk/res/android"

android:layout_width="match_parent"

android:layout_height="match_parent"

android:orientation="vertical" >

<TextView

android:layout_width="match_parent"

android:layout_height="wrap_content"

android:id="@+id/selectedopt"

android:textSize="@dimen/text_size"

android:textStyle="bold" />

</LinearLayout>

为了在Java代码中标识TextView,它的ID被赋为selectedopt。通过TextView控件显示的文字将会以粗体显示、字体大小为18dp。为了把点击菜单或Action项之后的反馈信息显示出来,请修改ActionBarSubmenuActivity.java,如代码清单3-8所示。其中的代码会显示文字信息,标示是哪个菜单或Action项被选中了。

代码清单3-8 写入Java Activity文件ActionBarSubmenuActivity.java的代码

package com.androidtablet.actionbarsubmenu;

import android.os.Bundle;

import android.app.Activity;

import android.view.Menu;

import android.view.MenuInflater;

import android.view.MenuItem;

import android.widget.TextView;

public class ActionBarSubmenuActivity extends Activity {

private TextView selectedOpt;

@Override

public void onCreate(Bundle savedInstanceState) {

super.onCreate(savedInstanceState);

setContentView(R.layout.activity_action_bar_submenu);

selectedOpt=(TextView)findViewById(R.id.selectedopt);

}

@Override

public boolean onCreateOptionsMenu(Menu menu) {

MenuInflater inflater = getMenuInflater();

inflater.inflate(R.menu.activity_action_bar_submenu, menu);

return true;

}

@Override

public boolean onOptionsItemSelected(MenuItem item) {

switch (item.getItemId()) {

case R.id.create:

selectedOpt.setText("You have selected Create

option");

break;

case R.id.update:

selectedOpt.setText("You have selected Update option");

break;

case R.id.create_invoice:

selectedOpt.setText("You have selected Create

Invoice option");

break;

case R.id.create_customer:

selectedOpt.setText("You have selected Create

Customer option");

break;

case R.id.create_product:

selectedOpt.setText("You have selected Create

Product option");

break;

}

return true;

}

}

为了显示ActionBar,把菜单文件activity_action_bar_submenu.xml中定义的菜单装载或整合进来。这样,从Activity类得到了MenuInflater。对象inflater创建自MenuInflater类,它调用inflater的inflate方法来装载或融合在activity_action_ bar_submenu中定义的菜单。onCreateOptionsMenu()方法将会返回布尔值True,以便让Android显示菜单。

所有被点击的菜单或Action项都会通过onOptionsItemSelected()方法进行处理。选中的菜单或Action项将会作为参数MenuItem传入此方法。可以在Activity中重写此方法,写入点击菜单或Action项后需要执行的代码。在此方法中,读取了所选菜单或Action项的ID,然后执行相应的动作。getItemId()方法将帮助你查找所选菜单或Action项的ID。然后,通过switch语句,把标示所选菜单或Action项的文字信息显示在TextView对象selectedOpt中。

运行此应用程序后,会看到显示在ActionBar 中的Action项Create和Update(见图3-6上)。点击Action项Create后,TextView将会显示信息“You have selected Create option”。点击Action项Create后将会出现一个子菜单,如图3-6中所示。在选择子菜单项后,相应的文字信息将会通过TextView显示出来。例如,选择子菜单项Create Customer后,将会显示文字信息“You have selected Create Customer option”,如图3-6下所示。

你能创建一个可勾选的菜单项吗?当然没问题。

要建立可勾选的菜单项,请把android:checkable属性设为布尔值True。比如,要让子菜单项Create Product成为可勾选项(见图3-6中),可以写入以下代码:

<item android:id="@+id/create_product"

android:title="Create Product"

android:checkable="true" />

这段代码将会让Create Product显示为可勾选的菜单项(参见图3-7上)。

还可以让菜单项显示为单选按钮。也就是说,可以让用户选择一组菜单项中的某一个。一旦选中了某一个,以前选中的菜单项将自动取消。

为了理解单选按钮的概念,请在Action项Update下添加一组互斥的菜单项。这组菜单项显示为Update Code、Update Name和Update Price。这些菜单项将显示为单选按钮,因此其中只有一个菜单项能被选中。当选中了一个菜单项时,之前所选的菜单项都将会自动取消选中。为了把一组互斥的菜单项加入到Action项Update中,请把菜单文件activity_action_bar_submenu.xml修改如代码清单3-9所示。

代码清单3-9 写入菜单文件activity_action_bar_submenu.xml的代码

<menu

xmlns:android="http://schemas.android.com/apk/res/android">

<item android:id="@+id/create"

android:title="Create"

android:orderInCategory="0"

android:showAsAction="ifRoom|withText" >

<menu>

<item android:id="@+id/create_invoice"

android:title="Create Invoice" />

<item android:id="@+id/create_customer"

android:title="Create Customer" />

<item android:id="@+id/create_product"

android:title="Create Product"

android:checkable="true" />

</menu>

</item>

<item android:id="@+id/update"

android:title="Update"

android:showAsAction="always" >

<menu>

<group android:checkableBehavior="single">

<item android:id="@+id/update_code"

android:title="Update Code"

android:checked="true" />

<item android:id="@+id/update_name"

android:title="Update Name" />

<item android:id="@+id/update_price"

android:title="Update Price" />

</group>

</menu>

</item>

</menu>

可以看到,菜单项嵌套在<group>元素中,android:checkableBehavior=single属性与该组关联,确保菜单组中每次只能选中一个菜单项。由此,Update Code、Update Name、Update Price 菜单项将会显示为单选按钮。为了知道选中了哪个单选按钮,请把代码清单 3-10给出的代码写入 ActionBarSubmenuActivity.java 文件。只有以粗体显示的代码是新添加的,其余部分与代码清单3-8一致。

代码清单3-10 写入Java Activity 文件ActionBarSubmenuActivity.java的代码

package com.androidtablet.actionbarsubmenu;

import android.os.Bundle;

import android.app.Activity;

import android.view.Menu;

import android.view.MenuInflater;

import android.view.MenuItem;

import android.widget.TextView;

public class ActionBarSubmenuActivity extends Activity {

private TextView selectedOpt;

@Override

public void onCreate(Bundle savedInstanceState) {

super.onCreate(savedInstanceState);

setContentView(R.layout.activity_action_bar_submenu);

selectedOpt=(TextView)findViewById(R.id.selectedopt);

}

@Override

public boolean onCreateOptionsMenu(Menu menu) {

MenuInflater inflater = getMenuInflater();

inflater.inflate(R.menu.activity_action_bar_submenu, menu);

return true;

}

@Override

public boolean onOptionsItemSelected(MenuItem item) {

switch (item.getItemId()) {

case R.id.create:

selectedOpt.setText("You have selected Create

option");

break;

case R.id.update:

selectedOpt.setText("You have selected Update

option");

break;

case R.id.create_invoice:

selectedOpt.setText("You have selected Create

Invoice option");

break;

case R.id.create_customer:

selectedOpt.setText("You have selected Create

Customer option");

break;

case R.id.create_product:

selectedOpt.setText("You have selected Create

Product option");

break;

case R.id.update_code:

selectedOpt.setText("You have selected Update

Code option");

break;

case R.id.update_name:

selectedOpt.setText("You have selected Update

Name option");

break;

case R.id.update_price:

selectedOpt.setText("You have selected Update

Price option");

break;

}

return true;

}

}

运行此应用程序后,选择Action项Update,将会出现一个子菜单,菜单项Update Code、Update Name和Update Price将以单选按钮方式显示。当选中菜单项时,任何以前选中的菜单项将会取消,对应的文字信息将会由TextView显示出来。例如,当你点击子菜单中的Update Code菜单项时,将会显示文字信息“You have selected Update Code”,如图3-7下所示。

3.8 技巧:创建一个Tab页式的ActionBar

Tab页式的ActionBar类似于自定义事件处理方法的按钮,它被设计成与Fragment Manager一起使用。为了在ActionBar中显示导航Tab页,请调用setNavigationMode()方法,把值ActionBar.NAVIGATION_MODE_TABS作为参数传入,如下所示:

actionBar.setNavigationMode(ActionBar.NAVIGATION_MODE_TABS);

指定了导航模式后,通过调用ActionBar 的addTab()方法可以添加Tab页,如下所示:

actionBar.addTab(actionBar.newTab().setText("Create").setTabListener(this));

以上代码新建了一个Tab页,把它的标题设为“Create”,给它绑定了一个TabListener,最后把新建的Tab页添加到ActionBar中去。例如,这里用setText()方法设置了Tab页的标题。可以调用setIcon()方法来为Tab页定义一个图标。你还可以调用setContentDescription()方法设置Tab页的更多细节信息。

示例:

Tab tab1 = actionBar.newTab();

tabOne.setText("Create")

.setIcon(R.drawable.ic_launcher)

.setContentDescription("Creating the Invoice")

.setTabListener(this));

actionBar.addTab(tab1);

这段代码给ActionBar添加了一个Tab页面,标题为“Create”。与此Tab页关联的图标是默认图标ic_launcher,详细的描述信息是“Creating the Invoice”。当点击Tab页时,事件由TabListener进行处理,完成所需的任务。

现在将通过一个实际的例子来了解 Tab 页式 ActionBar 的概念。请创建一个名为的ActionBarTabApp Android项目。在这个应用程序中,将新建两个Tab页:Create和Update。当选中一个Tab页时,对应的Fragment将会被激活,并显示一段文字信息表示该Fragment被激活了。两个Fragment的View将会通过单独的XML Layout文件显示。因此请在res/layout文件夹下分别添加两个名为createfragment.xml和updatefragment.xml的XML文件。

请在createfragment.xml中写入代码清单3-11给出的代码。

代码清单3-11 写入createfragment.xml文件的代码

<?xml version="1.0" encoding="utf-8"?>

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"

android:layout_width="match_parent"

android:layout_height="match_parent"

android:orientation="vertical" >

<TextView

android:id="@+id/create_textview"

android:layout_width="match_parent"

android:layout_height="wrap_content"

android:text=" This is Create Fragment "

android:textSize="@dimen/text_size"

android:textStyle="bold" />

</LinearLayout>

可以看到,上述Layout文件定义了一个TextView,初始时显示文字“This is Create Fragment”。显示此信息即表示第一个Fragment被激活了。类似地,在updatefragment.xml文件中写入代码清单3-12给出的代码。

代码清单3-12 写入updatefragment.xml文件的代码

<?xml version="1.0" encoding="utf-8"?>

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"

android:layout_width="match_parent"

android:layout_height="match_parent"

android:orientation="vertical" >

<TextView

android:id="@+id/update_textview"

android:layout_width="match_parent"

android:layout_height="wrap_content"

android:text=" This is Update Fragment "

android:textSize="@dimen/text_size"

android:textStyle="bold" />

</LinearLayout>

同样,在Layout文件中为第二个Fragemt定义了一个TextView控件。此TextView初始时显示文字“This is Update Fragment”,表示第二个Fragemt被激活了。

为了在选中Action Tab页时能够显示相应Fragemt的内容,需要在Activity Layout文件中定义一个Fragemt容器。因此,在Activity Layout文件activity_action_bar_tab_app.xml中写入代码清单3-13所示的代码。

代码清单3-13 写入Activity Layout文件activity_action_bar_tab_app.xml的代码

<LinearLayout

xmlns:android="http://schemas.android.com/apk/res/android"

xmlns:tools="http://schemas.android.com/tools"

android:layout_width="match_parent"

android:layout_height="match_parent"

android:orientation="horizontal" >

<LinearLayout

android:id="@+id/fragment_container"

android:layout_width="wrap_content"

android:layout_height="match_parent" />

</LinearLayout>

为了载入两个Fragment的View,请在Android项目的包com.androidtablet.action bartabapp中添加两个Java类文件:CreateActivity.java和UpdateActivity.java。

为了从Layout文件createfragment.xml中载入View,请把代码清单3-14给出的代码写入CreateActivity.java文件。

代码清单3-14 写入CreateActivity.java文件的代码

package com.androidtablet.actionbartabapp;

import android.app.Fragment;

import android.view.View;

import android.view.ViewGroup;

import android.view.LayoutInflater;

import android.os.Bundle;

public class CreateActivity extends Fragment {

@Override

public View onCreateView(LayoutInflater inflater, ViewGroup container,

Bundle savedInstanceState) {

return inflater.inflate(R.layout.createfragment,

container, false);

}

}

同样,为了从Layout文件updatefragment.xml载入View,请把代码清单3-15给出的代码写入UpdateActivity.java文件。

代码清单3-15 写入UpdateActivity.java文件的代码

package com.androidtablet.actionbartabapp;

import android.app.Fragment;

import android.view.View;

import android.view.ViewGroup;

import android.view.LayoutInflater;

import android.os.Bundle;

public class UpdateActivity extends Fragment {

@Override

public View onCreateView(LayoutInflater inflater, ViewGroup

container, Bundle savedInstanceState) {

return inflater.inflate(R.layout.updatefragment, container, false);

}

}

接下来,需要在主 Activity 文件 ActionBarTabAppActivity.java 中写入一些 Java代码,以完成以下任务。

在应用程序中定义两个Tab页:Create和Update。

定义Tab页侦听器并与两个Tab页关联。

当相应的Tab页被点击时,激活Fragment Create和Update。

为了完成上述所有任务,把代码清单3-16所给出的代码写入Java Activity文件ActionBarTab AppActivity.java中。

代码清单3-16 写入Java Activity文件ActionBarTabAppActivity.java的代码

package com.androidtablet.actionbartabapp;

import android.os.Bundle;

import android.app.Activity;

import android.app.ActionBar;

import android.app.ActionBar.Tab;

import android.app.FragmentTransaction;

import android.util.Log;

import android.app.FragmentManager;

import android.app.Fragment;

public class ActionBarTabAppActivity extends Activity {

@Override

public void onCreate(Bundle savedInstanceState) {

super.onCreate(savedInstanceState);

setContentView(R.layout.activity_action_bar_tab_app);

Fragment createFragment = new CreateActivity();

Fragment updateFragment = new UpdateActivity();

ActionBar actionBar = getActionBar();

actionBar.setNavigationMode(ActionBar.NAVIGATION_

MODE_TABS);

actionBar.setDisplayShowTitleEnabled(true);

ActionBar.Tab CreateTab = actionBar.newTab().

setText("Create");

ActionBar.Tab UpdateTab = actionBar.newTab().

setText("Update");

CreateTab.setTabListener(new MyTabsListener(

createFragment));

UpdateTab.setTabListener(new MyTabsListener(updateFragment));

actionBar.addTab(CreateTab);

actionBar.addTab(UpdateTab);

}

protected class MyTabsListener implements ActionBar.

TabListener {

Fragment fragment;

public MyTabsListener(Fragment fragment){

this.fragment = fragment;

}

public void onTabSelected(Tab tab, FragmentTransaction ft) {

ft.replace(R.id.fragment_container, fragment, null);

}

public void onTabUnselected(Tab tab, FragmentTransaction ft) {

ft.remove(fragment);

getFragmentManager().popBackStack(null,

FragmentManager.POP_BACK_STACK_INCLUSIVE);

}

public void onTabReselected(Tab tab, FragmentTransaction ft) {

Log.d("Tab", String.valueOf(tab.getPosition()) +

" re-selected");

}

}

}

可以看到,调用getActionBar()方法创建了ActionBar对象。为了让ActionBar以 Tab页的方式显示,把它的导航模式设成了 ActionBar.NAVIGATION_MODE_TABS。可以在setDisplayShowTitleEnabled()方法传入布尔值False,来隐藏Activity的标题。然后,创建两个标签为Create和Update的Tab页,并添加到ActionBar中。

事件侦听器TabListener与两个Tab页都关联。不管选中哪一个Tab页,onTabSelected()方法都会被调用,并打开预设的Fragment。onTabSelected()方法激活相应的Fragment,把定义于Layout文件的View显示出来。当Tab页被选中时,onTabUnselected ()方法也会被调用,那些没有被选中的Tab页将作为参数传入。与未选中Tab页关联的Fragment将会从堆栈中移除,这些Fragment变为不可见。

onTabUnselected ()方法将显示未选中Tab页的位置[1]。运行此应用程序后,你将看到Tab页式ActionBar显示了两个Tab页:Create和Update。当你选择Create页后,与之相关联的Fragment将会被激活,显示出一条信息“This is Create Fragment”,如图3-8上所示。类似地,在选择Update页后,与之关联的Fragment将会被激活,显示出文字信息“This is Update Fragment”,如图3-8下所示。

3.9 技巧:创建一个下拉列表式的ActionBar

在下拉列表式 ActionBar 中,Action 项以下拉列表的形式显示出来。为了在ActionBar中显示下拉列表,请调用它的 setNavigationMode()方法,把 ActionBar.NAVIGATION_MODE_LIST值作为参数传入,如下所示:

actionBar.setNavigationMode(ActionBar.NAVIGATION_MODE_LIST);

下拉列表以spinner方式显示一个可选项列表,用户只能从中选择一项。为了在下拉列表中显示 Action 项,将使用一个实现了 SpinnerAdapter 接口的适配器;比如,你可能会用ArrayAdapter、SimpleCursorAdapter 或任何 BaseAdapter。在接下来要创建的应用程序中,将使用ArrayAdapter ,因为它是最简单的适配器,可以作为Selection Widget的数据源来使用。可以按照以下步骤来创建应用程序。

(1)定义一个字符串数组,里面包含了需要显示在下拉列表中的字符串。

(2)创建一个ArrayAdapter,把数组中的元素显示为下拉列表项。也就是说,把数组元素封装或加入到spinner下拉列表项中。

(3)把ArrayAdapter赋给ActionBar,以显示Action项。为了把ArrayAdapter赋给ActionBar,并为显示出来的下拉项绑定事件侦听器,需调用 setListNavigationCallbacks()方法,把适配器和OnNavigationListener作为参数传入,如下所示:

String[] items = new String[] { "Create", "Insert", "Update", "Search" };

ArrayAdapter<String> adapter = new ArrayAdapter<String>(this,

android.R.layout.simple_spinner_dropdown_item, items);

ActionBar actionBar = getActionBar();

actionBar.setNavigationMode(ActionBar.NAVIGATION_MODE_LIST);

actionBar.setListNavigationCallbacks(adapter, onNavigationItemSelected);

在上述代码中,定义了一个字符串数组 items,里面包含了需要在下拉列表式 ActionBar中显示的字符串。创建了名为adapter的ArrayAdapter,用于存放字符串数组项,并把数组元素加入到spinner下拉项中。

创建ActionBar对象actionBar,其导航模式设置为ActionBar.NAVIGATION_MODE_LIST。调用 actionBar 的 setListNavigationCallbacks()方法,把 ArrayAdapter、adapter和侦听器onNavigationSelected作为参数传入。给定了回调函数来处理下拉选择动作。如果用户在下拉列表中选择了一个 Action 项,将会调用事件处理方法onNavigationItemSelected,可以在里面编写代码来执行所需的动作。

下面尝试创建一个下拉列表式的 ActionBar。首先创建一个名为 ActionBarListApp 的Android项目。在这个应用程序中,将以下拉列表的形式显示一些Action项。如果其中某项被选中,则相应的日志信息将会显示出来。请在Java Activity文件ActionBarListAppActivity.java中写下代码清单3-17所示的代码。

代码清单3-17 写入Java Activity 文件ActionBarListAppActivity.java的代码

package com.androidtablet.actionbarlistapp;

import android.os.Bundle;

import android.app.Activity;

import android.app.ActionBar.OnNavigationListener;

import android.app.ActionBar;

import android.widget.ArrayAdapter;

import android.util.Log;

public class ActionBarListAppActivity extends Activity {

@Override

public void onCreate(Bundle savedInstanceState) {

super.onCreate(savedInstanceState);

String[] items = new String[] { "Create", "Insert",

"Update", "Search" };

ArrayAdapter<String> adapter = new ArrayAdapter<String>(

this, android.R.layout.simple_spinner_dropdown_item, items);

ActionBar actionBar = getActionBar();

actionBar.setNavigationMode(ActionBar.NAVIGATION_MODE_LIST);

actionBar.setListNavigationCallbacks(adapter,

onNavigationItemSelected);

}

OnNavigationListener onNavigationItemSelected = new

OnNavigationListener() {

@Override

public boolean onNavigationItemSelected(int itemPosition,

long itemId) {

Log.d("Option ", String.valueOf(itemId) +

" is selected");

return true;

}

};

}

这里,你会注意到,当某个下拉列表中的 Action项被选中时,将会调用 onNavigation ItemSelected()方法。onNavigationItemSelected()方法的 itemPosition 和itemId参数包含了选中项的位置和ID。日志信息,即所选Action项ID将会显示出来。ID是连续赋值给下拉列表中的 Action 项的,起始值为 0。为了启用 ActionBar,请不要忘记把AndroidManifest.xml文件中的android:minSdkVersion属性值设置为11以上。

运行此应用程序,可以看到一个Spinner,如图3-9a所示。Spinner将显示下拉列表中的第一个选项:Create。默认的样式会把第一项显示为黑色,这在黑色的背景色下几乎是看不见的。请打开res/values 文件夹中的styles.xml文件,添加一个名为MyActionBar的自定义Style,语句如下:

<style name="MyActionBar" parent="@android:style/Widget.Holo.Light.ActionBar" />

添加完Style后,styles.xml文件将会如代码清单3-18所示。

代码清单3-18 写入styles.xml文件的代码

<resources >

<style name="AppBaseTheme" parent="android:Theme.Light" >

</style>

<style name="AppTheme" parent="AppBaseTheme">

</style>

<style name="MyActionBar" parent="@android:style/Widget.

Holo.Light.ActionBar" />

</resources>

为了在应用程序中应用这个 Style,请打开 AndroidManifest.xml 文件,并把android:theme属性值设置如下:

android:theme="@style/MyActionBar"

这条语句将样式MyActionBar应用到应用程序中。现在屏幕输出将会如图3-9b所示。

当你点击Spinner时,将会打开一个下拉列表,所有的可选Action项将会显示出来(见图3-9c)。选中Action项Update,它将显示为Spinner的第一项(见图3-9d),以告知用户它被选中了。

图 3-10 给出了从下拉列表选中 Update 和 Create Action 项之后的日志信息。利用onNavigationItemSelected()方法的itemId参数把选中下拉项的ID显示出来。

3.10 小结

在本章中,我们见识了 ActionBar 在显示程序主要 Action 时的用途,学习了显示和隐藏ActionBar、理解了各种组件的运作,了解了在ActionBar中显示Action项和Action View的过程。还学习了如何在ActionBar中显示子菜单以及如何创建Tab页式和下拉列表式的ActionBar。

下一章将学习自API 11开始引入的新增Widget。你将学习通过CalendarView在Android应用程序中显示日历、通过 NumberPicker 显示一定范围内的数字,还将学习利用StackView Widget显示一叠图片,最后将学习通过ListPopupWindow显示选项列表、通过PopupMenu显示建议项。

[1].这句原文如此,可能是作者笔误。对照上面的代码,应该是onTabReselected()方法会显示重新被选中的Tab页的位置。——译者注

相关图书

Android App开发入门与实战
Android App开发入门与实战
Kotlin入门与实战
Kotlin入门与实战
Android 并发开发
Android 并发开发
Android APP开发实战——从规划到上线全程详解
Android APP开发实战——从规划到上线全程详解
Android应用案例开发大全( 第4版)
Android应用案例开发大全( 第4版)
深入理解Android内核设计思想(第2版)(上下册)
深入理解Android内核设计思想(第2版)(上下册)

相关文章

相关课程