前言

设置页面是App中不可或缺的部分,用户可以在这里调整各种偏好选项。一个好的设置页面应该分类清晰、操作便捷。本篇我们来实现音乐播放器的设置页面,包含播放设置、下载设置、通知设置、缓存管理等多个功能模块,同时还会实现弹窗选择和确认对话框。

功能规划

设置页面按功能分为五个区块:播放设置(自动播放、仅WiFi播放、高品质音效、桌面歌词)、下载设置(下载音质、下载路径、最大同时下载数)、通知设置(推送通知开关)、缓存管理(清除缓存、缓存上限)、其他(隐私政策、用户协议、检查更新)。页面底部还有一个退出登录按钮。

状态管理

设置页面有多个开关选项需要管理状态,所以使用 StatefulWidget

class SettingsPage extends StatefulWidget {
  const SettingsPage({super.key});

  
  State<SettingsPage> createState() => _SettingsPageState();
}

在状态类中定义各个开关的状态变量:

class _SettingsPageState extends State<SettingsPage> {
  bool _autoPlay = true;
  bool _wifiOnly = true;
  bool _highQuality = false;
  bool _notification = true;
  bool _lyrics = true;

这里定义了5个布尔变量,分别控制自动播放、仅WiFi播放、高品质音效、推送通知和桌面歌词的开关状态。默认值根据常见的用户习惯设置,比如自动播放和仅WiFi播放默认开启,高品质音效默认关闭(考虑到流量消耗)。

页面整体结构

设置页面使用 ListView 作为容器,方便内容滚动:

  
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: const Text('设置')),
      body: ListView(
        children: [
          _buildSection('播放设置', [
            _buildSwitchTile('自动播放', '打开APP自动播放上次歌曲', _autoPlay, 
              (v) => setState(() => _autoPlay = v)),
            _buildSwitchTile('仅WiFi播放', '移动网络下不自动播放', _wifiOnly, 
              (v) => setState(() => _wifiOnly = v)),
            _buildSwitchTile('高品质音效', '优先播放高品质音源', _highQuality, 
              (v) => setState(() => _highQuality = v)),
            _buildSwitchTile('桌面歌词', '在桌面显示歌词', _lyrics, 
              (v) => setState(() => _lyrics = v)),
          ]),

每个设置区块通过 _buildSection 方法构建,传入区块标题和子项列表。开关类型的设置项使用 _buildSwitchTile 方法,传入标题、副标题、当前值和值变化回调。

继续添加其他设置区块:

          _buildSection('下载设置', [
            _buildNavigationTile('下载音质', '标准品质', () => _showQualityDialog()),
            _buildNavigationTile('下载路径', '/storage/Music', () {}),
            _buildNavigationTile('最大同时下载', '3', () {}),
          ]),
          _buildSection('通知设置', [
            _buildSwitchTile('推送通知', '接收新歌推荐等通知', _notification, 
              (v) => setState(() => _notification = v)),
          ]),
          _buildSection('缓存管理', [
            _buildNavigationTile('清除缓存', '256.8 MB', () => _showClearCacheDialog()),
            _buildNavigationTile('缓存上限', '1 GB', () {}),
          ]),

下载设置和缓存管理使用 _buildNavigationTile 方法,这类设置项点击后会跳转到新页面或弹出选择框,而不是简单的开关切换。

          _buildSection('其他', [
            _buildNavigationTile('隐私政策', '', () {}),
            _buildNavigationTile('用户协议', '', () {}),
            _buildNavigationTile('检查更新', '当前版本 2.1.3', () {}),
          ]),

其他区块包含隐私政策、用户协议和版本检查,这些是App的标配功能。

退出登录按钮

页面底部放置退出登录按钮,使用红色调提示这是一个需要谨慎操作的功能:

          const SizedBox(height: 20),
          Padding(
            padding: const EdgeInsets.symmetric(horizontal: 16),
            child: ElevatedButton(
              style: ElevatedButton.styleFrom(
                backgroundColor: Colors.red.withOpacity(0.2), 
                foregroundColor: Colors.red, 
                padding: const EdgeInsets.symmetric(vertical: 16)
              ),
              onPressed: () => _showLogoutDialog(),
              child: const Text('退出登录'),
            ),
          ),
          const SizedBox(height: 40),
        ],
      ),
    );
  }

按钮背景使用红色的20%透明度,文字使用红色,这种设计既醒目又不会过于刺眼。点击按钮会弹出确认对话框,避免用户误操作。

区块构建方法

_buildSection 方法用于构建每个设置区块:

  Widget _buildSection(String title, List<Widget> children) {
    return Column(
      crossAxisAlignment: CrossAxisAlignment.start,
      children: [
        Padding(
          padding: const EdgeInsets.fromLTRB(16, 20, 16, 8), 
          child: Text(title, style: const TextStyle(color: Colors.grey, fontSize: 14))
        ),
        Container(
          color: const Color(0xFF1E1E1E), 
          child: Column(children: children)
        ),
      ],
    );
  }

每个区块由标题和内容两部分组成。标题使用灰色小字,与内容区域形成视觉层次。内容区域使用深灰色背景,与页面背景区分开来。fromLTRB 方法可以分别设置左、上、右、下四个方向的内边距。

开关设置项

_buildSwitchTile 方法用于构建带开关的设置项:

  Widget _buildSwitchTile(String title, String subtitle, bool value, 
    Function(bool) onChanged) {
    return ListTile(
      title: Text(title),
      subtitle: Text(subtitle, 
        style: const TextStyle(color: Colors.grey, fontSize: 12)),
      trailing: Switch(
        value: value, 
        activeColor: const Color(0xFFE91E63), 
        onChanged: onChanged
      ),
    );
  }

ListTile 是Flutter提供的列表项组件,自带标题、副标题、前置图标、后置组件等属性,非常适合构建设置项。trailing 属性放置 Switch 开关组件,activeColor 设置开关打开时的颜色为主题粉色。

导航设置项

_buildNavigationTile 方法用于构建点击跳转的设置项:

  Widget _buildNavigationTile(String title, String value, VoidCallback onTap) {
    return ListTile(
      title: Text(title),
      trailing: Row(
        mainAxisSize: MainAxisSize.min, 
        children: [
          Text(value, style: const TextStyle(color: Colors.grey)), 
          const SizedBox(width: 8), 
          const Icon(Icons.chevron_right, color: Colors.grey)
        ]
      ),
      onTap: onTap,
    );
  }

trailing 使用 Row 组合当前值文字和右箭头图标。mainAxisSize: MainAxisSize.minRow 只占用必要的宽度,不会撑满整个 trailing 区域。右箭头图标提示用户这是一个可点击的项目。

音质选择对话框

点击"下载音质"会弹出选择对话框:

  void _showQualityDialog() {
    showDialog(
      context: context,
      builder: (context) => AlertDialog(
        backgroundColor: const Color(0xFF1E1E1E),
        title: const Text('选择下载音质'),
        content: Column(
          mainAxisSize: MainAxisSize.min,
          children: ['标准品质 (128kbps)', '高品质 (320kbps)', '无损品质 (FLAC)']
            .map((q) => ListTile(
              title: Text(q), 
              onTap: () => Get.back()
            )).toList(),
        ),
      ),
    );
  }

AlertDialog 是Flutter的标准对话框组件。backgroundColor 设置为深灰色与整体主题一致。content 使用 Column 包裹三个选项,每个选项是一个 ListTilemainAxisSize: MainAxisSize.min 让对话框高度自适应内容。点击选项后调用 Get.back() 关闭对话框。

清除缓存确认框

清除缓存是一个不可逆操作,需要用户确认:

  void _showClearCacheDialog() {
    showDialog(
      context: context,
      builder: (context) => AlertDialog(
        backgroundColor: const Color(0xFF1E1E1E),
        title: const Text('清除缓存'),
        content: const Text('确定要清除所有缓存吗?'),
        actions: [
          TextButton(
            onPressed: () => Get.back(), 
            child: const Text('取消')
          ),
          TextButton(
            onPressed: () => Get.back(), 
            child: const Text('确定', style: TextStyle(color: Color(0xFFE91E63)))
          ),
        ],
      ),
    );
  }

确认对话框使用 actions 属性放置操作按钮。取消按钮使用默认样式,确定按钮使用粉色文字突出显示。实际项目中,点击确定后应该执行清除缓存的逻辑,然后更新界面显示的缓存大小。

退出登录确认框

退出登录同样需要确认,避免误操作:

  void _showLogoutDialog() {
    showDialog(
      context: context,
      builder: (context) => AlertDialog(
        backgroundColor: const Color(0xFF1E1E1E),
        title: const Text('退出登录'),
        content: const Text('确定要退出当前账号吗?'),
        actions: [
          TextButton(
            onPressed: () => Get.back(), 
            child: const Text('取消')
          ),
          TextButton(
            onPressed: () => Get.back(), 
            child: const Text('确定', style: TextStyle(color: Colors.red))
          ),
        ],
      ),
    );
  }

退出登录的确定按钮使用红色文字,与页面上的退出登录按钮风格一致,强调这是一个需要谨慎的操作。

页面入口

设置页面的入口在个人中心页面的右上角:

appBar: AppBar(
  title: const Text('我的'), 
  actions: [
    IconButton(
      icon: const Icon(Icons.settings), 
      onPressed: () => Get.to(() => const SettingsPage())
    )
  ]
),

使用齿轮图标 Icons.settings 作为设置入口,这是用户熟悉的设计模式。

小结

本篇我们实现了一个功能完善的设置页面,包含多种类型的设置项:开关类型使用 Switch 组件,选择类型使用弹窗,危险操作使用确认对话框。通过 _buildSection_buildSwitchTile_buildNavigationTile 三个方法的封装,代码结构清晰,易于维护和扩展。在实际项目中,这些设置项的值应该持久化存储,可以使用 shared_preferences 或其他本地存储方案。


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

Logo

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

更多推荐