- 示例工程
- 教程
【免费下载链接】cw-omnibus
Source code to omnibus edition of _The Busy Coder's Guide to Android Development_
导读
RadioButton(单选按钮)与RadioGroup(单选组)是 Android 中最常用的"多选一"交互组件组合:RadioGroup负责承载一组RadioButton并自动保证"同一时刻只有一个被选中",非常适合性别选择、答题选项、设置项二选一或三选一这类场景。本文以 cw-omnibus 仓库中的 Basic/RadioButton 示例为骨架,逐步拆解其布局文件、字符串资源、Activity 入口与工程配置,并对比 BasicMaterial/RadioButton 的 Material 主题版本,帮助读者掌握从零搭建单选界面的完整链路,同时理解选中状态监听、程序化控制等进阶用法。
一、示例定位:一份"最小可运行"的单选组件演示
在 cw-omnibus(《The Busy Coder's Guide to Android Development》全量示例源码合集)中,Basic/RadioButton/README.markdown 用一句话概括了本示例的核心目标:
This sample Android app demonstrates using
RadioButtonwidgets in aRadioGroup.
即:演示如何在RadioGroup容器中使用RadioButton控件。与之配套的兄弟示例 Basic/CheckBox 则演示多选CheckBox的用法,二者同属于"常用控件与容器"主题章节,可以对照学习。
该示例的工程结构非常精简,仅包含一个app模块(见 settings.gradle 中的include ':app'),核心代码文件只有三个:
| 文件 | 职责 |
|---|---|
| app/src/main/res/layout/main.xml | 界面布局:一个纵向RadioGroup内嵌三个RadioButton |
| app/src/main/res/values/strings.xml | 字符串资源:应用名与三个选项文案 |
| app/src/main/java/com/commonsware/android/basic/RadioButtonDemo.java | Activity 入口:加载布局并展示界面 |
这种"布局 + 资源 + 一个 Activity"的最小组合,正是 Android 入门阶段学习单选控件的理想范本。
二、布局核心:用 RadioGroup 保证单选互斥
示例的界面完全由 XML 布局声明,未写任何 Java 逻辑。完整布局如下(app/src/main/res/layout/main.xml):
<?xml version="1.0" encoding="utf-8"?> <RadioGroup xmlns:android="http://schemas.android.com/apk/res/android" android:orientation="vertical" android:layout_width="match_parent" android:layout_height="match_parent" > <RadioButton android:id="@+id/radio1" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="@string/rock" /> <RadioButton android:id="@+id/radio2" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="@string/scissors" /> <RadioButton android:id="@+id/radio3" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="@string/paper" /> </RadioGroup>2.1 RadioGroup:单选互斥的容器
RadioGroup是LinearLayout的子类,具备线性容器的全部特性,同时额外承担单选互斥管理职责:
android:orientation:决定选项排列方向。示例取vertical(垂直排列),改为horizontal即可让三个选项横向排布在一行内。android:layout_width/height:示例均为match_parent,让整个单选组铺满屏幕。- 互斥规则:在同一个
RadioGroup内,任意时刻最多只有一个RadioButton处于选中(checked)状态。当用户点击一个新的选项时,RadioGroup会自动取消其余选项的选中态,开发者无需手工遍历清除。这正是"组"存在的意义——脱离RadioGroup的RadioButton彼此独立、可同时选中,不构成单选语义。
2.2 RadioButton:单个选项
每个RadioButton继承自CompoundButton,是一个"圆形按钮 + 文本标签"的复合控件,常用属性:
| 属性 | 示例取值 | 作用 |
|---|---|---|
android:id | @+id/radio1等 | 为每个选项定义唯一标识,供 Java 代码findViewById查找 |
android:layout_width/height | wrap_content | 让按钮按自身内容自适应大小 |
android:text | @string/rock | 引用字符串资源作为选项文案,而非硬编码 |
示例为三个选项分别声明了radio1、radio2、radio3三个 id,对应"石头(Rock)— 剪刀(Scissors)— 布(Paper)"这一经典的猜拳三选一场景,语义直观、便于演示单选行为。
2.3 默认选中项
示例布局中三个RadioButton均未声明android:checked属性,因此初始状态三者都处于未选中状态。在实际项目中,如果要求"默认必须选中某一项",只需在目标RadioButton上添加android:checked="true"即可;而RadioGroup也支持在 Java 侧通过check(int id)或clearCheck()方法程序化控制选中项。更进阶的默认值设定(如根据持久化数据恢复选中项)会在第四节展开说明。
三、字符串资源:文案与布局解耦
选项文案没有直接写死在布局里,而是抽取到 app/src/main/res/values/strings.xml:
<?xml version="1.0" encoding="utf-8"?> <resources> <string name="app_name">RadioButtonDemo</string> <string name="rock">Rock</string> <string name="scissors">Scissors</string> <string name="paper">Paper</string> </resources>其中rock、scissors、paper分别对应三个单选选项的文本,app_name则作为应用与 Activity 的显示名称。这样做的好处是:
- 多语言支持:新增
values-zh/strings.xml、values-ja/strings.xml等目录即可完成本地化,无需改动布局; - 便于维护:文案集中管理,修改措辞不会触及代码与布局;
- 符合 Android 最佳实践:所有面向用户的文本都应放入资源而非硬编码字符串。
四、Java 入口:一个纯粹加载布局的 Activity
Java 侧的实现极其简洁(RadioButtonDemo.java):
package com.commonsware.android.basic; import android.app.Activity; import android.os.Bundle; public class RadioButtonDemo extends Activity { @Override public void onCreate(Bundle state) { super.onCreate(state); setContentView(R.layout.main); } }要点如下:
RadioButtonDemo继承原生Activity(android.app.Activity),而非 AppCompat 系列;onCreate(Bundle state)中通过setContentView(R.layout.main)将第二节的布局树挂载为界面内容;- 由于本示例只演示静态展示,没有编写任何事件监听代码——单选互斥行为完全由
RadioGroup内部机制保证。
4.1 如何监听"用户选了哪一项"
虽然示例未实现监听,但"获取选中结果"是单选组件的核心诉求。RadioButton继承自CompoundButton,因此可通过setOnCheckedChangeListener(CompoundButton.OnCheckedChangeListener)监听选中状态变化。同仓库的 Basic/CheckBox/app/src/main/java/com/commonsware/android/checkbox/CheckBoxDemo.java 展示了这一监听模式的完整写法(CheckBox与RadioButton同为CompoundButton子类,监听 API 完全一致):
public class CheckBoxDemo extends Activity implements CompoundButton.OnCheckedChangeListener { CheckBox cb; @Override public void onCreate(Bundle state) { super.onCreate(state); setContentView(R.layout.main); cb = (CheckBox) findViewById(R.id.check); cb.setOnCheckedChangeListener(this); } public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) { if (isChecked) { cb.setText(R.string.checked); } else { cb.setText(R.string.unchecked); } } }将其套用到本示例,即可得到实用的单选反馈逻辑:
RadioGroup group = (RadioGroup) findViewById(R.id.group); group.setOnCheckedChangeListener(new RadioGroup.OnCheckedChangeListener() { @Override public void onCheckedChanged(RadioGroup group, int checkedId) { // checkedId 为当前选中项的 id(如 R.id.radio1) if (checkedId == R.id.radio1) { // 用户选择了 Rock } } });两点关键区别需要注意:
RadioGroup提供的OnCheckedChangeListener回调签名是onCheckedChanged(RadioGroup group, int checkedId),直接给出被选中项的 id,无需遍历;CompoundButton级别的监听签名是onCheckedChanged(CompoundButton buttonView, boolean isChecked),粒度到单个按钮。
此外,通过radio.isChecked()可查询某个按钮的选中态,通过radio.setChecked(true)或group.check(R.id.radioX)可程序化设置选中项——这些 API 组合足以覆盖"读取当前选择"和"恢复默认选择"两类常见需求。
五、工程与构建配置:让示例跑起来
要让这份示例编译运行,还需要了解它的工程配置。该示例使用 Gradle 构建(Android Studio 时代的标准工程布局),相关配置如下:
5.1 模块声明与 SDK 定位
settings.gradle 声明了唯一模块:app。同时项目还保留了 project.properties(早期 Ant/Eclipse 工程的残留配置),其中target=android-19表明项目定位在 API 19(Android 4.4)级别编译。
5.2 应用清单
app/src/main/AndroidManifest.xml 的关键声明:
<uses-sdk android:minSdkVersion="4" android:targetSdkVersion="14"/> ... <application android:icon="@drawable/ic_launcher"> <activity android:name=".RadioButtonDemo" android:label="RadioButtonDemo"> <intent-filter> <action android:name="android.intent.action.MAIN"/> <category android:name="android.intent.category.LAUNCHER"/> </intent-filter> </activity> </application>minSdkVersion="4"使示例可运行在 Android 1.6 及以上的几乎所有设备上,兼容范围极广;RadioButtonDemo被声明为带MAIN/LAUNCHER过滤器的启动 Activity,即应用安装后的默认入口;- 同时声明了
supports-screens(兼容各尺寸屏幕)与应用图标@drawable/ic_launcher(drawable-ldpi 至 drawable-xhdpi 共四档密度图标)。
5.3 构建方式
由于工程采用 Gradle 构建(gradle/wrapper/gradle-wrapper.properties 已提供 Wrapper 配置),在 Android Studio 中直接打开该目录即可同步并运行;命令行下也可使用 Gradle Wrapper 执行构建任务(如assembleDebug)。构建时还会套用 proguard.cfg 中的混淆规则(该配置面向android.app.Activity等四大组件及Parcelable实现类做 keep 保护),因此即使启用混淆也不会误伤 Activity 与布局回调。
六、进阶对比:Material 主题下的单选组件
在 Android 5.0(API 21)引入 Material Design 之后,单选组件的视觉风格有了显著升级。cw-omnibus 为此提供了配套示例 BasicMaterial/RadioButton,其布局文件与 Basic 版完全一致(同样是纵向RadioGroup+ 三个RadioButton,见 其 main.xml),差异集中在主题与清单配置上:
6.1 主题替换
styles.xml 以android:Theme.Material为父主题,并注入三色方案:
<resources> <style name="AppTheme" parent="android:Theme.Material"> <item name="android:colorPrimary">@color/primary</item> <item name="android:colorPrimaryDark">@color/primary_dark</item> <item name="android:colorAccent">@color/accent</item> </style> </resources>对应的 colors.xml 定义了配色(主色#3f51b5、深主色#1a237e、强调色#ffee58)。在 Material 主题下,RadioButton会自动采用符合 Material 规范的选择动画与强调色渲染,圆点选中时呈现colorAccent着色效果。
6.2 清单差异
BasicMaterial 版 Manifest 将minSdkVersion/targetSdkVersion提升到21,并在<application>上声明android:theme="@style/AppTheme"。两版对比可归纳为:
| 维度 | Basic/RadioButton | BasicMaterial/RadioButton |
|---|---|---|
| 主题 | 系统默认(Holoe 前身风格) | Theme.Material |
| minSdk | 4 | 21(Material 主题的最低要求) |
| 布局 | 同一份RadioGroup+ 三个RadioButton | 完全相同 |
| 视觉 | 旧式圆点 | Material 动画与强调色 |
由此可见:单选组件的交互逻辑与布局结构不随主题变化,主题只改变其外观渲染;需要 Material 风格时,只需按上述方式换主题并提升 minSdk 即可。
七、总结与延伸
通过 Basic/RadioButton 这一示例,可以完整掌握 Android 单选组件的核心用法:
- 布局:
RadioGroup(纵向/横向排列)内嵌多个RadioButton,容器自动维护单选互斥; - 资源:文案抽离到
strings.xml,便于本地化与维护; - 入口:Activity 仅需
setContentView(R.layout.main)即可渲染; - 监听:借助
RadioGroup.OnCheckedChangeListener获取选中项 id,或复用CompoundButton.OnCheckedChangeListener监听单按钮状态; - 主题升级:切换到
Theme.Material(minSdk 21)即可获得现代化视觉,布局代码无需改动。
若需继续深入,可在仓库中对照 Basic/CheckBox(多选场景)、BasicMaterial/RadioButton(Material 风格)以及 Selection 目录下的选择类控件示例,形成对"选择控件族"的系统认知。
- 示例工程
- 教程
【免费下载链接】cw-omnibus
Source code to omnibus edition of _The Busy Coder's Guide to Android Development_
相关推荐
cw-omnibus 实战:在 appcompat-v7 下使用 RadioButton 与 RadioGroup 构建单选界面
cw omnibus 实战:在 appcompat v7 下使用 RadioButton 与 RadioGroup 构建单选界面 本篇技术指南以 cw omni
示例工程教程cw-omnibus 实战:在 appcompat-v7 中使用 CheckBox 控件(含状态监听与主题配置)
cw omnibus 实战:在 appcompat v7 中使用 CheckBox 控件(含状态监听与主题配置) 本文以 cw omnibus 仓库中的 App
示例工程教程rsuite RadioGroup 单选按钮组:从分组表单到受控状态的完整实践
rsuite RadioGroup 单选按钮组:从分组表单到受控状态的完整实践 单选按钮(Radio)用于在一系列选项中只能选择一个选项的场景,而 RadioG
前端UI组件
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考