效果图

主要功能:
音效模式切换:用户可以在三种音效模式之间循环切换
-
🎵 音乐模式 - 背景:音乐背景图,图标:苹果
-
🎬 电影模式 - 背景:电影背景图,图标:香蕉
-
🎮 游戏模式 - 背景:游戏背景图,图标:樱桃
交互功能:
左右切换:
-
点击左侧图标(芒果)切换到上一个模式
-
点击右侧图标(芒果)切换到下一个模式
-
支持循环切换(音乐 ↔ 电影 ↔ 游戏)
页面布局:
-
顶部:返回按钮(樱桃图标) + 模式标题
-
中部:模式描述文字
-
底部:模式选择控件 + 确认按钮(三色渐变)
步骤
①新建枚举
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,
),
),
),
),
],
),
),
],
),
);
}
}