flutter_for_openharmony口腔护理app实战+意见反馈实现

前言

意见反馈是应用与用户沟通的重要渠道。通过收集用户的建议和问题反馈,开发者可以不断改进应用,提升用户体验。一个设计良好的反馈页面应该让用户能够方便地表达自己的想法。

本文将介绍如何在 Flutter 中实现一个功能完善的意见反馈页面。

功能设计

意见反馈页面需要实现以下功能:

  • 反馈类型:支持选择功能建议、问题反馈、内容纠错等类型
  • 反馈内容:多行文本输入,支持字数限制
  • 联系方式:可选填写联系方式
  • 提交反馈:验证并提交反馈内容

页面基础结构

意见反馈页面使用 StatefulWidget 实现:

dart 复制代码
class FeedbackPage extends StatefulWidget {
  const FeedbackPage({super.key});

  @override
  State<FeedbackPage> createState() => _FeedbackPageState();
}

class _FeedbackPageState extends State<FeedbackPage> {
  String _selectedType = '功能建议';
  final _contentController = TextEditingController();
  final _contactController = TextEditingController();

定义反馈类型和文本控制器。

资源释放

dispose 中释放控制器:

dart 复制代码
  @override
  void dispose() {
    _contentController.dispose();
    _contactController.dispose();
    super.dispose();
  }

避免内存泄漏。

页面布局

使用 SingleChildScrollView 包裹表单:

dart 复制代码
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: const Text('意见反馈')),
      body: SingleChildScrollView(
        padding: const EdgeInsets.all(16),
        child: Column(
          crossAxisAlignment: CrossAxisAlignment.start,
          children: [

表单内容较多时需要支持滚动。

反馈类型选择

使用 ChoiceChip 实现类型选择:

dart 复制代码
            const Text('反馈类型', 
                style: TextStyle(fontWeight: FontWeight.bold)),
            const SizedBox(height: 12),
            Wrap(
              spacing: 12,
              children: ['功能建议', '问题反馈', '内容纠错', '其他'].map((type) => 
                  ChoiceChip(
                label: Text(type),
                selected: _selectedType == type,
                onSelected: (selected) {
                  if (selected) setState(() => _selectedType = type);
                },
                selectedColor: const Color(0xFF26A69A).withOpacity(0.2),
                labelStyle: TextStyle(
                  color: _selectedType == type 
                      ? const Color(0xFF26A69A) 
                      : Colors.grey.shade700,
                ),
              )).toList(),
            ),

ChoiceChip 提供了单选的交互效果,选中状态使用主题色。

反馈内容输入

多行文本输入框:

dart 复制代码
            const SizedBox(height: 24),
            const Text('反馈内容', 
                style: TextStyle(fontWeight: FontWeight.bold)),
            const SizedBox(height: 12),
            Container(
              decoration: BoxDecoration(
                color: Colors.white,
                borderRadius: BorderRadius.circular(12),
              ),
              child: TextField(
                controller: _contentController,
                maxLines: 6,
                maxLength: 500,
                decoration: const InputDecoration(
                  hintText: '请详细描述您的问题或建议...',
                  border: InputBorder.none,
                  contentPadding: EdgeInsets.all(16),
                ),
              ),
            ),

设置最大行数和字数限制,maxLength 会自动显示字数计数器。

联系方式输入

可选的联系方式输入:

dart 复制代码
            const SizedBox(height: 24),
            const Text('联系方式(选填)', 
                style: TextStyle(fontWeight: FontWeight.bold)),
            const SizedBox(height: 12),
            Container(
              decoration: BoxDecoration(
                color: Colors.white,
                borderRadius: BorderRadius.circular(12),
              ),
              child: TextField(
                controller: _contactController,
                decoration: const InputDecoration(
                  hintText: '手机号或邮箱,方便我们联系您',
                  border: InputBorder.none,
                  contentPadding: EdgeInsets.all(16),
                ),
              ),
            ),

联系方式为选填项,提示用户可以填写手机号或邮箱。

提交按钮

提交反馈按钮:

dart 复制代码
            const SizedBox(height: 32),
            SizedBox(
              width: double.infinity,
              child: ElevatedButton(
                onPressed: _submitFeedback,
                style: ElevatedButton.styleFrom(
                  backgroundColor: const Color(0xFF26A69A),
                  foregroundColor: Colors.white,
                  padding: const EdgeInsets.symmetric(vertical: 14),
                  shape: RoundedRectangleBorder(
                      borderRadius: BorderRadius.circular(12)),
                ),
                child: const Text('提交反馈', style: TextStyle(fontSize: 16)),
              ),
            ),

按钮占满宽度,使用主题色背景。

温馨提示

页面底部的温馨提示:

dart 复制代码
            const SizedBox(height: 16),
            Container(
              padding: const EdgeInsets.all(16),
              decoration: BoxDecoration(
                color: Colors.blue.shade50,
                borderRadius: BorderRadius.circular(12),
              ),
              child: Row(
                children: [
                  Icon(Icons.info_outline, color: Colors.blue.shade700),
                  const SizedBox(width: 12),
                  const Expanded(
                    child: Text('感谢您的反馈,我们会认真对待每一条建议!'),
                  ),
                ],
              ),
            ),
          ],
        ),
      ),
    );
  }

蓝色背景的提示卡片,表达对用户反馈的重视。

提交反馈逻辑

提交反馈的处理逻辑:

dart 复制代码
void _submitFeedback() {
  if (_contentController.text.isEmpty) {
    ScaffoldMessenger.of(context).showSnackBar(
      const SnackBar(content: Text('请输入反馈内容')),
    );
    return;
  }

  showDialog(
    context: context,
    builder: (ctx) => AlertDialog(
      title: const Row(
        children: [
          Icon(Icons.check_circle, color: Color(0xFF26A69A)),
          SizedBox(width: 8),
          Text('提交成功'),
        ],
      ),
      content: const Text('感谢您的反馈,我们会尽快处理!'),
      actions: [
        ElevatedButton(
          onPressed: () {
            Navigator.pop(ctx);
            Navigator.pop(context);
          },
          child: const Text('确定'),
        ),
      ],
    ),
  );
}

提交前验证内容不为空,成功后显示确认对话框并返回上一页。

数据模型定义

反馈的数据模型:

dart 复制代码
class Feedback {
  final String id;
  final String type;
  final String content;
  final String? contact;
  final DateTime createTime;

  Feedback({
    String? id,
    required this.type,
    required this.content,
    this.contact,
    DateTime? createTime,
  }) : id = id ?? DateTime.now().millisecondsSinceEpoch.toString(),
       createTime = createTime ?? DateTime.now();
}

模型包含类型、内容、联系方式和创建时间。

图片上传功能

添加图片上传功能:

dart 复制代码
List<String> _images = [];

Wrap(
  spacing: 8,
  runSpacing: 8,
  children: [
    ..._images.map((path) => Stack(
      children: [
        Container(
          width: 80,
          height: 80,
          decoration: BoxDecoration(
            borderRadius: BorderRadius.circular(8),
            image: DecorationImage(
              image: FileImage(File(path)),
              fit: BoxFit.cover,
            ),
          ),
        ),
        Positioned(
          right: 0,
          top: 0,
          child: GestureDetector(
            onTap: () => setState(() => _images.remove(path)),
            child: Container(
              padding: const EdgeInsets.all(2),
              decoration: const BoxDecoration(
                color: Colors.red,
                shape: BoxShape.circle,
              ),
              child: const Icon(Icons.close, size: 14, color: Colors.white),
            ),
          ),
        ),
      ],
    )),
    if (_images.length < 3)
      GestureDetector(
        onTap: _pickImage,
        child: Container(
          width: 80,
          height: 80,
          decoration: BoxDecoration(
            color: Colors.grey.shade200,
            borderRadius: BorderRadius.circular(8),
          ),
          child: const Icon(Icons.add_photo_alternate, color: Colors.grey),
        ),
      ),
  ],
)

支持上传最多3张图片,可以删除已选图片。

图片选择

使用 image_picker 选择图片:

dart 复制代码
Future<void> _pickImage() async {
  final picker = ImagePicker();
  final image = await picker.pickImage(source: ImageSource.gallery);
  if (image != null) {
    setState(() => _images.add(image.path));
  }
}

从相册选择图片添加到列表。

表单验证

完善表单验证:

dart 复制代码
bool _validateForm() {
  if (_contentController.text.isEmpty) {
    _showError('请输入反馈内容');
    return false;
  }
  if (_contentController.text.length < 10) {
    _showError('反馈内容至少10个字');
    return false;
  }
  if (_contactController.text.isNotEmpty) {
    if (!_isValidContact(_contactController.text)) {
      _showError('请输入正确的手机号或邮箱');
      return false;
    }
  }
  return true;
}

bool _isValidContact(String contact) {
  final phoneRegex = RegExp(r'^1[3-9]\d{9}$');
  final emailRegex = RegExp(r'^[\w-\.]+@([\w-]+\.)+[\w-]{2,4}$');
  return phoneRegex.hasMatch(contact) || emailRegex.hasMatch(contact);
}

void _showError(String message) {
  ScaffoldMessenger.of(context).showSnackBar(
    SnackBar(content: Text(message)),
  );
}

验证内容长度和联系方式格式。

提交加载状态

添加提交加载状态:

dart 复制代码
bool _isSubmitting = false;

ElevatedButton(
  onPressed: _isSubmitting ? null : _submitFeedback,
  child: _isSubmitting
      ? const SizedBox(
          width: 20,
          height: 20,
          child: CircularProgressIndicator(
            strokeWidth: 2,
            valueColor: AlwaysStoppedAnimation<Color>(Colors.white),
          ),
        )
      : const Text('提交反馈', style: TextStyle(fontSize: 16)),
)

提交时显示加载指示器,禁用按钮防止重复提交。

草稿保存功能

自动保存草稿:

dart 复制代码
@override
void initState() {
  super.initState();
  _loadDraft();
}

Future<void> _loadDraft() async {
  final prefs = await SharedPreferences.getInstance();
  final draft = prefs.getString('feedback_draft');
  if (draft != null) {
    _contentController.text = draft;
  }
}

Future<void> _saveDraft() async {
  final prefs = await SharedPreferences.getInstance();
  await prefs.setString('feedback_draft', _contentController.text);
}

用户输入时自动保存草稿,下次打开时恢复。

反馈历史

查看反馈历史:

dart 复制代码
ListTile(
  title: const Text('我的反馈'),
  trailing: const Icon(Icons.chevron_right),
  onTap: () {
    Navigator.push(
      context,
      MaterialPageRoute(builder: (_) => const FeedbackHistoryPage()),
    );
  },
)

用户可以查看自己提交过的反馈。

总结

本文详细介绍了口腔护理 App 中意见反馈功能的实现。通过合理的表单设计和交互逻辑,我们构建了一个用户友好的反馈页面。核心技术点包括:

  • 使用 ChoiceChip 实现类型选择
  • 通过 TextField 实现多行文本输入
  • 使用 maxLength 限制输入字数
  • 表单验证和提交状态管理

意见反馈是应用与用户沟通的重要渠道,希望本文的实现对你有所帮助。

欢迎加入开源鸿蒙跨平台社区:https://openharmonycrossplatform.csdn.net

相关推荐
峥嵘life2 小时前
Android 16 EDLA测试STS模块
android·大数据·linux·学习
TheNextByte12 小时前
如何打印Android手机联系人?
android·智能手机
Trae1ounG2 小时前
Vue Iframe
前端·javascript·vue.js
爱上妖精的尾巴3 小时前
8-1 WPS JS宏 String.raw等关于字符串的3种引用方式
前端·javascript·vue.js·wps·js宏·jsa
hvang19883 小时前
某花顺隐藏了重仓涨幅,通过chrome插件计算基金的重仓涨幅
前端·javascript·chrome
web打印社区3 小时前
vue页面打印:printjs实现与进阶方案推荐
前端·javascript·vue.js·electron·html
向哆哆3 小时前
用 Flutter × OpenHarmony 构建智能健康提醒应用:健康档案管理实战
flutter·开源·鸿蒙·openharmony·开源鸿蒙
泡泡以安3 小时前
Android 逆向实战:从零突破某电商 App 登录接口全参数加密
android·爬虫·安卓逆向
菜鸟小芯4 小时前
【开源鸿蒙跨平台开发先锋训练营】DAY8~DAY13 底部选项卡&动态功能实现
flutter·harmonyos