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,
                      ),
                    ),
                  ),
                ),
              ],
            ),
          ),
        ],
      ),
    );
  }
}
相关推荐
周某人姓周2 分钟前
XSS(一)概述
前端·安全·xss
半梅芒果干6 分钟前
vue3 网站访问页面缓存优化
前端·javascript·缓存
lichong9518 分钟前
android 使用 java 编写网络连通性检查
android·java·前端
孟祥_成都8 分钟前
公司 React 应用感觉很慢,我把没必要的重复渲染砍掉了 40%!
前端
王大宇_12 分钟前
word对比工具从入门到出门
前端·javascript
jackaso13 分钟前
ES6 学习笔记2
前端·学习·es6
得物技术14 分钟前
项目性能优化实践:深入FMP算法原理探索|得物技术
前端·算法
幼儿园的扛把子16 分钟前
一次请求 Request failed with status code 400的解决之旅
前端
g***727022 分钟前
解决 Tomcat 跨域问题 - Tomcat 配置静态文件和 Java Web 服务(Spring MVC Springboot)同时允许跨域
java·前端·spring
盟接之桥26 分钟前
盟接之桥说制造:做新时代的“点火者”——从《星星之火,可以燎原》看制造者的信念与方法(供批评)
大数据·前端·人工智能·安全·制造