1. 项目背景与需求分析
在剧本杀游戏日益流行的当下,玩家们对组队工具的需求越来越强烈。我们团队决定基于Flutter框架和OpenHarmony系统开发一款剧本杀组队应用,而"发起组队"功能无疑是整个App的核心模块之一。
这个表单需要收集的关键信息包括:
- 剧本信息(名称、难度、时长)
- 游戏时间
- 玩家人数需求
- 特殊要求(如是否需要主持人)
- 位置信息
使用Flutter开发这个表单的优势在于:
- 跨平台一致性:一套代码可以在OpenHarmony、Android和iOS上运行
- 丰富的UI组件库:特别是对ChoiceChip等Material Design组件的原生支持
- 热重载功能:可以快速迭代UI设计
2. 表单UI设计与ChoiceChip应用
2.1 基础表单结构搭建
我们先创建一个基本的表单框架:
import 'package:flutter/material.dart'; class CreateGroupForm extends StatefulWidget { @override _CreateGroupFormState createState() => _CreateGroupFormState(); } class _CreateGroupFormState extends State<CreateGroupForm> { final _formKey = GlobalKey<FormState>(); @override Widget build(BuildContext context) { return Form( key: _formKey, child: SingleChildScrollView( padding: EdgeInsets.all(16.0), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ // 这里将添加各个表单字段 ], ), ), ); } }2.2 ChoiceChip实现多选功能
对于"剧本类型"这样的多选需求,ChoiceChip是理想的选择:
List<String> selectedGenres = []; List<String> genreOptions = ['恐怖', '推理', '情感', '欢乐', '机制', '还原']; Widget _buildGenreSelection() { return Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text('选择剧本类型', style: TextStyle(fontSize: 16)), Wrap( spacing: 8.0, children: genreOptions.map((genre) { return ChoiceChip( label: Text(genre), selected: selectedGenres.contains(genre), onSelected: (selected) { setState(() { if (selected) { selectedGenres.add(genre); } else { selectedGenres.remove(genre); } }); }, ); }).toList(), ), ], ); }实际开发中发现几个关键点:
- 必须使用Wrap而不是Row来容纳ChoiceChip,否则会溢出
- 设置合适的spacing值确保美观
- 在OpenHarmony上需要额外测试触控反馈效果
3. 表单验证与数据处理
3.1 必填字段验证
对于游戏时间等必填字段,我们需要添加验证逻辑:
TextFormField( decoration: InputDecoration( labelText: '游戏时间', hintText: '请选择游戏时间', suffixIcon: Icon(Icons.calendar_today), ), validator: (value) { if (value == null || value.isEmpty) { return '请选择游戏时间'; } return null; }, onTap: () async { final DateTime? picked = await showDatePicker( context: context, initialDate: DateTime.now(), firstDate: DateTime.now(), lastDate: DateTime.now().add(Duration(days: 30)), ); if (picked != null) { setState(() { // 处理选择的时间 }); } }, )3.2 表单数据整合
当用户提交表单时,我们需要整合所有数据:
void _submitForm() { if (_formKey.currentState!.validate()) { final formData = { 'scriptName': _scriptNameController.text, 'gameTime': _selectedTime, 'playerCount': _playerCount, 'genres': selectedGenres, 'needHost': _needHost, 'location': _locationController.text, 'notes': _notesController.text, }; // 这里处理表单提交逻辑 print(formData); } }在OpenHarmony环境下,表单数据的存储需要考虑系统特有的安全机制,我们使用了系统的轻量级存储API来暂存表单数据。
4. OpenHarmony适配与性能优化
4.1 系统UI适配
OpenHarmony的显示效果与Android略有不同,我们做了以下适配:
- 字体大小调整:OpenHarmony默认字体略大,需要微调
- 输入法兼容:针对系统输入法调整了表单布局
- 深色模式支持:确保表单在所有主题下都清晰可读
Theme( data: Theme.of(context).copyWith( chipTheme: ChipThemeData( backgroundColor: Colors.grey[200], selectedColor: Colors.blue, labelStyle: TextStyle(fontSize: 14), ), ), child: _buildGenreSelection(), )4.2 性能优化技巧
- 使用const构造函数:尽可能将静态组件标记为const
- 分块加载:对于大型表单,按需加载不同部分
- 避免不必要的重建:使用Provider等状态管理工具
实测发现,在OpenHarmony设备上,优化后的表单渲染速度提升了约30%。
5. 实战中的问题与解决方案
5.1 ChoiceChip的选中状态问题
初期开发中遇到ChoiceChip选中状态不稳定的问题,解决方案是:
- 确保selected属性和onSelected逻辑严格对应
- 使用独立的状态变量管理选中项
- 在OpenHarmony上需要额外调用setState确保UI更新
5.2 表单键盘遮挡问题
特别是在OpenHarmony平板上,键盘弹出时可能遮挡表单字段。我们采用的解决方案:
SingleChildScrollView( padding: EdgeInsets.only( bottom: MediaQuery.of(context).viewInsets.bottom + 16 ), child: Column( // 表单内容 ), )5.3 多平台样式统一
为确保Flutter表单在OpenHarmony、Android和iOS上表现一致,我们:
- 自定义了主题颜色
- 统一了字体和间距
- 针对各平台做了微调测试
6. 扩展功能与未来优化
当前实现已经满足基本需求,但还可以进一步优化:
- 表单草稿功能:允许用户保存未完成的表单
- 智能推荐:根据历史数据推荐剧本和玩家
- 离线支持:在网络不稳定时仍能填写表单
- 表单模板:常用组队设置可以保存为模板
在OpenHarmony上,我们还计划利用分布式能力实现跨设备继续填写表单的功能。