在这里插入图片描述

案例概述

本案例展示如何使用 RadioListTile 创建单选按钮组,允许用户从多个选项中选择一个。

核心概念

1. Radio

  • 基础单选按钮组件;
  • 同一组中只能选中一个;
  • 需要 groupValue 参数指定当前选中值。

2. RadioListTile

  • 包含标题和描述的单选按钮;
  • 整个区域都可点击;
  • 适合列表中使用。

3. 分组管理

  • 使用 groupValue 参数管理单选组;
  • 所有 Radio 共享同一个 groupValue

代码详解

1. 单选按钮组

String _selectedGender = '男';

RadioListTile<String>(
  title: const Text('男'),
  value: '男',
  groupValue: _selectedGender,
  onChanged: (String? value) {
    setState(() {
      _selectedGender = value ?? '男';
    });
  },
)

2. 多个单选组

String _selectedGender = '男';
String _selectedLevel = '初级';

// 性别选择
RadioListTile<String>(
  value: '男',
  groupValue: _selectedGender,
  onChanged: (value) => setState(() => _selectedGender = value ?? '男'),
)

// 等级选择
RadioListTile<String>(
  value: '初级',
  groupValue: _selectedLevel,
  onChanged: (value) => setState(() => _selectedLevel = value ?? '初级'),
)

3. 响应式布局

Row(
  children: [
    Expanded(
      child: RadioListTile<String>(
        title: const Text('初级'),
        value: '初级',
        groupValue: _selectedLevel,
        onChanged: (value) => setState(() => _selectedLevel = value ?? '初级'),
      ),
    ),
    Expanded(
      child: RadioListTile<String>(
        title: const Text('中级'),
        value: '中级',
        groupValue: _selectedLevel,
        onChanged: (value) => setState(() => _selectedLevel = value ?? '中级'),
      ),
    ),
  ],
)

高级话题:单选按钮的高级应用

1. 单选按钮验证

validator: (value) {
  if (_selectedValue == null) {
    return '请选择一个选项';
  }
  return null;
}

2. 条件单选按钮

某些单选按钮的启用/禁用取决于其他条件:

RadioListTile<String>(
  title: Text('高级选项'),
  value: '高级',
  groupValue: _selectedLevel,
  enabled: _selectedLevel != '初级',
  onChanged: _selectedLevel != '初级'
      ? (value) => setState(() => _selectedLevel = value ?? '高级')
      : null,
)

3. 单选按钮分组

Column(
  children: [
    Text('性别', style: TextStyle(fontWeight: FontWeight.bold)),
    RadioListTile<String>(
      title: Text('男'),
      value: '男',
      groupValue: _selectedGender,
      onChanged: (value) => setState(() => _selectedGender = value ?? '男'),
    ),
    RadioListTile<String>(
      title: Text('女'),
      value: '女',
      groupValue: _selectedGender,
      onChanged: (value) => setState(() => _selectedGender = value ?? '女'),
    ),
    SizedBox(height: 16),
    Text('等级', style: TextStyle(fontWeight: FontWeight.bold)),
    // 等级选项...
  ],
)

4. 单选按钮的样式自定义

RadioListTile<String>(
  title: Text('选项'),
  activeColor: Colors.green,
  value: '选项',
  groupValue: _selectedValue,
  onChanged: (value) => setState(() => _selectedValue = value),
)

5. 单选按钮的响应式布局

在不同屏幕宽度上调整布局:

final isWideScreen = MediaQuery.of(context).size.width > 600;

if (isWideScreen) {
  // 显示为网格
  GridView.count(
    crossAxisCount: 3,
    children: options.map((option) {
      return RadioListTile<String>(
        title: Text(option),
        value: option,
        groupValue: _selectedValue,
        onChanged: (value) => setState(() => _selectedValue = value),
      );
    }).toList(),
  );
} else {
  // 显示为列表
  Column(
    children: options.map((option) {
      return RadioListTile<String>(
        title: Text(option),
        value: option,
        groupValue: _selectedValue,
        onChanged: (value) => setState(() => _selectedValue = value),
      );
    }).toList(),
  );
}

6. 单选按钮的键盘导航

Focus(
  onKey: (node, event) {
    if (event.isKeyPressed(LogicalKeyboardKey.arrowDown)) {
      // 移动到下一个选项
      return KeyEventResult.handled;
    }
    return KeyEventResult.ignored;
  },
  child: RadioListTile<String>(...),
)

7. 单选按钮的无障碍支持

RadioListTile<String>(
  title: Text('选项'),
  semanticLabel: '选择此选项',
  value: '选项',
  groupValue: _selectedValue,
  onChanged: (value) => setState(() => _selectedValue = value),
)

8. 单选按钮的动态选项

List<String> get availableOptions {
  if (_userType == 'admin') {
    return ['管理员', '编辑', '查看者'];
  }
  return ['编辑', '查看者'];
}

Column(
  children: availableOptions.map((option) {
    return RadioListTile<String>(
      title: Text(option),
      value: option,
      groupValue: _selectedRole,
      onChanged: (value) => setState(() => _selectedRole = value),
    );
  }).toList(),
)

9. 单选按钮状态的持久化

Future<void> _saveSelection() async {
  final prefs = await SharedPreferences.getInstance();
  await prefs.setString('selected_option', _selectedValue);
}

Future<void> _loadSelection() async {
  final prefs = await SharedPreferences.getInstance();
  final saved = prefs.getString('selected_option');
  if (saved != null) {
    setState(() {
      _selectedValue = saved;
    });
  }
}

10. 单选按钮的表单集成

FormField<String>(
  initialValue: _selectedValue,
  validator: (value) {
    if (value == null) return '请选择一个选项';
    return null;
  },
  builder: (FormFieldState<String> state) {
    return Column(
      children: options.map((option) {
        return RadioListTile<String>(
          title: Text(option),
          value: option,
          groupValue: state.value,
          onChanged: (value) {
            state.didChange(value);
            setState(() => _selectedValue = value);
          },
        );
      }).toList(),
    );
  },
)

通过这些高级技巧,你可以构建出功能完整的单选系统。

高级话题:单选按钮的企业级应用

1. 条件单选按钮

RadioListTile<String>(
  title: Text('高级选项'),
  value: '高级',
  groupValue: _selectedLevel,
  enabled: _selectedLevel != '初级',
  onChanged: _selectedLevel != '初级' ? (value) => setState(() => _selectedLevel = value ?? '高级') : null,
)

2. 单选按钮分组

Column(
  children: [
    Text('性别', style: TextStyle(fontWeight: FontWeight.bold)),
    RadioListTile<String>(title: Text('男'), ...),
    RadioListTile<String>(title: Text('女'), ...),
  ],
)

3. 单选按钮的响应式布局

final isWideScreen = MediaQuery.of(context).size.width > 600;
if (isWideScreen) {
  GridView.count(crossAxisCount: 3, children: ...)
} else {
  Column(children: ...)
}

4. 单选按钮的键盘导航

Focus(
  onKey: (node, event) {
    if (event.isKeyPressed(LogicalKeyboardKey.arrowDown)) {
      // 移动到下一个选项
      return KeyEventResult.handled;
    }
    return KeyEventResult.ignored;
  },
  child: RadioListTile<String>(...),
)

5. 单选按钮的无障碍支持

RadioListTile<String>(
  title: Text('选项'),
  semanticLabel: '选择此选项',
  value: '选项',
  groupValue: _selectedValue,
  onChanged: (value) => setState(() => _selectedValue = value),
)

6. 单选按钮的动态选项

List<String> get availableOptions {
  if (_userType == 'admin') {
    return ['管理员', '编辑', '查看者'];
  }
  return ['编辑', '查看者'];
}

7. 单选按钮的状态持久化

Future<void> _saveSelection() async {
  final prefs = await SharedPreferences.getInstance();
  await prefs.setString('selected_option', _selectedValue);
}

8. 单选按钮的表单集成

FormField<String>(
  initialValue: _selectedValue,
  validator: (value) {
    if (value == null) return '请选择一个选项';
    return null;
  },
  builder: (FormFieldState<String> state) {
    return Column(
      children: options.map((option) {
        return RadioListTile<String>(
          title: Text(option),
          value: option,
          groupValue: state.value,
          onChanged: (value) {
            state.didChange(value);
            setState(() => _selectedValue = value);
          },
        );
      }).toList(),
    );
  },
)

9. 单选按钮的验证

validator: (value) {
  if (_selectedValue == null) {
    return '请选择一个选项';
  }
  return null;
}

10. 单选按钮的样式自定义

RadioListTile<String>(
  title: Text('选项'),
  activeColor: Colors.green,
  value: '选项',
  groupValue: _selectedValue,
  onChanged: (value) => setState(() => _selectedValue = value),
)

通过这些企业级技巧,你可以构建出功能完整的单选系统。
欢迎加入开源鸿蒙跨平台社区:https://openharmonycrossplatform.csdn.net

Logo

开源鸿蒙跨平台开发社区汇聚开发者与厂商,共建“一次开发,多端部署”的开源生态,致力于降低跨端开发门槛,推动万物智联创新。

更多推荐