Flutter for OpenHarmony衣橱管家App实战:设置功能实现
本文介绍了衣橱管家App设置功能的实现方案。主要内容包括: 设置页面整体采用ListView结构,分为通知设置、显示设置和数据管理三大模块 每个模块使用分组标题区分,包含开关设置项和可点击选项 实现了开关设置项组件,支持自定义标题、副标题和开关状态 语言选择通过对话框实现,提供单选功能 数据管理模块包含自动备份、数据导出/导入和清除缓存功能 设置页面遵循简洁明了的设计原则,通过合理的分组和清晰的说

设置页面是每个App的标配,它让用户能够根据自己的喜好定制App的行为。今天我们来实现衣橱管家App的设置功能,包括通知设置、显示设置、数据管理等模块。
设置功能的设计原则
好的设置页面应该简洁明了,让用户能够快速找到想要调整的选项。我们按功能分组,每组有明确的标题,选项使用开关或列表项的形式呈现。
设置项不宜过多,只保留用户真正需要的选项。过多的设置会让用户感到困惑,反而降低使用体验。
页面整体结构
设置页面使用ListView展示各个设置分组,每个分组包含标题和若干设置项。
import 'package:flutter/material.dart';
import 'package:flutter_screenutil/flutter_screenutil.dart';
class SettingsScreen extends StatefulWidget {
const SettingsScreen({super.key});
State<SettingsScreen> createState() => _SettingsScreenState();
}
class _SettingsScreenState extends State<SettingsScreen> {
bool _notificationEnabled = true;
bool _darkMode = false;
bool _autoBackup = true;
String _language = '简体中文';
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: const Text('设置')),
body: ListView(
children: [
_buildSectionTitle('通知设置'),
_buildSwitchTile('穿搭提醒', '每日推送穿搭建议', _notificationEnabled, (v) => setState(() => _notificationEnabled = v)),
// 更多设置项
],
),
);
}
}
StatefulWidget用于管理设置项的状态,每个开关对应一个bool变量。ListView直接使用children,因为设置项数量固定。
状态变量在类顶部声明,方便管理和查看。setState触发界面刷新,更新开关状态。
分组标题组件
每个设置分组都有一个标题,用于说明该组设置的用途。
Widget _buildSectionTitle(String title) {
return Padding(
padding: EdgeInsets.fromLTRB(16.w, 16.h, 16.w, 8.h),
child: Text(title, style: TextStyle(fontSize: 14.sp, color: Colors.grey, fontWeight: FontWeight.bold)),
);
}
分组标题使用灰色小字,与设置项的黑色文字形成区分。上边距16,下边距8,让标题与上一组有足够间隔,与本组设置项靠近。
fontWeight设为bold,虽然字号小但依然醒目。这种设计在iOS和Android的系统设置中都很常见。
开关设置项
开关设置项用于控制是否启用某个功能,使用SwitchListTile组件实现。
Widget _buildSwitchTile(String title, String subtitle, bool value, ValueChanged<bool> onChanged) {
return SwitchListTile(
title: Text(title),
subtitle: Text(subtitle),
value: value,
activeColor: const Color(0xFFE91E63),
onChanged: onChanged,
);
}
SwitchListTile是Material Design提供的开关列表项组件,集成了标题、副标题和开关。activeColor设置开关打开时的颜色为品牌色。
onChanged回调在开关状态改变时触发,传入新的bool值。这个方法可以复用于所有开关设置项。
通知设置分组
通知设置让用户控制App的推送行为。
_buildSectionTitle('通知设置'),
_buildSwitchTile('穿搭提醒', '每日推送穿搭建议', _notificationEnabled, (v) => setState(() => _notificationEnabled = v)),
_buildSwitchTile('洗衣提醒', '待洗衣物超过5件时提醒', true, (v) {}),
_buildSwitchTile('预算提醒', '预算使用超过80%时提醒', true, (v) {}),
三个通知选项覆盖了App的主要提醒场景:穿搭建议、洗衣提醒、预算提醒。每个选项都有清晰的说明文字。
副标题说明触发条件,让用户知道什么情况下会收到通知。
显示设置分组
显示设置让用户调整App的外观。
_buildSectionTitle('显示设置'),
_buildSwitchTile('深色模式', '切换深色/浅色主题', _darkMode, (v) => setState(() => _darkMode = v)),
ListTile(
title: const Text('语言'),
subtitle: Text(_language),
trailing: const Icon(Icons.chevron_right),
onTap: () => _showLanguageDialog(),
),
深色模式使用开关控制,语言选择使用列表项点击后弹出选择对话框。trailing的右箭头图标暗示用户这个选项可以点击进入。
subtitle显示当前选择的语言,让用户不用点击就能看到当前设置。
语言选择对话框
点击语言选项后弹出对话框,让用户选择语言。
void _showLanguageDialog() {
showDialog(
context: context,
builder: (context) => AlertDialog(
title: const Text('选择语言'),
content: Column(
mainAxisSize: MainAxisSize.min,
children: ['简体中文', 'English', '日本語'].map((lang) {
return RadioListTile<String>(
title: Text(lang),
value: lang,
groupValue: _language,
onChanged: (v) {
setState(() => _language = v!);
Navigator.pop(context);
},
);
}).toList(),
),
),
);
}
RadioListTile实现单选列表,groupValue是当前选中的值,value是该选项的值。选中后更新状态并关闭对话框。
mainAxisSize设为min让Column只占用必要的高度。三种语言覆盖了主要的用户群体。
数据管理分组
数据管理让用户控制数据的备份和恢复。
_buildSectionTitle('数据管理'),
_buildSwitchTile('自动备份', '自动备份衣橱数据', _autoBackup, (v) => setState(() => _autoBackup = v)),
ListTile(
title: const Text('导出数据'),
subtitle: const Text('导出衣橱数据到本地'),
trailing: const Icon(Icons.chevron_right),
onTap: () => ScaffoldMessenger.of(context).showSnackBar(const SnackBar(content: Text('功能开发中'))),
),
ListTile(
title: const Text('导入数据'),
subtitle: const Text('从备份文件恢复数据'),
trailing: const Icon(Icons.chevron_right),
onTap: () => ScaffoldMessenger.of(context).showSnackBar(const SnackBar(content: Text('功能开发中'))),
),
ListTile(
title: const Text('清除缓存'),
subtitle: const Text('清除应用缓存数据'),
trailing: const Icon(Icons.chevron_right),
onTap: () => _showClearCacheDialog(),
),
数据管理包含自动备份开关、导出数据、导入数据、清除缓存四个选项。导出导入功能暂时显示开发中提示。
清除缓存需要确认,避免用户误操作。
清除缓存对话框
清除缓存前需要用户确认。
void _showClearCacheDialog() {
showDialog(
context: context,
builder: (context) => AlertDialog(
title: const Text('清除缓存'),
content: const Text('确定要清除应用缓存吗?'),
actions: [
TextButton(onPressed: () => Navigator.pop(context), child: const Text('取消')),
TextButton(
onPressed: () {
Navigator.pop(context);
ScaffoldMessenger.of(context).showSnackBar(const SnackBar(content: Text('缓存已清除')));
},
child: const Text('确定'),
),
],
),
);
}
确认对话框包含取消和确定两个按钮,符合用户习惯。确定后显示SnackBar提示操作成功。
实际项目中需要调用清除缓存的逻辑,这里只是展示UI交互。
账号设置分组
账号设置包含重置数据等危险操作。
_buildSectionTitle('账号'),
ListTile(
title: const Text('重置数据'),
subtitle: const Text('清除所有衣橱数据'),
trailing: const Icon(Icons.chevron_right, color: Colors.red),
onTap: () => _showResetDialog(),
),
重置数据是危险操作,trailing图标使用红色警示。点击后弹出确认对话框,需要用户明确确认。
这种设计防止用户误操作导致数据丢失。
重置数据对话框
重置数据需要更强的确认,提示用户操作不可恢复。
void _showResetDialog() {
showDialog(
context: context,
builder: (context) => AlertDialog(
title: const Text('重置数据'),
content: const Text('此操作将清除所有衣橱数据,且无法恢复。确定要继续吗?'),
actions: [
TextButton(onPressed: () => Navigator.pop(context), child: const Text('取消')),
TextButton(
onPressed: () {
Navigator.pop(context);
ScaffoldMessenger.of(context).showSnackBar(const SnackBar(content: Text('数据已重置')));
},
child: const Text('重置', style: TextStyle(color: Colors.red)),
),
],
),
);
}
对话框内容明确说明操作不可恢复,让用户充分了解后果。确定按钮使用红色文字,强调危险性。
实际项目中需要调用清除数据的逻辑,并可能需要退出登录或重启App。
版本信息展示
在设置页面底部显示App版本信息。
Widget _buildVersionInfo() {
return Padding(
padding: EdgeInsets.all(16.w),
child: Center(
child: Column(
children: [
Text('衣橱管家', style: TextStyle(fontSize: 16.sp, fontWeight: FontWeight.bold)),
SizedBox(height: 4.h),
Text('版本 1.0.0', style: TextStyle(fontSize: 12.sp, color: Colors.grey)),
SizedBox(height: 4.h),
Text('© 2024 OpenHarmony', style: TextStyle(fontSize: 12.sp, color: Colors.grey)),
],
),
),
);
}
版本信息居中显示,包含App名称、版本号和版权信息。使用灰色小字,不抢眼但能被注意到。
版本号在用户反馈问题时很有用,方便开发者定位问题。
设置持久化
设置项的值需要持久化存储,下次打开App时恢复。
void initState() {
super.initState();
_loadSettings();
}
Future<void> _loadSettings() async {
final prefs = await SharedPreferences.getInstance();
setState(() {
_notificationEnabled = prefs.getBool('notification_enabled') ?? true;
_darkMode = prefs.getBool('dark_mode') ?? false;
_autoBackup = prefs.getBool('auto_backup') ?? true;
_language = prefs.getString('language') ?? '简体中文';
});
}
Future<void> _saveSetting(String key, dynamic value) async {
final prefs = await SharedPreferences.getInstance();
if (value is bool) {
await prefs.setBool(key, value);
} else if (value is String) {
await prefs.setString(key, value);
}
}
SharedPreferences是Flutter常用的本地存储方案,适合存储简单的键值对。initState中加载设置,每次修改时保存。
_saveSetting方法根据值的类型调用不同的set方法,支持bool和String两种类型。
深色模式实现
深色模式需要在App级别切换主题。
// 在main.dart中
class MyApp extends StatefulWidget {
State<MyApp> createState() => _MyAppState();
}
class _MyAppState extends State<MyApp> {
ThemeMode _themeMode = ThemeMode.light;
void setThemeMode(ThemeMode mode) {
setState(() => _themeMode = mode);
}
Widget build(BuildContext context) {
return MaterialApp(
themeMode: _themeMode,
theme: ThemeData.light(),
darkTheme: ThemeData.dark(),
// ...
);
}
}
MaterialApp的themeMode属性控制使用哪个主题,theme是浅色主题,darkTheme是深色主题。
设置页面修改深色模式开关时,需要调用App级别的setThemeMode方法。可以使用Provider或其他状态管理方案实现。
关于页面入口
设置页面通常包含关于页面的入口。
ListTile(
title: const Text('关于我们'),
trailing: const Icon(Icons.chevron_right),
onTap: () => Navigator.push(
context,
MaterialPageRoute(builder: (_) => const AboutScreen()),
),
),
ListTile(
title: const Text('使用帮助'),
trailing: const Icon(Icons.chevron_right),
onTap: () => Navigator.push(
context,
MaterialPageRoute(builder: (_) => const HelpScreen()),
),
),
ListTile(
title: const Text('意见反馈'),
trailing: const Icon(Icons.chevron_right),
onTap: () => Navigator.push(
context,
MaterialPageRoute(builder: (_) => const FeedbackScreen()),
),
),
关于我们、使用帮助、意见反馈是常见的设置项,点击后跳转到对应页面。
这些入口让用户能够了解App信息、获取帮助、提交反馈。
完整代码整合
把所有功能整合在一起,形成完整的设置页面。
import 'package:flutter/material.dart';
import 'package:flutter_screenutil/flutter_screenutil.dart';
class SettingsScreen extends StatefulWidget {
const SettingsScreen({super.key});
State<SettingsScreen> createState() => _SettingsScreenState();
}
class _SettingsScreenState extends State<SettingsScreen> {
bool _notificationEnabled = true;
bool _darkMode = false;
bool _autoBackup = true;
String _language = '简体中文';
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: const Text('设置')),
body: ListView(
children: [
_buildSectionTitle('通知设置'),
_buildSwitchTile('穿搭提醒', '每日推送穿搭建议', _notificationEnabled, (v) => setState(() => _notificationEnabled = v)),
_buildSwitchTile('洗衣提醒', '待洗衣物超过5件时提醒', true, (v) {}),
_buildSwitchTile('预算提醒', '预算使用超过80%时提醒', true, (v) {}),
_buildSectionTitle('显示设置'),
_buildSwitchTile('深色模式', '切换深色/浅色主题', _darkMode, (v) => setState(() => _darkMode = v)),
ListTile(
title: const Text('语言'),
subtitle: Text(_language),
trailing: const Icon(Icons.chevron_right),
onTap: () => _showLanguageDialog(),
),
_buildSectionTitle('数据管理'),
_buildSwitchTile('自动备份', '自动备份衣橱数据', _autoBackup, (v) => setState(() => _autoBackup = v)),
ListTile(
title: const Text('导出数据'),
subtitle: const Text('导出衣橱数据到本地'),
trailing: const Icon(Icons.chevron_right),
onTap: () => ScaffoldMessenger.of(context).showSnackBar(const SnackBar(content: Text('功能开发中'))),
),
ListTile(
title: const Text('导入数据'),
subtitle: const Text('从备份文件恢复数据'),
trailing: const Icon(Icons.chevron_right),
onTap: () => ScaffoldMessenger.of(context).showSnackBar(const SnackBar(content: Text('功能开发中'))),
),
ListTile(
title: const Text('清除缓存'),
subtitle: const Text('清除应用缓存数据'),
trailing: const Icon(Icons.chevron_right),
onTap: () => _showClearCacheDialog(),
),
_buildSectionTitle('账号'),
ListTile(
title: const Text('重置数据'),
subtitle: const Text('清除所有衣橱数据'),
trailing: const Icon(Icons.chevron_right, color: Colors.red),
onTap: () => _showResetDialog(),
),
],
),
);
}
Widget _buildSectionTitle(String title) {
return Padding(
padding: EdgeInsets.fromLTRB(16.w, 16.h, 16.w, 8.h),
child: Text(title, style: TextStyle(fontSize: 14.sp, color: Colors.grey, fontWeight: FontWeight.bold)),
);
}
Widget _buildSwitchTile(String title, String subtitle, bool value, ValueChanged<bool> onChanged) {
return SwitchListTile(
title: Text(title),
subtitle: Text(subtitle),
value: value,
activeColor: const Color(0xFFE91E63),
onChanged: onChanged,
);
}
void _showLanguageDialog() {
showDialog(
context: context,
builder: (context) => AlertDialog(
title: const Text('选择语言'),
content: Column(
mainAxisSize: MainAxisSize.min,
children: ['简体中文', 'English', '日本語'].map((lang) {
return RadioListTile<String>(
title: Text(lang),
value: lang,
groupValue: _language,
onChanged: (v) {
setState(() => _language = v!);
Navigator.pop(context);
},
);
}).toList(),
),
),
);
}
void _showClearCacheDialog() {
showDialog(
context: context,
builder: (context) => AlertDialog(
title: const Text('清除缓存'),
content: const Text('确定要清除应用缓存吗?'),
actions: [
TextButton(onPressed: () => Navigator.pop(context), child: const Text('取消')),
TextButton(
onPressed: () {
Navigator.pop(context);
ScaffoldMessenger.of(context).showSnackBar(const SnackBar(content: Text('缓存已清除')));
},
child: const Text('确定'),
),
],
),
);
}
void _showResetDialog() {
showDialog(
context: context,
builder: (context) => AlertDialog(
title: const Text('重置数据'),
content: const Text('此操作将清除所有衣橱数据,且无法恢复。确定要继续吗?'),
actions: [
TextButton(onPressed: () => Navigator.pop(context), child: const Text('取消')),
TextButton(
onPressed: () {
Navigator.pop(context);
ScaffoldMessenger.of(context).showSnackBar(const SnackBar(content: Text('数据已重置')));
},
child: const Text('重置', style: TextStyle(color: Colors.red)),
),
],
),
);
}
}
代码结构清晰,设置项按分组排列,每个分组有明确的标题。_buildSectionTitle和_buildSwitchTile方法实现代码复用。
对话框方法独立封装,便于维护和测试。危险操作使用红色警示,防止误操作。
写在最后
设置页面虽然不是App的核心功能,但它直接影响用户的使用体验。一个好的设置页面应该简洁明了,让用户能够快速找到想要调整的选项。
希望这篇文章能帮助你实现一个完善的设置功能,让用户能够根据自己的喜好定制App。
欢迎加入开源鸿蒙跨平台社区:https://openharmonycrossplatform.csdn.net
更多推荐



所有评论(0)