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

相关推荐
哈哈浩丶22 分钟前
ATF (ARM Trusted Firmware) -2:完整启动流程(冷启动)
android·linux·arm开发·驱动开发
哈哈浩丶26 分钟前
ATF (ARM Trusted Firmware) -3:完整启动流程(热启动)
android·linux·arm开发
哈哈浩丶33 分钟前
OP-TEE-OS:综述
android·linux·驱动开发
Highcharts.js34 分钟前
Highcharts跨域数据加载完全指南:JSONP原理与实战
javascript·数据库·开发文档·highcharts·图表开发·跨域数据
九狼JIULANG36 分钟前
Flutter SSE 流式响应用 Dio 实现 OpenAI 兼容接口的逐 Token 输出
flutter
skywalk81631 小时前
electrobun 使用TypeScript构建超快速、小巧且跨平台的桌面应用程序(待续)
前端·javascript·typescript
薛一半3 小时前
React的数据绑定
前端·javascript·react.js
爱看书的小沐3 小时前
【小沐杂货铺】基于Three.js渲染三维无人机Drone(WebGL / vue / react )
javascript·vue.js·react.js·无人机·webgl·three.js·drone
ShenJLLL10 小时前
vue部分知识点.
前端·javascript·vue.js·前端框架
恋猫de小郭10 小时前
你是不是觉得 R8 很讨厌,但 Android 为什么选择 R8 ?也许你对 R8 还不够了解
android·前端·flutter