- Android开发权威指南(第二版)
- 李宁编著
- 249字
- 2024-12-21 14:46:37
13.3 按钮(Button)和复选框(Checkbox)控件
本节将介绍Android SDK中的按钮和复选框控件。按钮可分为多种,例如,普通按钮(Button)、图像按钮(ImageButton)、选项按钮(RadioButton)等。除此之外,复选框(CheckBox)也是Android SDK中非常重要的控件,通常用于多选的应用中。
13.3.1 Button(普通按钮控件)
源代码目录:src/ch13/Button
Button控件在前面的章节已经多次使用到了。Button控件的基本使用方法与TextView、EditText并无太大的差异,例如,下面的代码在布局文件中定义了一个按钮。
<Button android:id="@+id/button1" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:text="我的按钮1" />
最常用的按钮事件是单击事件,可以通过Button.setOnClickListener方法设置处理单击事件的监听器,也可以直接通过<Button>标签的android:onClick属性指定单击事件方法名。如果当前的类实现了android.view.View.OnClickListener接口,可以直接将this传入setOnClickListener方法,代码如下:
Button button1 = (Button) findViewById(R.id.button1);
button1.setOnClickListener(this);
在本节的例子中包含两个按钮,并在单击事件中通过value变量控制按钮放大或缩小(value=1为放大,value=1为缩小),代码如下:
源代码文件:src/ch13/Button/src/mobile/android/button/Main.java
// “我的按钮1”按钮的单击事件方法
public void onClick(View view)
{
Button button = (Button) view;
// 如果按钮宽度等于屏幕宽度,按钮开始缩小
if (value == 1
&& button.getWidth() == getWindowManager().getDefaultDisplay().getWidth())
value = -1;
// 如果按钮宽度小于100,按钮开始放大
else if (value == -1 && button.getWidth() < 100)
value = 1;
// 以按钮宽度和高度的10%放大或缩小按钮
button.setWidth(button.getWidth() + (int) (button.getWidth() * 0.1)* value);
button.setHeight(button.getHeight() + (int) (button.getHeight() * 0.1)* value);
}
运行上面的代码后,将显示两个按钮,单击任何一个按钮后,该按钮都会放大,当按钮宽度等于屏幕宽度时,再次单击按钮时,按钮开始缩小。
为了使按钮更绚丽,还可以为按钮加上背景图。通过设置透明背景图,可以做出任何形状的按钮,这种按钮也可以称为“异形按钮”。异形按钮需要处理3个事件 ,这3个事件及各自的处理逻辑如下。
触摸事件(onTouch):当触摸按钮时,应该显示按钮被触摸后的状态。
焦点变化事件(onFocusChange):当焦点从一个按钮切换到另一个按钮时,应该显示按钮被触摸时的状态(image2.png),并且将上一个焦点按钮设为未被触摸时的状态。
键盘事件(onKey):当某一个按钮获得焦点后,按下手机或模拟器上的“确认”按钮后,当前按钮应该被设置成被按下的状态,也就是这个按钮的第3张图,因此,需要为每一个按钮准备3张图,分别是正常状态、触摸状态、按钮被按下的状态。
现在将本例的第2个按钮改成异形按钮,所以需要准备按钮的 3 个状态的png图(button1.png、button2.png、button3.png)。
先来编写触摸事件(onTouch)中的代码。
源代码文件:src/ch13/Button/src/mobile/android/button/Main.java
@Override
public boolean onTouch(View view, MotionEvent event)
{
if (event.getAction() == MotionEvent.ACTION_UP)
{
// 当手指或鼠标抬起时恢复按钮的默认状态
view.setBackgroundResource(R.drawable.button1);
}
else if (event.getAction() == MotionEvent.ACTION_DOWN)
{
// 当手指或鼠标按下时将按钮置为按下状态
view.setBackgroundResource(R.drawable.button2);
}
return false;
}
在上面的代码中根据getAction方法获得了触摸的状态,并使用setBackgroundResource方法为按钮设置了不同的背景图像。
当异形按钮处于焦点状态时,需要将异形按钮的背景图设为被触摸状态,代码如下:
源代码文件:src/ch13/Button/src/mobile/android/button/Main.java
// 当控件焦点变化时调用该事件方法,当控件获得焦点时,hasFocus参数值为true,否则为false
@Override
public void onFocusChange(View view, boolean hasFocus)
{
if (hasFocus)
{
// 设置异形按钮获得焦点时的背景图
imageButton.setBackgroundResource(R.drawable.button2);
}
else
{
// 设置异形按钮失去焦点时的背景图
imageButton.setBackgroundResource(R.drawable.button1);
}
}
当按手机或模拟器上的“确认”键时,需要将当前获得焦点的异形按钮设为按键被按下的状态,当松开“确认”键时,又恢复到获得焦点的状态,这个功能需要在处理键盘事件的onKey中完成,代码如下:
源代码文件:src/ch13/Button/src/mobile/android/button/Main.java
@Override
public boolean onKey(View view, int keyCode, KeyEvent event)
{
if (KeyEvent.ACTION_DOWN == event.getAction())
{
// 设置异形按钮被按下时的背景图
view.setBackgroundResource(R.drawable.button3);
}
else if (KeyEvent.ACTION_UP == event.getAction())
{
// 设置异形按钮被抬起时的背景图(焦点状态的背景图)
view.setBackgroundResource(R.drawable.button2);
}
return false;
}
本例中两个按钮在默认情况下的显示效果如图13-12所示。当不断按屏幕上的两个按钮时,两个按钮会不断放大,当遇到屏幕边界时,会不断缩小,如图13-13所示。
▲图13-12 默认状态的两个按钮
▲图13-13 单击放大的两个按钮
13.3.2 图文混排的按钮
源代码目录:src/ch13/ImageTextButton
上一节介绍的只是在按钮上显示文字或图像,在本节将介绍如下两种同时在按钮上显示文字和图像的方法。
使用<Button>标签的android:drawableXxx属性,其中Xxx表示Top、Bottom、Left、Right。这4个属性的值都是资源类型,需要指定图像资源的ID,分别表示在按钮上、下、左、右插入一个图像,同时还可配合android:drawablePadding属性来设置图像到文字的距离。
Button和EditText一样,也是TextView的子类,因此,也可以采用与TextView、EditText同样的方法来实现图文混排。
首先在布局文件中放5个按钮,其中前4个按钮分别使用android:drawableXxx属性在文字上、下、左、右插入一个图像,第5个按钮通过ImageSpan和SpannableString在文字两侧分别插入一个图像。
布局文件的代码如下:
源代码文件:src/ch13/ImageTextButton/res/layout/main.xml
<?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">
<LinearLayout android:orientation="horizontal"
android:layout_width="fill_parent" android:layout_height="120dp">
<Button android:layout_width="wrap_content"
android:layout_height="wrap_content" android:drawableTop="@drawable/star"
android:text="按钮1" />
<Button android:layout_width="wrap_content"
android:layout_height="wrap_content" android:drawableBottom="@drawable/star"
android:text="按钮2" android:drawablePadding="30dp" />
<Button android:layout_width="wrap_content"
android:layout_height="wrap_content" android:drawableLeft="@drawable/star"
android:text="按钮3" />
<Button android:layout_width="wrap_content"
android:layout_height="wrap_content" android:drawableRight="@drawable/star"
android:text="按钮4" android:drawablePadding="20dp" />
</LinearLayout>
<Button android:id="@+id/button" android:layout_width="200dp"
android:layout_height="200dp" android:layout_marginTop="10dp" />
</LinearLayout>
下面的代码向第5个按钮上的文字两侧分别插入了两个图像。
源代码文件:src/ch13/ImageTextButton/src/mobile/android/image/text/button/Main.java
public class Main extends Activity
{
@Override
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
Button button = (Button) findViewById(R.id.button);
// 处理文字左侧的图像
SpannableString spannableStringLeft = new SpannableString("left");
Bitmap bitmapLeft = BitmapFactory.decodeResource(getResources(),
R.drawable.image_left);
ImageSpan imageSpanLeft = new ImageSpan(bitmapLeft,
DynamicDrawableSpan.ALIGN_BOTTOM);
// 将left替换成ImageSpan对象
spannableStringLeft.setSpan(imageSpanLeft, 0, 4,
Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
// 处理文字右侧的图像
SpannableString spannableStringRight = new SpannableString("right");
Bitmap bitmapRight = BitmapFactory.decodeResource(getResources(),
R.drawable.image_right);
ImageSpan imageSpanRight = new ImageSpan(bitmapRight);
// 将right替换成ImageSpan对象
spannableStringRight.setSpan(imageSpanRight, 0, 5,
Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
// 插入文字左侧的图像
button.append(spannableStringLeft);
// 插入文字
button.append("我的按钮");
// 插入文字右侧的图像
button.append(spannableStringRight);
}
}
运行本例后,在窗口上会显示如图13-14所示的5个按钮。
13.3.3 ImageButton(图像按钮控件)
源代码目录:src/ch13/ImageButton
ImageButton控件可以作为图像按钮来使用。例如,下面的代码配置了两个带背景的图像按钮。
源代码文件:src/ch13/ImageButton/res/layout/main.xml
<ImageButton android:layout_width="wrap_content"
android:layout_height="wrap_content" android:src="@drawable/button1_1" />
<ImageButton android:layout_width="wrap_content"
android:layout_height="wrap_content" android:src="@drawable/button2_1" />
如果想在代码中修改ImageButton的图像,可以使用ImageButton.setImageResource或其他类似的方法。本例的显示效果如图13-15所示。
▲图13-14 图文混排的按钮
▲图13-15 图像按钮
注意
ImageButton并不是TextView的子类,而是ImageView的子类,因此并没有android:text属性。如果要在ImageButton上输出文字,可以自定义一个控件,并在onDraw方法中将文字画在ImageButton上。
13.3.4 RadioButton(选项按钮控件)
源代码目录:src/ch13/RadioButton
选项按钮可用于多选一的应用中。如果想在选中某一个选项按钮后,其他的选项按钮都被设为未选中状态,需要将<RadioButton>标签放在<RadioGroup>标签中。由于RadioButton是Button的子类(实际上,RadioButton是ComponentButton的直接子类,而ComponentButton又是Button的直接子类),因此,在<RadioButton>标签中同样可以使用android:drawableXxx及android:drawablePadding属性。例如,下面的代码在屏幕上放置了3个选项按钮,其中第3个选项按钮周围显示了4个图像。
源代码文件:src/ch13/RadioButton/res/layout/main.xml
<RadioGroup android:layout_width="wrap_content" android:layout_height="wrap_content">
<RadioButton android:layout_width="wrap_content"
android:layout_height="wrap_content" android:text="选项1" />
<RadioButton android:layout_width="wrap_content"
android:layout_height="wrap_content" android:text="选项2" />
<RadioButton android:layout_width="wrap_content"
android:layout_height="wrap_content" android:text="选项3"
android:drawableLeft="@drawable/star" android:drawableTop="@drawable/circle"
android:drawableRight="@drawable/star"
android:drawableBottom="@drawable/circle" android:drawablePadding="20dp" />
</RadioGroup>
本例的显示效果如图13-16所示。
▲图13-16 选项按钮
13.3.5 ToggleButton(开关状态按钮控件)
源代码目录:src/ch13/ToggleButton
ToggleButton控件与Button控件的功能基本相同,但ToggleButton控件还提供了可以表示“开/关”状态的功能,这种功能非常类似于复选框(CheckBox)。ToggleButton控件通过在按钮文字的下方显示一个绿色的指示条来表示“开/关”状态。至于绿色的指示条是表示“开”还是“关”,完全由开发人员自己决定。当指示条在绿色状态时,再次单击按钮,指示条就会变成白色。ToggleButton控件的基本使用方法与Button控件相同,代码如下:
<ToggleButton android:layout_width="wrap_content" android:layout_height="wrap_content" />
虽然ToggleButton是Button的子类,但android:text属性并不起作用。在默认情况下,根据ToggleButton控件的不同状态,会在按钮上显示“关闭”或“开启”。如果要更改默认的按钮文本,可以使用android:textOff和android:textOn属性,代码如下:
源代码文件:src/ch13/ToggleButton/res/layout/main.xml
<ToggleButton android:id="@+id/toggleButton" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_marginLeft="30dp"
android:textOff="打开电灯" android:textOn="关闭电灯" />
默认情况下,按钮上的指示条是白色的,如果要在XML布局文件中修改默认状态,可以使用android:checked属性,在代码中使用ToggleButton.setChecked方法。当checked属性值或setChecked方法的参数值为true时,指示条显示为绿色。
本例的显示效果如图13-17所示。
▲图13-17 ToggleButton 控件
13.3.6 CheckBox(复选框控件)
源代码目录:src/ch13/DynamicCheckbox
复选框通常用于多选的应用。基本的使用方法如下:
<CheckBox android:id="@+id/checkbox" android:layout_width="fill_parent"
android:layout_height="wrap_content" />
CheckBox默认情况下是未选中状态。如果想修改这个默认值,可以将<CheckBox>标签的android:checked属性值设为true,或使用CheckBox.setChecked方法设置CheckBox的状态。在代码中可以使用CheckBox.isChecked方法判断CheckBox是否被选中。如果isChecked方法返回true,则表示CheckBox处于选中状态。
本节给出一个动态创建CheckBox控件的例子,也许很多读者会首先想到在代码中创建CheckBox对象。这样做虽然从技术上说没有任何问题,也属于比较常用的动态创建控件的方法,但在实际应用中,往往会为CheckBox设置很多属性,如果在代码中直接创建CheckBox对象,就需要手工设置CheckBox对象的属性,这样做是很麻烦的。
如果单纯考虑设置控件的属性,布局文件无疑是最简单的方法。我们自然会想到是否可以在布局文件中先配置一个或若干CheckBox,然后以这些配置为模板来动态创建CheckBox对象呢?如果能想到这些,将会大大减少动态创建CheckBox对象的代码。
由于同一个控件不能拥有两个及以上的父控件,因此,不能直接在窗口中使用findViewById方法来获得CheckBox对象。如何解决这个问题呢?
实际上,XML布局文件的根节点不仅可以是像<LinearLayout>、<RelativeLayout>一样的ViewGroup(容器控件),也可以直接使用View,例如,<CheckBox>标签。因此,我们先来编写一个checkbox.xml文件设置复选框。
源代码文件:src/ch13/DynamicCheckbox/res/layout/checkbox.xml
<?xml version="1.0" encoding="utf-8"?>
<CheckBox xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/checkbox" android:layout_width="fill_parent"
android:layout_height="wrap_content" />
为了单击“确认”按钮后显示被选中的复选框的文本,需要在复选框下方显示一个“确认”按钮。因此,在本例中还需要一个main.xml布局文件,用于定义“确认”按钮。
源代码文件:src/ch13/DynamicCheckbox/res/layout/main.xml
<?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:id="@+id/button" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:text="确定" />
</LinearLayout>
动态创建CheckBox对象的方法是定义一个String类型的数组,数组元素是CheckBox的文本,然后根据String数组的元素个数来动态创建CheckBox对象。动态创建CheckBox对象的步骤如下。
第1步:使用getLayoutInflater().inflate方法装载main.xml布局文件,并返回一个LinearLayout对象。
第2步:使用getLayoutInflater().inflate方法装载checkbox.xml布局文件,并返回一个CheckBox对象。
第3步:根据String数组中的值设置CheckBox的文本。
第4步:调用linearLayout.addView方法将CheckBox对象添加到LinearLayout对象中。
第5步:根据String数组的元素重复执行第2步、第3步和第4步,直到处理完String数组中的最后一个元素为止。
动态创建CheckBox对象是在onCreate方法中完成的,代码如下:
源代码文件:src/ch13/DynamicCheckbox/src/mobile/android/dynamic/checkbox/Main.java
public void onCreate(Bundle savedInstanceState)
{
String[] checkboxText = new String[]
{ "是学生吗?", "是否喜欢Android?", "买车了吗?", "打算出国吗?" };
super.onCreate(savedInstanceState);
LinearLayout linearLayout = (LinearLayout) getLayoutInflater().inflate(
R.layout.main, null);
for (int i = 0; i < checkboxText.length; i++)
{
// 根据checkbox.xml文件创建CheckBox对象
CheckBox checkbox = (CheckBox) getLayoutInflater().inflate(R.layout.checkbox, null);
// 将CheckBox对象添加到checkboxs数组中,用于对CheckBox对象的检索
checkboxs.add(checkbox);
// 设置CheckBox对象的文本
checkboxs.get(i).setText(checkboxText[i]);
// 将CheckBox对象添加到界面的主布局中(main.xml),在按钮前面显示复选框
linearLayout.addView(checkbox, i);
}
setContentView(linearLayout);
Button button = (Button) findViewById(R.id.button);
button.setOnClickListener(this);
}
其中checkboxs是在Main类中定义的一个List<CheckBox>类型的变量,用来保存动态创建的CheckBox对象。该变量需要在“确认”按钮的单击事件方法中使用,代码如下:
源代码文件:src/ch13/DynamicCheckbox/src/mobile/android/dynamic/checkbox/Main.java
public void onClick(View view)
{
String s = "";
// 扫描所有的CheckBox,以便获得被选中的复选框的文本
for (CheckBox checkbox : checkboxs)
{
if (checkbox.isChecked())
s += checkbox.getText() + "\n";
}
if ("".equals(s))
s = "您还没选呢!";
new AlertDialog.Builder(this).setMessage(s).setPositive Button("关闭", null).show();
}
运行本例并选中相应的复选框,然后单击“确认”按钮,显示如图13-18所示的效果。
▲图13-18 动态创建复选框