Flutter---音效模式选择器

效果图

主要功能:

音效模式切换:用户可以在三种音效模式之间循环切换

  • 🎵 音乐模式 - 背景:音乐背景图,图标:苹果

  • 🎬 电影模式 - 背景:电影背景图,图标:香蕉

  • 🎮 游戏模式 - 背景:游戏背景图,图标:樱桃

交互功能:

左右切换:

  • 点击左侧图标(芒果)切换到上一个模式

  • 点击右侧图标(芒果)切换到下一个模式

  • 支持循环切换(音乐 ↔ 电影 ↔ 游戏)

页面布局:

  • 顶部:返回按钮(樱桃图标) + 模式标题

  • 中部:模式描述文字

  • 底部:模式选择控件 + 确认按钮(三色渐变)

步骤

①新建枚举

Dart 复制代码
enum SoundMode{music,movie,game}

②新建私有变量,设置为当前选中模式,默认为音乐模式

Dart 复制代码
//当前选中的模式
  SoundMode _currentMode = SoundMode.music;//进入的第一个页面

③通过switch/case获取当前的背景图、中间的图标、当前模式的标题、模式的描述、

Dart 复制代码
  //获取当前模式的背景图
  String get _backgroundImage{
    switch(_currentMode){
      case SoundMode.music:
        return "assets/images/music_mode_background.jpg";
      case SoundMode.movie:
        return "assets/images/movie_mode_background.jpg";
      case SoundMode.game:
        return "assets/images/game_mode_background.jpg";
      default:
        return "assets/images/music_mode_background.jpg";
    }
  }

  //获取当前模式的中间图标
  String get _centerIcon{
    switch(_currentMode){
      case SoundMode.music:
        return "assets/images/apple.png";
      case SoundMode.movie:
        return "assets/images/banana.png";
      case SoundMode.game:
        return "assets/images/cherry.png";
    }
  }

  //获取当前模式的标题
  String get _modeTitle{
    switch(_currentMode){
      case SoundMode.music:
        return "音乐模式";
      case SoundMode.movie:
        return "电影模式";
      case SoundMode.game:
        return "游戏模式";
    }
  }

  //获取当前模式的描述
  List<String> get _modeDescription{
    switch(_currentMode){
      case SoundMode.music:
        return ["这是音乐模式","音乐模式很好"];
      case SoundMode.movie:
        return ["这是电影模式","电影模式很好"];
      case SoundMode.game:
        return ["这是游戏模式","游戏模式很好"];
    }
  }

④写左右按钮切换模式的点击事件

Dart 复制代码
  //切换到上一个模式
  void _previousMode(){
    setState(() {
      final index = SoundMode.values.indexOf(_currentMode); //获取当前模式下标
      _currentMode = SoundMode.values[(index - 1) % SoundMode.values.length];
    });
  }

  //切换到下一个模式
  void _nextMode(){
    setState(() {
      final index = SoundMode.values.indexOf(_currentMode);//获取当前模式下标
      _currentMode = SoundMode.values[(index + 1) % SoundMode.values.length];
      //假设当前index = 0,则(0+1)%3 = 1,则SoundMode.values[1] = movie,然后重新构建UI
    });
  }

点击事件的实现

Dart 复制代码
//下一个模式
_nextMode() 执行过程:
1. index = SoundMode.values.indexOf(_currentMode) 
   → index = 0 (因为_currentMode是music)

2. (index + 1) % SoundMode.values.length
   → (0 + 1) % 3 = 1 % 3 = 1

3. SoundMode.values[1] 
   → SoundMode.movie

4. _currentMode = SoundMode.movie



//上一个模式

_previousMode() 执行过程(假设当前是movie):
1. index = SoundMode.values.indexOf(_currentMode) 
   → index = 1 (因为_currentMode是movie)

2. (index - 1) % SoundMode.values.length
   → (1 - 1) % 3 = 0 % 3 = 0

3. SoundMode.values[0] 
   → SoundMode.music

4. _currentMode = SoundMode.music

完整的触发流程

Dart 复制代码
用户点击 → 调用 _nextMode()/_previousMode() → setState() → 重建UI
     ↓
_currentMode 改变 → 所有getter重新计算
     ↓
_backgroundImage → 返回新背景图路径
_centerIcon → 返回新图标路径  
_modeTitle → 返回新标题
_modeDescription → 返回新描述
     ↓
UI使用新值重新渲染 → 用户看到界面更新

⑤建造UI,使用Stack,叠加布局

Dart 复制代码
body: Stack(
        children: [
          Container(
            height: double.infinity,
            width: double.infinity,
            decoration: BoxDecoration(
              image: DecorationImage(
                image: AssetImage(_backgroundImage), //动态背景图片
                fit:BoxFit.cover,
              ),
            ),
            child: Column(
              mainAxisAlignment: MainAxisAlignment.start,
              crossAxisAlignment: CrossAxisAlignment.center,
              children: [
                Padding(padding: EdgeInsets.only(top:50,left:27),
                child: Row(
                  mainAxisAlignment: MainAxisAlignment.start,
                  children: [
                    Image.asset("assets/images/cherry.png",width: 20,height: 20,),
                    const SizedBox(width: 102,),
                    Text(
                      _modeTitle,
                      style: const TextStyle(
                          color: Colors.white,
                          fontSize: 22,
                          fontWeight: FontWeight.bold
                      ),
                    ),
                  ],
                ),
                ),
                const SizedBox(height: 350,),

                //动态描述
                for (var description in _modeDescription)
                  Text(
                    description,
                    style: const TextStyle(
                      color: Colors.black,
                      fontSize: 14,
                    ),
                  ),
                const SizedBox(height: 67,),

                Row(
                  mainAxisAlignment: MainAxisAlignment.center,
                  children: [
                    GestureDetector(
                      onTap: _previousMode,
                      child: Image.asset("assets/images/mango.png",width: 20,height: 20,),
                    ),

                    const SizedBox(width: 21,),
                    Container(
                      width: 1,
                      height: 48,
                      decoration: const BoxDecoration(
                        color: Color(0xFFD8D8D8),
                      ),
                    ),
                    const SizedBox(width: 45,),
                    Image.asset(_centerIcon,width: 35,height: 35,),

                    const SizedBox(width: 45,),

                    Container(
                      width: 1,
                      height: 48,
                      decoration: const BoxDecoration(
                        color: Color(0xFFD8D8D8),
                      ),
                    ),
                    const SizedBox(width: 21,),
                    GestureDetector(
                      onTap: _nextMode,
                      child: Image.asset("assets/images/mango.png",width: 20,height: 20,),
                    ),

                  ],
                ),

                //确认按钮
                const SizedBox(height: 50,),
                Container(
                  width: 249,
                  height: 48,
                  decoration: BoxDecoration(
                    borderRadius: BorderRadius.circular(27),
                    gradient: const LinearGradient(
                      begin: Alignment.centerLeft,    // 从上开始
                      end: Alignment.centerRight,   // 到底结束
                      colors: [
                        Colors.blue,      // 顶部颜色
                        Colors.blueGrey,     // 中间颜色
                        Colors.green,    // 底部颜色
                      ],
                    ),
                  ),
                  child: Center(
                    child: Text(
                      "确认",
                      style: const TextStyle(
                        color: Colors.white,
                        fontWeight: FontWeight.bold,
                        fontSize: 24,
                      ),
                    ),
                  ),
                ),
              ],
            ),
          ),
        ],
      ),

⑥UI中有一个三种颜色的渲染按钮(从左到右),改变两个参数就能变成从上到下的渲染

Dart 复制代码
//确认按钮
                const SizedBox(height: 50,),
                Container(
                  width: 249,
                  height: 48,
                  decoration: BoxDecoration(
                    borderRadius: BorderRadius.circular(27),
                    gradient: const LinearGradient(
                      begin: Alignment.centerLeft,    // 左到右
                      end: Alignment.centerRight,   //从上到下渲染,可以换成topCenter到bottomCenter
                      colors: [
                        Colors.blue,      // 顶部颜色
                        Colors.blueGrey,     // 中间颜色
                        Colors.green,    // 底部颜色
                      ],
                    ),
                  ),
                  child: Center(
                    child: Text(
                      "确认",
                      style: const TextStyle(
                        color: Colors.white,
                        fontWeight: FontWeight.bold,
                        fontSize: 24,
                      ),
                    ),
                  ),
                ),

代码实例

Dart 复制代码
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';

enum SoundMode{music,movie,game}

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

  @override
  State<StatefulWidget> createState() => _HomePageState();

}

class _HomePageState extends State<HomePage> {

  //当前选中的模式
  SoundMode _currentMode = SoundMode.music;//进入的第一个页面

  //获取当前模式的背景图
  String get _backgroundImage{
    switch(_currentMode){
      case SoundMode.music:
        return "assets/images/music_mode_background.jpg";
      case SoundMode.movie:
        return "assets/images/movie_mode_background.jpg";
      case SoundMode.game:
        return "assets/images/game_mode_background.jpg";
      default:
        return "assets/images/music_mode_background.jpg";
    }
  }

  //获取当前模式的中间图标
  String get _centerIcon{
    switch(_currentMode){
      case SoundMode.music:
        return "assets/images/apple.png";
      case SoundMode.movie:
        return "assets/images/banana.png";
      case SoundMode.game:
        return "assets/images/cherry.png";
    }
  }

  //获取当前模式的标题
  String get _modeTitle{
    switch(_currentMode){
      case SoundMode.music:
        return "音乐模式";
      case SoundMode.movie:
        return "电影模式";
      case SoundMode.game:
        return "游戏模式";
    }
  }

  //获取当前模式的描述
  List<String> get _modeDescription{
    switch(_currentMode){
      case SoundMode.music:
        return ["这是音乐模式","音乐模式很好"];
      case SoundMode.movie:
        return ["这是电影模式","电影模式很好"];
      case SoundMode.game:
        return ["这是游戏模式","游戏模式很好"];
    }
  }

  //切换到上一个模式
  void _previousMode(){
    setState(() {
      final index = SoundMode.values.indexOf(_currentMode); //获取当前模式下标
      _currentMode = SoundMode.values[(index - 1) % SoundMode.values.length];
    });
  }

  //切换到下一个模式
  void _nextMode(){
    setState(() {
      final index = SoundMode.values.indexOf(_currentMode);//获取当前模式下标
      _currentMode = SoundMode.values[(index + 1) % SoundMode.values.length];
      //假设当前index = 0,则(0+1)%3 = 1,则SoundMode.values[1] = movie,然后重新构建UI
    });
  }

  //UI构建
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: Stack(
        children: [
          Container(
            height: double.infinity,
            width: double.infinity,
            decoration: BoxDecoration(
              image: DecorationImage(
                image: AssetImage(_backgroundImage), //动态背景图片
                fit:BoxFit.cover,
              ),
            ),
            child: Column(
              mainAxisAlignment: MainAxisAlignment.start,
              crossAxisAlignment: CrossAxisAlignment.center,
              children: [
                Padding(padding: EdgeInsets.only(top:50,left:27),
                child: Row(
                  mainAxisAlignment: MainAxisAlignment.start,
                  children: [
                    Image.asset("assets/images/cherry.png",width: 20,height: 20,),
                    const SizedBox(width: 102,),
                    Text(
                      _modeTitle,
                      style: const TextStyle(
                          color: Colors.white,
                          fontSize: 22,
                          fontWeight: FontWeight.bold
                      ),
                    ),
                  ],
                ),
                ),
                const SizedBox(height: 350,),

                //动态描述
                for (var description in _modeDescription)
                  Text(
                    description,
                    style: const TextStyle(
                      color: Colors.black,
                      fontSize: 14,
                    ),
                  ),
                const SizedBox(height: 67,),

                Row(
                  mainAxisAlignment: MainAxisAlignment.center,
                  children: [
                    GestureDetector(
                      onTap: _previousMode,
                      child: Image.asset("assets/images/mango.png",width: 20,height: 20,),
                    ),

                    const SizedBox(width: 21,),
                    Container(
                      width: 1,
                      height: 48,
                      decoration: const BoxDecoration(
                        color: Color(0xFFD8D8D8),
                      ),
                    ),
                    const SizedBox(width: 45,),
                    Image.asset(_centerIcon,width: 35,height: 35,),

                    const SizedBox(width: 45,),

                    Container(
                      width: 1,
                      height: 48,
                      decoration: const BoxDecoration(
                        color: Color(0xFFD8D8D8),
                      ),
                    ),
                    const SizedBox(width: 21,),
                    GestureDetector(
                      onTap: _nextMode,
                      child: Image.asset("assets/images/mango.png",width: 20,height: 20,),
                    ),

                  ],
                ),

                //确认按钮
                const SizedBox(height: 50,),
                Container(
                  width: 249,
                  height: 48,
                  decoration: BoxDecoration(
                    borderRadius: BorderRadius.circular(27),
                    gradient: const LinearGradient(
                      begin: Alignment.centerLeft,    // 左到右
                      end: Alignment.centerRight,   //从上到下渲染,可以换成topCenter到bottomCenter
                      colors: [
                        Colors.blue,      // 顶部颜色
                        Colors.blueGrey,     // 中间颜色
                        Colors.green,    // 底部颜色
                      ],
                    ),
                  ),
                  child: Center(
                    child: Text(
                      "确认",
                      style: const TextStyle(
                        color: Colors.white,
                        fontWeight: FontWeight.bold,
                        fontSize: 24,
                      ),
                    ),
                  ),
                ),
              ],
            ),
          ),
        ],
      ),
    );
  }
}
相关推荐
TLucas3 小时前
Layui连线题编辑器组件(ConnectQuestion)
前端·编辑器·layui
艾小码4 小时前
告别页面呆板!这5个DOM操作技巧让你的网站活起来
前端·javascript
正在学习前端的---小方同学5 小时前
vue-easy-tree树状结构
前端·javascript·vue.js
键盘不能没有CV键9 小时前
【图片处理】✈️HTML转图片字体异常处理
前端·javascript·html
yantuguiguziPGJ9 小时前
WPF 联合 Web 开发调试流程梳理(基于 Microsoft.Web.WebView2)
前端·microsoft·wpf
大飞记Python10 小时前
部门管理|“编辑部门”功能实现(Django5零基础Web平台)
前端·数据库·python·django
tsumikistep11 小时前
【前端】前端运行环境的结构
前端
你的人类朋友11 小时前
【Node】认识multer库
前端·javascript·后端
Aitter11 小时前
PDF和Word文件转换为Markdown的技术实现
前端·ai编程