在这里插入图片描述

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

🎯 欢迎来到 Flutter for OpenHarmony 社区!本文将深入讲解 Flutter 中 Switch 开关组件的使用方法,带你从基础到精通,掌握这一常见的开关控件。


一、Switch 组件概述

在 Flutter for OpenHarmony 应用开发中,Switch(开关)是一种用于二元状态切换的常见控件。用户可以通过点击或滑动来切换开关的状态,适用于表示"开/关"、“是/否”、"启用/禁用"等二元选择的场景。

📋 Switch 组件特点

特点 说明
二元状态 只有两个状态:开启(true)和关闭(false)
Material Design 遵循 Material Design 规范的开关样式
动画效果 开关切换时有平滑的动画过渡
触摸友好 提供较大的触摸区域,易于操作
可定制 支持自定义颜色、大小、圆角等样式

💡 使用场景:开关组件常用于设置页面中的功能启用/禁用,如推送通知开关、飞行模式开关、深色模式开关等。


二、Switch 基础用法

学习任何组件,我们都应该从最简单的用法开始。Switch 组件的核心功能非常简单:控制一个二元状态的切换。让我们一步步来理解它的基本使用方式。

2.1 最简单的 Switch

最基础的 Switch 只需要两个参数:value(当前状态)和 onChanged(状态改变时的回调)。

Switch(
  value: _isSwitched,
  onChanged: (bool value) {
    setState(() {
      _isSwitched = value;
    });
  },
)

代码解析:

  • value:这是一个布尔值,决定了开关的当前状态。true 表示开关处于开启状态,false 表示关闭状态。
  • onChanged:这是一个回调函数,当用户点击或滑动开关时会触发。回调函数会接收一个布尔参数,代表开关的新状态。
  • setState:这是 Flutter 中更新 UI 的关键方法。当我们修改状态后,必须调用 setState 来告诉 Flutter 重新构建界面。

⚠️ 注意:如果忘记调用 setState,UI 将不会更新,用户会看到开关"卡住"的状态。

2.2 完整示例

下面是一个完整的可运行示例,展示了如何在实际应用中使用 Switch 组件:

2.2 完整示例

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

  
  State<SwitchExample> createState() => _SwitchExampleState();
}

class _SwitchExampleState extends State<SwitchExample> {
  bool _isSwitched = false;

  
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: const Text('Switch 示例')),
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: [
            Switch(
              value: _isSwitched,
              onChanged: (bool value) {
                setState(() {
                  _isSwitched = value;
                });
              },
            ),
            const SizedBox(height: 16),
            Text(
              '当前状态: ${_isSwitched ? "开启" : "关闭"}',
              style: const TextStyle(fontSize: 18),
            ),
          ],
        ),
      ),
    );
  }
}

三、Switch 常用属性

掌握了基础用法后,我们来深入了解 Switch 的各种属性。这些属性可以帮助我们自定义开关的外观和行为,使其更好地融入我们的应用设计。

3.1 value - 当前状态

控制开关的当前状态,true 表示开启,false 表示关闭。这是 Switch 组件的必填参数。

Switch(
  value: true,  // 开启状态
  onChanged: (value) {},
)

使用技巧:

  • 通常我们会将 value 绑定到一个状态变量上,这样开关的状态就可以动态更新。
  • 在实际开发中,value 的值可能来自应用的全局状态管理,或者是从后端 API 获取的配置。

3.2 onChanged - 状态改变回调

当用户点击开关时触发,接收新状态作为参数。设为 null 时开关禁用。

Switch(
  value: _isSwitched,
  onChanged: (bool value) {
    print('开关状态变为: $value');
    setState(() {
      _isSwitched = value;
    });
  },
)

深入理解:

  • onChanged 不仅仅是更新 UI 的地方,更是处理业务逻辑的关键节点。
  • 在这个回调中,你可以:
    • 更新本地状态(如上面的示例)
    • 调用 API 保存用户设置
    • 触发其他相关的业务逻辑
    • 发送事件通知其他组件

3.3 activeColor - 激活状态颜色

设置开关处于开启状态时的颜色。这个属性帮助你将开关的视觉风格与应用的主题色保持一致。

Switch(
  value: _isSwitched,
  activeColor: Colors.green,
  onChanged: (value) {},
)

设计建议:

  • 使用应用的主色调作为激活颜色,可以增强品牌识别度。
  • 不同的开关可以使用不同的颜色来区分其功能(例如:绿色表示"启用",红色表示"危险操作")。

3.4 activeTrackColor - 激活状态轨道颜色

设置开关开启时轨道的颜色。轨道是指开关滑块下方的背景条。

Switch(
  value: _isSwitched,
  activeTrackColor: Colors.green.withOpacity(0.5),
  onChanged: (value) {},
)

视觉效果技巧:

  • 通常将轨道颜色设置为激活颜色的半透明版本(withOpacity(0.5)),这样可以创造出层次感。
  • 轨道颜色和滑块颜色的搭配会影响开关的整体质感,建议多尝试不同的组合。

3.5 inactiveThumbColor - 关闭状态滑块颜色

设置开关关闭时滑块的颜色。

Switch(
  value: _isSwitched,
  inactiveThumbColor: Colors.grey,
  onChanged: (value) {},
)

最佳实践:

  • 关闭状态的颜色通常使用中性色(如灰色),以减少视觉干扰。
  • 保持关闭状态颜色的一致性,让用户能够快速识别哪些开关是关闭的。

3.6 inactiveTrackColor - 关闭状态轨道颜色

设置开关关闭时轨道的颜色。

3.2 onChanged - 状态改变回调

当用户点击开关时触发,接收新状态作为参数。设为 null 时开关禁用。

Switch(
  value: _isSwitched,
  onChanged: (bool value) {
    print('开关状态变为: $value');
    setState(() {
      _isSwitched = value;
    });
  },
)

3.3 activeColor - 激活状态颜色

设置开关处于开启状态时的颜色。

Switch(
  value: _isSwitched,
  activeColor: Colors.green,
  onChanged: (value) {},
)

3.4 activeTrackColor - 激活状态轨道颜色

设置开关开启时轨道的颜色。

Switch(
  value: _isSwitched,
  activeTrackColor: Colors.green.withOpacity(0.5),
  onChanged: (value) {},
)

3.5 inactiveThumbColor - 关闭状态滑块颜色

设置开关关闭时滑块的颜色。

Switch(
  value: _isSwitched,
  inactiveThumbColor: Colors.grey,
  onChanged: (value) {},
)

3.6 inactiveTrackColor - 关闭状态轨道颜色

设置开关关闭时轨道的颜色。

Switch(
  value: _isSwitched,
  inactiveTrackColor: Colors.grey.withOpacity(0.3),
  onChanged: (value) {},
)

3.7 materialTapTargetSize - 触摸目标大小

控制触摸区域的大小,影响可点击区域的范围。

Switch(
  value: _isSwitched,
  materialTapTargetSize: MaterialTapTargetSize.padded,
  onChanged: (value) {},
)
说明
padded 扩展触摸区域以适应 Material Design 规范(默认)
shrinkWrap 收缩触摸区域到组件实际大小

📊 Switch 属性速查表

属性 类型 默认值 说明
value bool - 当前开关状态(必填)
onChanged ValueChanged <bool>? - 状态改变回调
activeColor Color? - 激活状态滑块颜色
activeTrackColor Color? - 激活状态轨道颜色
inactiveThumbColor Color? - 关闭状态滑块颜色
inactiveTrackColor Color? - 关闭状态轨道颜色
materialTapTargetSize MaterialTapTargetSize? - 触摸目标大小

四、Switch 禁用状态

在某些情况下,你可能需要暂时禁用某个开关选项。例如,当某个功能依赖其他功能时,或者当用户权限不足时,就需要将开关设置为禁用状态。

onChanged 设为 null 即可禁用开关,禁用后用户无法点击切换。

Column(
  children: [
    Switch(
      value: true,
      onChanged: (value) {},  // 可用状态
    ),
    const SizedBox(height: 16),
    Switch(
      value: false,
      onChanged: null,  // 禁用状态
    ),
  ],
)

禁用状态的适用场景:

  1. 功能依赖:当某个功能需要先启用另一个功能时
  2. 权限限制:当用户没有足够的权限操作某个设置时
  3. 临时维护:当某个功能暂时不可用时
  4. 条件限制:当某些条件不满足时(例如网络断开时禁用在线同步开关)

💡 小贴士:禁用状态的开关通常显示为灰色,视觉上明确告知用户该选项当前不可用。建议在禁用开关时,通过文字说明或工具提示(Tooltip)告知用户禁用的原因,提升用户体验。


五、Switch 配合 ListTile 使用

在实际的应用开发中,单独使用 Switch 的情况并不多见。更常见的做法是将 Switch 与 ListTile 组件配合使用,形成标准的设置选项布局。这种组合可以提供更好的视觉层次和信息展示效果。

为什么要配合 ListTile 使用?

  1. 信息完整:ListTile 提供了标题、副标题、图标等多个信息展示区域,让用户清楚地了解每个开关的作用。
  2. 交互友好:整个 ListTile 都可以作为点击区域,增加了可操作的范围,提升用户体验。
  3. 视觉统一:ListTile 是 Material Design 规范中推荐的列表项组件,使用它可以保证界面风格的一致性。
  4. 易于维护:通过封装,可以轻松复用设置项的结构。

基础用法示例

ListTile(
  title: const Text('推送通知'),
  subtitle: const Text('接收应用推送消息'),
  leading: const Icon(Icons.notifications),
  trailing: Switch(
    value: _notificationsEnabled,
    onChanged: (bool value) {
      setState(() {
        _notificationsEnabled = value;
      });
    },
  ),
  onTap: () {
    setState(() {
      _notificationsEnabled = !_notificationsEnabled;
    });
  },
)

代码解析:

  • title:设置项的主标题,清晰说明这是什么功能
  • subtitle:可选的副标题,提供额外的说明信息
  • leading:左侧的图标,增强视觉识别度
  • trailing:右侧的 Switch 组件
  • onTap:点击整个 ListTile 时的回调,这里我们实现点击也能切换开关状态

💡 体验优化:让整个 ListTile 都可以点击切换开关,是一种很好的用户体验设计。用户不需要精确点击小小的开关,点击任何位置都可以完成操作。

5.1 完整设置页面示例

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

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

class _SettingsPageState extends State<SettingsPage> {
  bool _notificationsEnabled = true;
  bool _darkModeEnabled = false;
  bool _autoUpdateEnabled = true;

  
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: const Text('设置')),
      body: ListView(
        children: [
          _buildSwitchTile(
            title: '推送通知',
            subtitle: '接收应用推送消息',
            icon: Icons.notifications,
            value: _notificationsEnabled,
            onChanged: (value) {
              setState(() {
                _notificationsEnabled = value;
              });
            },
          ),
          _buildSwitchTile(
            title: '深色模式',
            subtitle: '使用深色主题',
            icon: Icons.dark_mode,
            value: _darkModeEnabled,
            onChanged: (value) {
              setState(() {
                _darkModeEnabled = value;
              });
            },
          ),
          _buildSwitchTile(
            title: '自动更新',
            subtitle: '自动更新应用',
            icon: Icons.system_update,
            value: _autoUpdateEnabled,
            onChanged: (value) {
              setState(() {
                _autoUpdateEnabled = value;
              });
            },
          ),
        ],
      ),
    );
  }

  Widget _buildSwitchTile({
    required String title,
    required String subtitle,
    required IconData icon,
    required bool value,
    required ValueChanged<bool> onChanged,
  }) {
    return ListTile(
      title: Text(title),
      subtitle: Text(subtitle),
      leading: Icon(icon),
      trailing: Switch(
        value: value,
        onChanged: onChanged,
      ),
      onTap: () => onChanged(!value),
    );
  }
}

六、自定义 Switch 样式

虽然 Switch 的默认样式已经符合 Material Design 规范,但在实际开发中,我们经常需要根据应用的品牌风格来定制开关的外观。Flutter 提供了丰富的属性让我们能够轻松实现各种个性化设计。

6.1 主题色 Switch

将开关的颜色与应用的主题色保持一致,是提升应用整体视觉统一性的重要手段。

Switch(
  value: _isSwitched,
  activeColor: Colors.blue,
  activeTrackColor: Colors.blue.withOpacity(0.5),
  inactiveThumbColor: Colors.grey,
  inactiveTrackColor: Colors.grey.withOpacity(0.3),
  onChanged: (value) {},
)

颜色搭配原则:

  1. 激活状态:使用鲜明的主题色,让开启状态一目了然
  2. 轨道颜色:使用激活色的半透明版本,营造层次感
  3. 关闭状态:使用中性灰色,避免引起视觉注意
  4. 保持一致:所有开关的颜色方案应该保持一致

6.2 自定义颜色组合

不同的应用场景可能需要不同的颜色方案。例如,表示"启用"的功能可以用绿色,表示"危险操作"的功能可以用红色。

Switch(
  value: _isSwitched,
  activeColor: const Color(0xFF10B981),  // 绿色
  activeTrackColor: const Color(0xFFD1FAE5),
  inactiveThumbColor: const Color(0xFF9CA3AF),
  inactiveTrackColor: const Color(0xFFF3F4F6),
  onChanged: (value) {},
)

色彩心理学应用:

  • 🟢 绿色:表示安全、成功、启用
  • 🔴 红色:表示危险、警告、删除
  • 🔵 蓝色:表示信息、中性、标准
  • 🟡 黄色:表示注意、警告
  • 🟣 紫色:表示高级、特殊功能

6.2 自定义颜色组合

Switch(
  value: _isSwitched,
  activeColor: const Color(0xFF10B981),  // 绿色
  activeTrackColor: const Color(0xFFD1FAE5),
  inactiveThumbColor: const Color(0xFF9CA3AF),
  inactiveTrackColor: const Color(0xFFF3F4F6),
  onChanged: (value) {},
)

6.3 不同尺寸的 Switch

虽然 Switch 组件本身没有提供直接的尺寸属性,但我们可以通过 Transform.scale 来调整开关的大小。这在需要突出重要功能或节省空间时非常有用。

Row(
  mainAxisAlignment: MainAxisAlignment.spaceEvenly,
  children: [
    Transform.scale(
      scale: 0.8,
      child: Switch(
        value: _isSwitched,
        onChanged: (value) {},
      ),
    ),
    Switch(
      value: _isSwitched,
      onChanged: (value) {},
    ),
    Transform.scale(
      scale: 1.2,
      child: Switch(
        value: _isSwitched,
        onChanged: (value) {},
      ),
    ),
  ],
)

尺寸选择建议:

场景 推荐尺寸 说明
密集列表 scale: 0.8 节省空间,适合信息密集的界面
标准设置 scale: 1.0 遵循 Material Design 规范
重要开关 scale: 1.2 突出显示,增强视觉重要性
无障碍优化 scale: 1.3+ 为视力障碍用户提供更大的操作目标

⚠️ 注意:虽然可以随意调整尺寸,但建议不要使用过大的缩放比例,以免破坏界面的整体协调性。


七、Switch 与 Checkbox 的对比

在 Flutter 中,Switch 和 Checkbox 都是用于表示选择的组件,初学者经常会混淆它们的用途。理解它们的区别,选择合适的组件,对于创建符合用户预期的界面非常重要。

📊 Switch vs Checkbox

特性 Switch Checkbox
状态含义 开启/关闭 选中/未选中
适用场景 设置选项、功能开关 多选列表、协议确认
视觉形式 滑动开关 勾选框
空间占用 横向占用较小 纵向占用较小
Material 3 使用自适应开关 使用自定义形状
用户心理 状态切换 选项选择
交互方式 点击或滑动 点击

如何选择?

使用 Switch 的场景:

  1. ✅ 功能开关:如"推送通知"、“深色模式”
  2. ✅ 状态切换:如"飞行模式"、“蓝牙”
  3. ✅ 设置选项:如"自动更新"、“省电模式”
  4. ✅ 独立控制:每个开关独立控制一个功能

使用 Checkbox 的场景:

  1. ✅ 多选列表:如选择多个联系人、选择多个文件
  2. ✅ 协议确认:如"同意服务条款"、“同意隐私政策”
  3. ✅ 选项选择:如选择兴趣爱好、选择技能标签
  4. ✅ 组合选择:多个选项的组合选择

💡 核心区别:Switch 表示"状态"的切换,Checkbox 表示"选项"的选择。如果是一个功能是开启还是关闭,用 Switch;如果是多个选项中哪些被选中,用 Checkbox。


八、实际应用场景

8.1 通知设置

Card(
  margin: const EdgeInsets.all(16),
  child: Column(
    children: [
      _buildSwitchSetting(
        title: '推送通知',
        subtitle: '接收推送消息',
        icon: Icons.notifications,
        value: _pushEnabled,
        onChanged: (value) => setState(() => _pushEnabled = value),
      ),
      _buildSwitchSetting(
        title: '声音提醒',
        subtitle: '新消息时播放声音',
        icon: Icons.volume_up,
        value: _soundEnabled,
        onChanged: (value) => setState(() => _soundEnabled = value),
      ),
      _buildSwitchSetting(
        title: '震动反馈',
        subtitle: '触感震动',
        icon: Icons.vibration,
        value: _vibrationEnabled,
        onChanged: (value) => setState(() => _vibrationEnabled = value),
      ),
    ],
  ),
)

Widget _buildSwitchSetting({
  required String title,
  required String subtitle,
  required IconData icon,
  required bool value,
  required ValueChanged<bool> onChanged,
}) {
  return ListTile(
    title: Text(title),
    subtitle: Text(subtitle),
    leading: Icon(icon),
    trailing: Switch(
      value: value,
      onChanged: onChanged,
    ),
    onTap: () => onChanged(!value),
  );
}

8.2 隐私设置

Card(
  margin: const EdgeInsets.all(16),
  child: Column(
    children: [
      _buildSwitchSetting(
        title: '位置信息',
        subtitle: '允许应用访问位置',
        icon: Icons.location_on,
        value: _locationEnabled,
        onChanged: (value) => setState(() => _locationEnabled = value),
      ),
      _buildSwitchSetting(
        title: '数据分析',
        subtitle: '帮助改进应用体验',
        icon: Icons.analytics,
        value: _analyticsEnabled,
        onChanged: (value) => setState(() => _analyticsEnabled = value),
      ),
      _buildSwitchSetting(
        title: '个性化推荐',
        subtitle: '根据喜好推荐内容',
        icon: Icons.recommend,
        value: _personalizationEnabled,
        onChanged: (value) => setState(() => _personalizationEnabled = value),
      ),
    ],
  ),
)

8.3 功能模块开关

Card(
  margin: const EdgeInsets.all(16),
  child: Column(
    children: [
      _buildSwitchSetting(
        title: '深色模式',
        subtitle: '使用深色主题',
        icon: Icons.dark_mode,
        value: _darkMode,
        onChanged: (value) {
          setState(() => _darkMode = value);
          // 切换主题逻辑
        },
      ),
      _buildSwitchSetting(
        title: '省电模式',
        subtitle: '降低功耗',
        icon: Icons.battery_saver,
        value: _powerSaving,
        onChanged: (value) => setState(() => _powerSaving = value),
      ),
      _buildSwitchSetting(
        title: '自动同步',
        subtitle: '自动同步数据',
        icon: Icons.sync,
        value: _autoSync,
        onChanged: (value) => setState(() => _autoSync = value),
      ),
    ],
  ),
)

九、完整示例代码

下面是一个完整的 Flutter 应用示例,展示 Switch 组件的各种用法。

import 'package:flutter/material.dart';

void main() {
  runApp(const SwitchDemo());
}

class SwitchDemo extends StatelessWidget {
  const SwitchDemo({super.key});

  
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Switch 组件演示',
      debugShowCheckedModeBanner: false,
      theme: ThemeData(
        colorScheme: ColorScheme.light(
          primary: const Color(0xFF6366F1),
          secondary: const Color(0xFF8B5CF6),
          surface: const Color(0xFFE8EAF6),
          background: const Color(0xFFF8F9FF),
          brightness: Brightness.light,
        ),
        useMaterial3: true,
      ),
      home: const SwitchPage(),
    );
  }
}

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

  
  State<SwitchPage> createState() => _SwitchPageState();
}

class _SwitchPageState extends State<SwitchPage> {
  bool _isSwitched = false;
  bool _notificationsEnabled = true;
  bool _darkModeEnabled = false;
  bool _locationEnabled = true;
  bool _analyticsEnabled = false;
  bool _greenSwitch = false;
  bool _purpleSwitch = false;
  bool _orangeSwitch = false;
  bool _smallSwitch = false;
  bool _normalSwitch = false;
  bool _largeSwitch = false;

  
  Widget build(BuildContext context) {
    return Scaffold(
      body: Container(
        decoration: const BoxDecoration(
          gradient: LinearGradient(
            begin: Alignment.topCenter,
            end: Alignment.bottomCenter,
            colors: [
              Color(0xFFE8F4FF),
              Color(0xFFF8F9FF),
              Color(0xFFE8F4FF),
            ],
          ),
        ),
        child: SafeArea(
          child: SingleChildScrollView(
            padding: const EdgeInsets.all(20),
            child: Column(
              crossAxisAlignment: CrossAxisAlignment.start,
              children: [
              // 标题区域
              Container(
                padding: const EdgeInsets.all(24),
                decoration: BoxDecoration(
                  gradient: const LinearGradient(
                    begin: Alignment.topLeft,
                    end: Alignment.bottomRight,
                    colors: [
                      Color(0xFF6366F1),
                      Color(0xFF8B5CF6),
                      Color(0xFFEC4899),
                    ],
                  ),
                  borderRadius: BorderRadius.circular(24),
                  boxShadow: [
                    BoxShadow(
                      color: const Color(0xFF6366F1).withOpacity(0.3),
                      blurRadius: 20,
                      offset: const Offset(0, 8),
                    ),
                  ],
                ),
                child: Column(
                  crossAxisAlignment: CrossAxisAlignment.start,
                  children: [
                    Row(
                      children: [
                        Container(
                          padding: const EdgeInsets.all(12),
                          decoration: BoxDecoration(
                            color: Colors.white.withOpacity(0.2),
                            borderRadius: BorderRadius.circular(12),
                          ),
                          child: const Icon(
                            Icons.toggle_on,
                            color: Colors.white,
                            size: 28,
                          ),
                        ),
                        const SizedBox(width: 16),
                        const Text(
                          'Switch',
                          style: TextStyle(
                            fontSize: 32,
                            fontWeight: FontWeight.bold,
                            color: Colors.white,
                            letterSpacing: 0.5,
                          ),
                        ),
                      ],
                    ),
                    const SizedBox(height: 12),
                    Text(
                      '探索 Flutter 中开关组件的各种用法',
                      style: TextStyle(
                        fontSize: 16,
                        color: Colors.white.withOpacity(0.9),
                        height: 1.5,
                      ),
                    ),
                  ],
                ),
              ),

              const SizedBox(height: 32),

              // 基础开关
              _buildSection(
                title: '基础开关',
                icon: Icons.toggle_on,
                color: Colors.blue,
                child: _buildCard([
                  Row(
                    mainAxisAlignment: MainAxisAlignment.spaceBetween,
                    children: [
                      const Text(
                        '基础开关',
                        style: TextStyle(
                          fontSize: 16,
                          fontWeight: FontWeight.w500,
                          color: Color(0xFF1E293B),
                        ),
                      ),
                      Switch(
                        value: _isSwitched,
                        onChanged: (value) {
                          setState(() {
                            _isSwitched = value;
                          });
                        },
                      ),
                    ],
                  ),
                  const SizedBox(height: 16),
                  Row(
                    mainAxisAlignment: MainAxisAlignment.spaceBetween,
                    children: [
                      const Text(
                        '禁用状态',
                        style: TextStyle(
                          fontSize: 16,
                          fontWeight: FontWeight.w500,
                          color: Color(0xFF94A3B8),
                        ),
                      ),
                      Switch(
                        value: false,
                        onChanged: null,
                      ),
                    ],
                  ),
                ]),
              ),

              const SizedBox(height: 24),

              // 自定义颜色
              _buildSection(
                title: '自定义颜色',
                icon: Icons.palette,
                color: Colors.green,
                child: _buildCard([
                  _buildCustomSwitch('绿色主题', Colors.green, _greenSwitch),
                  const SizedBox(height: 12),
                  _buildCustomSwitch('紫色主题', Colors.purple, _purpleSwitch),
                  const SizedBox(height: 12),
                  _buildCustomSwitch('橙色主题', Colors.orange, _orangeSwitch),
                ]),
              ),

              const SizedBox(height: 24),

              // 不同尺寸
              _buildSection(
                title: '不同尺寸',
                icon: Icons.straighten,
                color: Colors.pink,
                child: _buildCard([
                  Row(
                    mainAxisAlignment: MainAxisAlignment.spaceEvenly,
                    children: [
                      Column(
                        children: [
                          Transform.scale(
                            scale: 0.8,
                            child: Switch(
                              value: _smallSwitch,
                              onChanged: (value) {
                                setState(() {
                                  _smallSwitch = value;
                                });
                              },
                            ),
                          ),
                          const SizedBox(height: 8),
                          const Text(
                            '小',
                            style: TextStyle(
                              fontSize: 12,
                              color: Color(0xFF64748B),
                            ),
                          ),
                        ],
                      ),
                      Column(
                        children: [
                          Switch(
                            value: _normalSwitch,
                            onChanged: (value) {
                              setState(() {
                                _normalSwitch = value;
                              });
                            },
                          ),
                          const SizedBox(height: 8),
                          const Text(
                            '中',
                            style: TextStyle(
                              fontSize: 12,
                              color: Color(0xFF64748B),
                            ),
                          ),
                        ],
                      ),
                      Column(
                        children: [
                          Transform.scale(
                            scale: 1.2,
                            child: Switch(
                              value: _largeSwitch,
                              onChanged: (value) {
                                setState(() {
                                  _largeSwitch = value;
                                });
                              },
                            ),
                          ),
                          const SizedBox(height: 8),
                          const Text(
                            '大',
                            style: TextStyle(
                              fontSize: 12,
                              color: Color(0xFF64748B),
                            ),
                          ),
                        ],
                      ),
                    ],
                  ),
                ]),
              ),

              const SizedBox(height: 24),

              // 通知设置
              _buildSection(
                title: '通知设置',
                icon: Icons.notifications,
                color: Colors.cyan,
                child: _buildCard([
                  _buildSwitchTile(
                    title: '推送通知',
                    subtitle: '接收应用推送消息',
                    icon: Icons.notifications,
                    value: _notificationsEnabled,
                    onChanged: (value) {
                      setState(() {
                        _notificationsEnabled = value;
                      });
                    },
                  ),
                  const SizedBox(height: 16),
                  _buildSwitchTile(
                    title: '深色模式',
                    subtitle: '使用深色主题',
                    icon: Icons.dark_mode,
                    value: _darkModeEnabled,
                    onChanged: (value) {
                      setState(() {
                        _darkModeEnabled = value;
                      });
                    },
                  ),
                ]),
              ),

              const SizedBox(height: 24),

              // 隐私设置
              _buildSection(
                title: '隐私设置',
                icon: Icons.privacy_tip,
                color: Colors.amber,
                child: _buildCard([
                  _buildSwitchTile(
                    title: '位置信息',
                    subtitle: '允许应用访问位置',
                    icon: Icons.location_on,
                    value: _locationEnabled,
                    onChanged: (value) {
                      setState(() {
                        _locationEnabled = value;
                      });
                    },
                  ),
                  const SizedBox(height: 16),
                  _buildSwitchTile(
                    title: '数据分析',
                    subtitle: '帮助改进应用体验',
                    icon: Icons.analytics,
                    value: _analyticsEnabled,
                    onChanged: (value) {
                      setState(() {
                        _analyticsEnabled = value;
                      });
                    },
                  ),
                ]),
              ),

              const SizedBox(height: 80),
              ],
            ),
          ),
        ),
      ),
    );
  }

  Widget _buildSection({
    required String title,
    required IconData icon,
    required Color color,
    required Widget child,
  }) {
    return Column(
      crossAxisAlignment: CrossAxisAlignment.start,
      children: [
        Row(
          children: [
            Container(
              padding: const EdgeInsets.all(12),
              decoration: BoxDecoration(
                gradient: LinearGradient(
                  begin: Alignment.topLeft,
                  end: Alignment.bottomRight,
                  colors: [
                    color,
                    color.withOpacity(0.7),
                  ],
                ),
                borderRadius: BorderRadius.circular(14),
                boxShadow: [
                  BoxShadow(
                    color: color.withOpacity(0.3),
                    blurRadius: 8,
                    offset: const Offset(0, 2),
                  ),
                ],
              ),
              child: Icon(icon, color: Colors.white, size: 22),
            ),
            const SizedBox(width: 12),
            Text(
              title,
              style: const TextStyle(
                fontSize: 20,
                fontWeight: FontWeight.w700,
                color: Color(0xFF1E293B),
              ),
            ),
          ],
        ),
        const SizedBox(height: 16),
        child,
      ],
    );
  }

  Widget _buildCard(List<Widget> children) {
    return Container(
      width: double.infinity,
      padding: const EdgeInsets.all(24),
      decoration: BoxDecoration(
        color: Colors.white,
        borderRadius: BorderRadius.circular(20),
        boxShadow: [
          BoxShadow(
            color: Colors.black.withOpacity(0.05),
            blurRadius: 20,
            offset: const Offset(0, 4),
          ),
        ],
      ),
      child: Column(
        children: children,
      ),
    );
  }

  Widget _buildCustomSwitch(String label, Color color, bool currentValue) {
    return Row(
      mainAxisAlignment: MainAxisAlignment.spaceBetween,
      children: [
        Row(
          children: [
            Container(
              width: 12,
              height: 12,
              decoration: BoxDecoration(
                color: color,
                borderRadius: BorderRadius.circular(3),
              ),
            ),
            const SizedBox(width: 12),
            Text(
              label,
              style: const TextStyle(
                fontSize: 16,
                fontWeight: FontWeight.w500,
                color: Color(0xFF1E293B),
              ),
            ),
          ],
        ),
        Switch(
          value: currentValue,
          activeColor: color,
          activeTrackColor: color.withOpacity(0.5),
          inactiveThumbColor: Colors.grey,
          inactiveTrackColor: Colors.grey.withOpacity(0.3),
          onChanged: (newValue) {
            setState(() {
              if (label == '绿色主题') {
                _greenSwitch = newValue;
              } else if (label == '紫色主题') {
                _purpleSwitch = newValue;
              } else if (label == '橙色主题') {
                _orangeSwitch = newValue;
              }
            });
          },
        ),
      ],
    );
  }

  Widget _buildSwitchTile({
    required String title,
    required String subtitle,
    required IconData icon,
    required bool value,
    required ValueChanged<bool> onChanged,
  }) {
    Color iconColor = Colors.cyan;
    if (title == '推送通知') iconColor = Colors.blue;
    if (title == '深色模式') iconColor = Colors.purple;
    if (title == '位置信息') iconColor = Colors.red;
    if (title == '数据分析') iconColor = Colors.amber;

    return InkWell(
      onTap: () => onChanged(!value),
      borderRadius: BorderRadius.circular(12),
      child: Padding(
        padding: const EdgeInsets.symmetric(vertical: 6),
        child: Row(
          children: [
            Container(
              padding: const EdgeInsets.all(12),
              decoration: BoxDecoration(
                gradient: LinearGradient(
                  begin: Alignment.topLeft,
                  end: Alignment.bottomRight,
                  colors: [
                    iconColor,
                    iconColor.withOpacity(0.7),
                  ],
                ),
                borderRadius: BorderRadius.circular(12),
                boxShadow: [
                  BoxShadow(
                    color: iconColor.withOpacity(0.2),
                    blurRadius: 8,
                    offset: const Offset(0, 2),
                  ),
                ],
              ),
              child: Icon(icon, color: Colors.white, size: 22),
            ),
            const SizedBox(width: 16),
            Expanded(
              child: Column(
                crossAxisAlignment: CrossAxisAlignment.start,
                children: [
                  Text(
                    title,
                    style: const TextStyle(
                      fontSize: 16,
                      fontWeight: FontWeight.w600,
                      color: Color(0xFF1E293B),
                    ),
                  ),
                  const SizedBox(height: 4),
                  Text(
                    subtitle,
                    style: const TextStyle(
                      fontSize: 13,
                      color: Color(0xFF64748B),
                    ),
                  ),
                ],
              ),
            ),
            Switch(
              value: value,
              onChanged: onChanged,
            ),
          ],
        ),
      ),
    );
  }
}

十、总结

恭喜你!通过这篇文章的学习,你已经掌握了 Flutter 中 Switch 开关组件的全面知识。让我们回顾一下本章的核心内容。

🎯 核心要点

  1. 基础用法value 控制状态,onChanged 响应变化,这是 Switch 的最基本用法
  2. 样式定制:通过 activeColorinactiveThumbColor 等属性自定义开关外观
  3. 禁用状态:将 onChanged 设为 null 即可禁用开关
  4. 配合 ListTile:创建标准的设置选项布局,提升用户体验
  5. 最佳实践:为开关添加清晰的标题和说明,使用图标增强识别度

📚 使用建议

场景 推荐方案
设置页面 配合 ListTile 使用,添加标题和说明
功能开关 使用明确的图标和文字描述
颜色定制 保持与应用主题色一致
禁用状态 视觉上明确区分,避免用户困惑
状态管理 每个开关使用独立的状态变量,避免互相影响
Logo

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

更多推荐