Android 学习之路 之 第2组UI组件:TextView及其子类(十)

前面介绍了 Android 界面编程的一些基础知识,接下来将要介绍的是 Android 基本界面组件。“九层之台,起于垒土” —— 无论看上去多么美观的 UI 界面,开始都是先创建容器(ViewGroup 的实例),然后不断地向容器中添加界面组件,最后形成一个美观的 UI 界面。掌握这些基本用户界面组件时学好 Android 编程的基础。

1,文本框(TextView)与编辑框(EditText)的功能和用法

TextView 直接继承了 View,它还是 EditText、Button 两个 UI 组件类的父类。TextView 的作用就是在界面上显示文本 —— 从这个意义上来看,它有点类似于 Swing 编程中的 JLabel,不过它比 JLabel  功能更强大。

从功能上看,TextView 其实就是一个文本编辑器,只是 Android 关闭了它的编辑功能。如果开发者想要定义一个可以编辑内容的文本框,则可以使用它的子类:EditText,EditText 允许用户编辑文本框中内容。

TextView 还派生了一个 CheckedTextView,CheckedTextView 增加了一个 checked 状态,开发者可通过 setChecked(boolean) 和 isChecked() 方法来改变、访问该组件的 checked 状态。除此之外,该组件还可通过 setCheckMarkDrawable() 方法来设置它的勾选图标。

不仅如此,TextView 还派生出了 Button 类,TextView 类及其子类的类图如图 2.16 所示。


TextView 和 EditText 具有很多相似之处,它们之间的最大的区别在于 TextView 不允许用户编辑文本内容,而 EditText 则允许用户编辑文本内容。

TextView 提供了大量的 XML 属性,这些 XML 属性大部分不仅可适用于 TextView,而且可适用于它的子类(EditText、Button 等)。表 2.13 显示了 TextView 支持的 XML 属性及相关方法的说明。






下面通过系列实例来介绍 TextView 和 CheckedTextView 的用法。

由于 TextView 提供了大量 XML 属性,因此我们可以通过这些 XML 属性来控制 TextView 中文本的行为,例如如下界面布局文件。

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
	android:orientation="vertical"
	android:layout_width="fill_parent"
	android:layout_height="fill_parent"
	>
	<!-- 设置字体为20pt,文本框结尾处绘制图片  -->
	<TextView
	android:layout_width="fill_parent" 
	android:layout_height="wrap_content" 
	android:text="我爱Java"
	android:textSize="20pt"
	android:drawableEnd="@drawable/ic_launcher"
	/>
	<!-- 设置中间省略, 所有字母大写 -->
	<TextView
	android:layout_width="fill_parent" 
	android:layout_height="wrap_content"
	android:singleLine="true" 
	android:text="我爱Java我爱Java我爱Java我爱Java我爱Java我aaaJava"
	android:ellipsize="middle"
	android:textAllCaps="true"
	/>
	<!-- 对邮件、电话增加链接 -->
	<TextView
	android:layout_width="fill_parent" 
	android:layout_height="wrap_content"
	android:singleLine="true" 
	android:text="邮件是kongyeeku@163.com,电话是02088888888"
	android:autoLink="email|phone"
	/>
	<!-- 设置文字颜色 、大小,并使用阴影 -->
	<TextView
	android:layout_width="fill_parent" 
	android:layout_height="wrap_content" 
	android:text="测试文字"
	android:shadowColor="#0000ff"
	android:shadowDx="10.0"
	android:shadowDy="8.0"
	android:shadowRadius="3.0"
	android:textColor="#f00"
	android:textSize="18pt"
	/>
	<!-- 测试密码框 -->
	<TextView android:id="@+id/passwd"
	android:layout_width="fill_parent" 
	android:layout_height="wrap_content" 
	android:text="@string/hello"
	android:password="true"
	/>
	<!-- 测试CheckedTextView
	通过checkMark设置该文本框的勾选图标
	 -->
	<CheckedTextView
	android:layout_width="fill_parent" 
	android:layout_height="wrap_content"
	android:text="可勾选的文本"
	android:checkMark="@drawable/ok"    
	    />
</LinearLayout>

上面的界面布局文件中定义了 6 个 TextView,它们指定的规则如下。

第 1 个 TextView 指定 android:textSize="20pt",则就指定了字号为 20pt。且指定了在文本框结尾处绘制图片。

第 2 个 TextView 指定 android:ellipsize="middle",则就指定了当文本多余文本框的宽度时,从中间省略文本。而且指定了 android:textAllCaps="true',表明该文本框的所有字母大写。

第 3 个 TextView 指定 android:autoLink="email|phone",这就指定了该文本框会自动为文本框的 E-mail 地址、电话号码添加超链接。

第 4 个 TextView 指定系列 android:shadowXXX 属性,这就为该文本框内的文本内容添加了阴影。

第 5 个 TextView 制度能够 android:password="true" ,这就指定了该文本框会用点来代替显示所有字符。

第 6 个 CheckedTextView 指定 android:checkMark="@drawable/ok",这就制度能够了该可勾选文本框的勾选图标。

使用 Activity 来显示上面的布局文件,将看到如图 2.17 所示的界面。


默认情况下,TextView 是不带边框的,如果想为 TextView 添加边框,只能通过“曲线救国” 的方式来实现 —— 我们可以考虑为 TextView 设置一个背景 Drawable,该 Drawable 只是一个边框,这样就实现了带边框的 TextView。

由于可以为 TextView 设置背景 Drawable 对象,因此可以在定义 Drawable 时不仅指定边框,还可以指定渐变背景,这样既可为 TextView 添加渐变背景和边框。

下面的界面布局文件中定义了两个 TextView,界面布局文件的代码如下。

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
	android:orientation="vertical"
	android:layout_width="fill_parent"
	android:layout_height="fill_parent"
	>
<!-- 通过android:background指定背景 -->
<TextView
	android:layout_width="fill_parent" 
	android:layout_height="wrap_content"
	android:text="带边框的文本"
	android:textSize="24pt"
	android:background="@drawable/bg_border"
	/>
<!-- 通过android:drawableLeft绘制一张图片 -->	
<TextView  
	android:layout_width="fill_parent"
	android:layout_height="wrap_content"
	android:text="圆角边框、渐变背景的文本"
	android:textSize="24pt"
	android:background="@drawable/bg_border2"
	/>
</LinearLayout>

上面的界面布局文件中定义了两个 TextView,其中第一个指定了背景,第二个定义文本框时指定使用圆角边框、渐变背景。第一个文本框所指定的背景是由 XML 文件定义的,将该文件放在 drawable_mdpi 文件夹内,该 XML 文件也可当成 Drawable 使用。下面是该 XML 文件的代码。

<?xml version="1.0" encoding="UTF-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android">
    <!-- 设置背景色为透明色 -->
	<solid android:color="#0000"/>
	<!-- 设置红色边框 -->
	<stroke android:width="4px" android:color="#f00" />
</shape>

第二个文本框所指定的背景是由 XML 文件定义的,将该文件放在 drawable_mdpi 文件夹内,该 XML 文件也可当成 Drawable 使用。下面是该 XML 文件的代码。

<?xml version="1.0" encoding="UTF-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
    android:shape="rectangle">
    <!-- 指定圆角矩形的4个圆角的半径 -->
   	<corners android:topLeftRadius="20px"
    android:topRightRadius="5px"
    android:bottomRightRadius="20px"
    android:bottomLeftRadius="5px"/>
   	<!-- 指定边框线条的宽度和颜色 -->
	<stroke android:width="4px" android:color="#f0f" />
	<!-- 指定使用渐变背景色,使用sweep类型的渐变
	颜色从红色→绿色→蓝色 -->
	<gradient android:startColor="#f00"
	    android:centerColor="#0f0"
	    android:endColor="#00f"
	    android:type="sweep"/>
</shape>

使用 Activity 来显示上面定义的布局页面,可以看到如图 2.18 所示界面。

从图 2.18 不难看出,通过为 TextView 的 android:background 赋值,可以为文本增加大量自定义外观,这种控制方式非常灵活。


需要指出的是,表面上这里只是在介绍 TextView,但由于 TextView 是 EditText、Button 等类的父类,因此此处介绍的对 TextView 控制的属性,同样适用于EditText 与 Button。

2,EditText 的功能与用法

EditText 与 TextView 非常相似,它甚至与 TextView 共用了绝大部分 XML 属性和方法。EditText 与 TextView 的最大区别在于:EditText 可以接受用户输入。表 2.13 中介绍的与输入相关的属性主要就是为 EditText 准备的。

EditText 组件最重要的属性时 inputType,该属性相当于 HTML 的 <input.../> 元素的 type 属性,用于 EditText 为指定类型的输入组件。inputType 能接受的属性非常丰富,而且随着 Android 版本的升级,该属性能接受的类型还会增加。

EditText 还派生了如下两个子类。

AutoCompleteTextView:带有自动完成功能的 EditText,实际上该组件的命令不太恰当。笔者认为该类名应该叫 AutoCompleteEditText 比较合适。由于该类通常需要与 Adapte 结合使用,因此将会在介绍 AdapteView 组件时介绍该组件的用法。

ExtractEditText:它并不是 UI 组件,而是 EditText 组件的底层服务类,负责提供全屏输入法支持。

下面通过一个实例来介绍 EditText 的用法。

对于一个用户友好的输入界面而言,接受用户输入的文本框内默认会提示用户如何输入;当用户把焦点切换到输入框时,输入框自动选中其中已输入的内容,避免用户删除已有内容;当用户把焦点切换到只接受电话号码的输入框时,输入法自动切换到数字键盘。

下面程序的输入界面完成了以上功能,输入界面的界面布局如下。

<?xml version="1.0" encoding="utf-8"?>
<TableLayout xmlns:android="http://schemas.android.com/apk/res/android"
	android:orientation="vertical"
	android:layout_width="fill_parent"
	android:layout_height="fill_parent"
	android:stretchColumns="1"
	>
<TableRow>
<TextView
	android:layout_width="fill_parent"
	android:layout_height="wrap_content"
	android:text="用户名:"
	android:textSize="16sp"
	/>	
<EditText
	android:layout_width="fill_parent"
	android:layout_height="wrap_content"
	android:hint="请填写登录帐号"
	android:selectAllOnFocus="true"
	/>
</TableRow>
<TableRow>
<TextView
	android:layout_width="fill_parent"
	android:layout_height="wrap_content"
	android:text="密码:"
	android:textSize="16sp"	
	/>
<!-- android:inputType="numberPassword"表明只能接收数字密码 -->
<EditText
	android:layout_width="fill_parent"
	android:layout_height="wrap_content"
	android:inputType="numberPassword"
	/>
</TableRow>
<TableRow>
<TextView
	android:layout_width="fill_parent"
	android:layout_height="wrap_content"
	android:text="年龄:"
	android:textSize="16sp"	
	/>
<!-- inputType="number"表明是数值输入框 -->
<EditText
	android:layout_width="fill_parent"
	android:layout_height="wrap_content"
	android:inputType="number"
	/>
</TableRow>
<TableRow>
<TextView
	android:layout_width="fill_parent"
	android:layout_height="wrap_content"
	android:text="生日:"
	android:textSize="16sp"	
	/>
<!-- inputType="date"表明是日期输入框 -->
<EditText
	android:layout_width="fill_parent"
	android:layout_height="wrap_content"
	android:inputType="date"
	/>
</TableRow>
<TableRow>
<TextView
	android:layout_width="fill_parent"
	android:layout_height="wrap_content"
	android:text="电话号码:"
	android:textSize="16sp"	
	/>
<!-- inputType="phone"表明是输入电话号码的输入框 -->
<EditText
	android:layout_width="fill_parent"
	android:layout_height="wrap_content"
	android:hint="请填写您的电话号码"
	android:selectAllOnFocus="true"
	android:inputType="phone"
	/>
</TableRow>
<Button 
	android:layout_width="wrap_content"
	android:layout_height="wrap_content"
	android:text="注册"
	/>
</TableLayout>

上面的界面布局中第一个文本框通过 android:hint 指定了文本框的提示信息:请填写登录账户 —— 这是文本框默认的提示,当用户还没有输入时,该文本框内默认显示这段信息;第二个输入框通过 android:inputType="numberPassword" 设置这是一个密码框,而且只能接受数字密码,用户在该文本框输入的字符会以点号代替;第三个输入框通过 android:inputType="number" 设置为只能接受数字的输入框;第四个输入框通过 android:inputType="date" 指定它是一个日期选输入框;第五个输入框通过 android;inputType="phone" 设置为一个电话号码输入框。

使用 Activity 显示上面的界面布局将可看到如图 2.19 所示的界面。


从图 2.19 可以看出,当用户把焦点定位到数字密码输入框时,系统自动显示数字输入键盘,这就是设置 android:inputType="numberPassword" 的作用。第一个编辑框默认显示了 “请填写登录账户”,这是由 android:hint 属性指定的。

3,按钮(Button)组件的功能和用法

Button 继承了 TextView,它主要是在 UI 界面上生成一个按钮,该按钮可以供用户单击,当用户单击按钮时,按钮会触发一个 onClick 事件。关于 onClick 事件编程的简单示例,本书前面已经见过很多,后面还会详细介绍 Android 的事件编程。

按钮使用起来比较容易,可以通过为按钮指定 android:background 属性为按钮增加背景颜色或背景图片,如果将背景图片设为不顾则的背景图片随用户动作动态改变,则可以考虑使用自定义 Drawable 对象来实现。

下面通过实例来开发出更强大的按钮。

为了定义图片随用户动作改变的按钮,可以考虑使用 XML 资源文件来定义 Drawable 对象,再将 Drawable 对象设为 Button 的 android:background 属性值,或设为 ImageButton 的 android:src 属性值。

例如有如下界面布局文件。

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
	android:orientation="vertical"
	android:layout_width="fill_parent"
	android:layout_height="fill_parent"
	>
<!-- 文字带阴影的按钮 -->	
<Button
	android:layout_width="wrap_content"
	android:layout_height="wrap_content"
	android:text="文字带阴影的按钮"
	android:textSize="12pt"
	android:shadowColor="#aa5"
	android:shadowRadius="1"
	android:shadowDx="5"
	android:shadowDy="5"
/>	
<!-- 普通文字按钮 -->	
<Button
	android:layout_width="wrap_content"
	android:layout_height="wrap_content"
	android:background="@drawable/red"
	android:text="普通按钮"
	android:textSize="10pt"
/>
<!-- 带文字的图片按钮-->
<Button
	android:layout_width="wrap_content"
	android:layout_height="wrap_content"
	android:background="@drawable/button_selector"
	android:textSize="11px"
	android:text="带文字的图片按钮"
/>
</LinearLayout>

上面的界面布局中第一个按钮时一个普通按钮,但为该按钮的文字指定了阴影 —— 配置阴影的方式与为 TextView 配置阴影的方式完全相同,这是因为 Button 的本质还是 TextView。第二个按钮通过 background 属性配置了背景图片,因此该按钮将会显示为背景图片形状的按钮。

第三个按钮有点特殊,它指定了 android:background 属性为 @drawable/button_selector,该属性值引用一个 Drawable 资源,该资源对应的 XML 文件如下。

<?xml version="1.0" encoding="UTF-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
	<!-- 指定按钮按钮下时的图片 -->
	<item android:state_pressed="true"
		android:drawable="@drawable/red"
	/>
	<!-- 指定按钮松开时的图片 -->	
	<item android:state_pressed="false"
		android:drawable="@drawable/purple"
	/>
</selector>

上面的资源文件使用 <selector.../> 元素定义了一个 StateListDrawable 对象 —— 本书后面会详细介绍如何使用 XML 文件来定义 Drawable 的内容,此处不再深入讲解。

使用 Activity 显示上面的布局文件,可以看到如图 2.20 所示的界面。


在图 2.20 所示界面的三个按钮中,前两个按钮的背景色、图片都是固定的,用户单击该按钮不会看到任何改变;用户按下后面两个按钮时,将会看到按钮的图片被切换成红色。

以笔者的经验来看,Button 生成的按钮功能很强大,就像第三个按钮就是 Button 生成的,而且它也可以通过背景色来设置图片,因此使用 Button 生成的按钮不仅可以是普通的文字按钮,也可以定制成任意形状,并可以随用户交互动作改变外观。

4,使用 9Patch 图片作为按钮背景

从图 2.20 的第三个按钮来看,当按钮的内容太多时,Android 会自动缩放整张图片,以保证背景图片能覆盖整个按钮。但这种缩放整张的效果可能并不好。可能需要的情况是我们只想缩放图片中某个部分,这样才能保证按钮的视觉效果。

为了实现只缩放图片中某个部分的效果,我么您需要借助于 9Patch 图片来实现。9Patch 图片是一种特殊的 PNG 图片,这种图片 .9.png 结尾,它在原始图片四周各添加一个宽度为 1 像素的线条,这 4 条线就决定了该图片的缩放规则、内容显示规则。

左侧和上侧的直线共同决定了图片的缩放区域:以左边直线为左边界绘制矩形,它覆盖的区域可以在纵向缩放;以上面直线为上边界绘制矩形,它覆盖的区域可以水平缩放;它们二者的交集可以在两个方向上缩放。图 2.21 显示了定义图片缩放区域的示意。

右侧和下侧的直线共同决定图片的内容显示区域;以右边直线为右边界绘制矩形,以下边直线为下边界绘制矩形,它们二者的交集就是图片的内容显示区域。图 2.22 显示了定义图片内容显示区域的示意。

Android 为制作 9Patch 图片提供了 draw9patch 工具,该工具位于 Android SDK 安装路径的 tools 目录下,进入该目录双击 draw9patch.bat 文件,即可启动该工具。



如果启动该程序时提示 java.lang.NoClassDefFoundError: org/jdesktop/swingworkder/SwingWorkder 异常。可能的原因是 draw9patch.bat 工具需要依赖于 SwingWorker 类,这个类在 JDK 1.5 以前需要单独下载 swing-worker 的 JAR 包,但从 JDK 1.6 以后,该类已经加入了 javax.swing 包下,但 Android SDK 还在使用早期的 SwingWorker,而且 Android SDK 又删除了 swing-worker-1.1.jar 包,所以引发上面的错误。为了能正常启动 draw9patch.bat,手动将 swing-worker-1.1.jar 复制到 Android SDK 安装路径的 tools/lib 路径下即可。

启动 draw9patch.bat 以后,通过该工具主菜单的 “File → Open 9 - Patch” 菜单项打开一张 PNG 图片,然后通过该工具定义图片的缩放区域、内容显示区域。图 2.23 显示了定义 9Patch 图片的示意。


将上面生成的图片保存到应用的 res/drawable-mdpi 路径下,主文件名任意,draw9patch.bat 自动将该文件的后缀保存为 .9.png。

定义 9Patch 图片之后,接下来在应用中定义两个按钮,分别使用原始图片和 9Patch 图片作为 Button 的背景。页面定义比较比较简单,此处不再赘述。普通图片为背景的按钮及 9Patch 图片为背景的按钮的界面如图 2.24 所示。


从图 2.24 可以看出,普通图片作为背景时,整张图片都被缩放了,如果使用 9Patch 图片作为背景,则只有指定区域才会被缩放。

5,单选按钮(RadioButton)与复选框(CheckBox)的功能与用法

单选按钮(RadioButton)和复选框(CheckBox)、状态开关按钮(ToggleButton)与开发(Switch)是用户界面中最普通的 UI 组件,它们都继承了 Button 类,因此都可直接使用 Button 支持的各种属性和方法。

RadioButton、CheckBox 与普通按钮不同的是,它们多了一个可选中的功能,因此 RadioButton、CheckBox 都可额外指定一个 android:checked 属性,该属性用于指定 RadioButton、CheckBox 初始时是否被选中。

RadioButton 与 CheckBox 的不同之处在于,一组 RadioButton 只能选中其中一个,因此 RadioButton 通常要与 RadioButton 一起使用,用于定义一组单选按钮。

下面通过实例来界面 RadioButton 和 CheckBox 的用法。

在需要获取用户信息的界面中,有些信息不需要用户直接输入,可以考虑让用户进行选择,比如用户的性别、爱好等。下面的界面布局文件定义了一个让用户选择的输入界面。

<?xml version="1.0" encoding="utf-8"?>
<TableLayout xmlns:android="http://schemas.android.com/apk/res/android"
	android:orientation="vertical"
	android:layout_width="fill_parent"
	android:layout_height="fill_parent">
<TableRow>
<TextView 
	android:layout_width="wrap_content"
	android:layout_height="wrap_content"
	android:text="性别:"
	android:textSize="16px"
	/>
<!-- 定义一组单选框 -->
<RadioGroup android:id="@+id/rg"
	android:orientation="horizontal"
	android:layout_gravity="center_horizontal">
<!-- 定义两个单选框 -->
<RadioButton android:layout_width="wrap_content"
	android:layout_height="wrap_content"
	android:id="@+id/male"
	android:text="男"
	android:checked="true"
	/>
<RadioButton android:layout_width="wrap_content"
	android:layout_height="wrap_content"
	android:id="@+id/female"
	android:text="女"
	/>
</RadioGroup>
</TableRow>	
<TableRow>
<TextView 
	android:layout_width="wrap_content"
	android:layout_height="wrap_content"
	android:text="喜欢的颜色:"
	android:textSize="16px"
	/>
<!-- 定义一个垂直的线性布局 -->
<LinearLayout android:layout_gravity="center_horizontal"
	android:orientation="vertical"
	android:layout_width="wrap_content"
	android:layout_height="wrap_content">
<!-- 定义三个复选框 -->
<CheckBox android:layout_width="wrap_content"
	android:layout_height="wrap_content"
	android:text="红色"
	android:checked="true"
/>
<CheckBox android:layout_width="wrap_content"
	android:layout_height="wrap_content"
	android:text="蓝色"
/>
<CheckBox android:layout_width="wrap_content"
	android:layout_height="wrap_content"
	android:text="绿色"
/>
</LinearLayout>
</TableRow>
<TextView 
   	android:id="@+id/show"
    android:layout_width="wrap_content"
	android:layout_height="wrap_content"/>
</TableLayout>

上面的界面布局中定义了一组单选按钮,并默认勾选了第一个单选按钮,这组单选按钮共用户选择性别;还定义了三个复选框,供用户选择喜欢的颜色。

如果在 XML 布局文件中默认勾选了某个单选按钮,则必须为该组单选按钮的每个按钮指定 android:id 属性值,否则这组单选按钮不能正常工作。

为了监听单选按钮、复选框的勾选状态的改变,可以为它们添加事件监听器。例如下面 Activity 为 RadioGroup 添加了事件监听器,该监听器可以监听这组单选按钮的勾选状态的改变。

public class CheckButtonTest extends Activity
{
	RadioGroup rg;
	TextView show;
	@Override
	public void onCreate(Bundle savedInstanceState)
	{
		super.onCreate(savedInstanceState);
		setContentView(R.layout.main);
		// 获取界面上rg、show两个组件
		rg = (RadioGroup) findViewById(R.id.rg);
		show = (TextView) findViewById(R.id.show);
		// 为RadioGroup组件的OnCheck事件绑定事件监听器
		rg.setOnCheckedChangeListener(new OnCheckedChangeListener()
		{
			@Override
			public void onCheckedChanged(RadioGroup group, int checkedId)
			{
				// 根据用户勾选的单选按钮来动态改变tip字符串的值
				String tip = checkedId == R.id.male ?
						"您的性别是男人": "您的性别是女人";
				// 修改show组件中的文本。
				show.setText(tip);
			}
		});
	}
}

上面代码添加事件监听器的方式采用了 “委托式” 事件处理机制。委托式事件处理机制的原理是:当事件源上发生事件时,该事件将会激发该事件源上的监听器的特定方法。

运行上面的程序,并改变第一组单选按钮的勾选状态,将看到如图 2.25 所示界面。


6,状态开发按钮(ToggleButton)与开关(Switch)的功能与用法

状态开关按钮(ToggleButton)与开关(Switch)也是由 Button 派生出来的,因此它们的本质也是按钮,Button 支持的各种属性、方法也适用于 ToggleButton 和 Switch。从功能上来看,ToggleButton、Switch 与 CheckBox 复选框非常相似,它们都可以提供两个状态。不过 ToggleButton、Switch 与 CheckBox 的区别主要体现在功能上,ToggleButton、Switch 通常用于切换程序中的某种状态。

表 2.14 显示了 ToggleButton 所支持的 XML 属性及相关方法的说明。


表 2.15 显示了 Switch 所支持的 XML 属性及相关方法的说明。


下面通过一个动态控制布局的实例来示范 ToggleButton 与 Switch 的用法。

该实例的思路是在页面中增加一个 ToggleButton,随着该按钮状态的改变,界面布局中的 LinearLayout 布局的方向在水平布局、垂直布局之间切换。下面是该程序所使用的界面布局。

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
	android:orientation="vertical"
	android:layout_width="fill_parent"
	android:layout_height="fill_parent"
	>
<!-- 定义一个ToggleButton按钮 -->
<ToggleButton android:id="@+id/toggle"
	android:layout_width="wrap_content"
	android:layout_height="wrap_content"
	android:textOff="横向排列"
	android:textOn="纵向排列"
	android:checked="true"
	/>
<Switch android:id="@+id/switcher"
    android:layout_width="wrap_content"
	android:layout_height="wrap_content"
	android:textOff="横向排列"
	android:textOn="纵向排列"
	android:thumb="@drawable/check"
	android:checked="true"/>
<!-- 定义一个可以动态改变方向的线性布局 -->
<LinearLayout android:id="@+id/test"
	android:orientation="vertical"
	android:layout_width="fill_parent"
	android:layout_height="fill_parent"
	>
<Button
	android:layout_width="wrap_content"
	android:layout_height="wrap_content"
	android:text="测试按钮一"
	/>
<Button
	android:layout_width="wrap_content"
	android:layout_height="wrap_content"
	android:text="测试按钮二"
	/>
<Button
	android:layout_width="wrap_content"
	android:layout_height="wrap_content"
	android:text="测试按钮三"
	/>
</LinearLayout>
</LinearLayout>

上面 LinearLayout 中定义了三个按钮,该 LinearLayout 默认采用垂直方向的线性布局。接下来我们为 ToggleButton 按钮、Switch 按钮绑定监听器,当它的选中状态发生改变时,程序通过代表来改变 LinearLayout 的布局方向。

public class ToggleButtonTest extends Activity
{
	ToggleButton toggle;
	Switch switcher;
	@Override
	public void onCreate(Bundle savedInstanceState)
	{
		super.onCreate(savedInstanceState);
		setContentView(R.layout.main);
		toggle = (ToggleButton)findViewById(R.id.toggle);
		switcher = (Switch)findViewById(R.id.switcher);
		final LinearLayout test = (LinearLayout)findViewById(R.id.test);
		OnCheckedChangeListener listener = new OnCheckedChangeListener()
		{
			@Override
			public void onCheckedChanged(CompoundButton button
					, boolean isChecked)
			{
				if(isChecked)
				{
					//设置LinearLayout垂直布局
					test.setOrientation(1);
				}
				else
				{
					//设置LinearLayout水平布局
					test.setOrientation(0);
				}
			}
		};
		toggle.setOnCheckedChangeListener(listener);
		switcher.setOnCheckedChangeListener(listener);
	}
}

运行上面的程序,随着用户改变 ToggleButton 按钮的状态,下面界面布局的房型也在不断发生改变。图 2.26 显示了 ToggleButton 的界面。



7,时钟(AnalogClock 和 DigitalClock)的功能与用法

时钟 UI 组件是两个非常简单的组件,DigitalClock 本身就继承了 TextView —— 也就是说它本身就是文本框,只是它里面显示的内容总是当前时间。与 TextView 不同的是,为 DigitalClock 设置 android:text 属性没什么作用。

AnalogClock 则继承上 View 组件,它重写了 View 的 onDraw 方法,它会在 View 上绘制模拟时钟。

表 2.16 显示了 AnalogClock 所支持的 XML 属性的说明。


DigitalClock 和 AnalogClock 都会显示当前时间。不同的是,DigitalClock 显示数字时钟,可以显示当前的秒数;AnalogClock 显示模拟时钟,不会显示当前秒数。

下面通过实例来示范 AnalogClock 和 DigitalClock 的用法。

由于我们可以通过图片定制 AnalogClock 模拟指定的表盘、时针、分针,因此只要使用合适的图片,就可以对 AnalogClock 进行任意定制。下面的实例将会使用 “劳力士” 图片来定义模拟时钟,从而开发手机里的 “劳力士”。

下面是本实例的布局文件。

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
	android:orientation="vertical"
	android:layout_width="fill_parent"
	android:layout_height="fill_parent"
	android:gravity="center_horizontal"
	>
<!-- 定义模拟时钟 -->
<AnalogClock  
	android:layout_width="wrap_content" 
	android:layout_height="wrap_content" 
	/>
<!-- 定义数字时钟 -->
<DigitalClock
	android:layout_width="wrap_content" 
	android:layout_height="wrap_content" 
	android:textSize="14pt"
	android:textColor="#f0f"
	android:drawableRight="@drawable/ic_launcher"
	/>
<!-- 定义模拟时钟,并使用自定义表盘、时针图片 -->
<AnalogClock  
	android:layout_width="wrap_content" 
	android:layout_height="wrap_content" 
	android:dial="@drawable/watch"
	android:hand_minute="@drawable/hand"
	/>
</LinearLayout>

使用 Activity 显示上面的界面布局,将看到如图 2.27 所示的界面。

正如从上面代码看到的,如果想控制模拟显示时间的字号大小、字体颜色等,都可通过 android:textSize、android:textColor 等属性进行控制 —— 因为 DigitalClock 的本质还是一个 TextView,所以它可以使用 TextView 的 XML 属性和方法。


8,计时器(Chronometer)

Android 还提供了一个计时器组件:Chronometer,该组件与 DigitalClock 都继承自 TextView,因此它们都会显示一段文本。但 Chronometer 并不显示当前时间,它显示的是从某个起始时间开始,一共过去了多长时间。

Chronometer 的用法也很简单,它只提供了一个 android:format 属性,用于指定计时器的计时格式。除此之外,Chronometer 支持如下常用方法。

setBase(long base):设置计时器的起始时间。

setFormat(String format):设置显示时间的格式。

start():开始计时。

stop():停止计时。

setOnChronometerTickListener(Chronometer.OnChronometerTickListener listener):为计时器绑定事件监听器,当计时器改变时触发该监听器。

下面的程序简单示范了 Chronometer 的用法,该程序界面中定义一个 Chronometer 组件和一个 Button 组件。当用户单击 Button 时系统开始计时,当计时超过 20 秒时停止计时。下面是该程序的代码。

public class ChronometerTest extends Activity
{
	Chronometer ch;
	Button start;
	@Override
	public void onCreate(Bundle savedInstanceState)
	{
		super.onCreate(savedInstanceState);
		setContentView(R.layout.main);
		// 获取计时器组件
		ch = (Chronometer) findViewById(R.id.test);
		// 获取“开始”按钮
		start = (Button) findViewById(R.id.start);
		start.setOnClickListener(new OnClickListener()
		{
			@Override
			public void onClick(View source)
			{
				// 设置开始计时时间
				ch.setBase(SystemClock.elapsedRealtime());
				// 启动计时器
				ch.start();
				start.setEnabled(false);
			}
		});
		// 为Chronometer绑定事件监听器。	
		ch.setOnChronometerTickListener(new OnChronometerTickListener()
		{
			@Override
			public void onChronometerTick(Chronometer ch)
			{
				// 如果从开始计时到现在超过了20s。
				if (SystemClock.elapsedRealtime() - ch.getBase() > 20 * 1000)
				{
					ch.stop();
					start.setEnabled(true);
				}
			}
		});
	}
}

上面的程序代码用于设置 Chronometer 的起始时间,并启动 Chronometer。启动计时器后可以看到该组件显示已流逝的时间。

程序中用到的 SystemClock 类仅仅是一个获取系统时间、运行时间的工具类,用法很简单,读者自行查阅 API 文档即可。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值