现在,我正在尝试创建一个基本的锻炼应用程序。我正在研究游戏锻炼功能,有一件事我想改变,我不知道如何做。当用户点击下一个箭头时,我想让下一个锻炼幻灯片进来,而不是仅仅被替换,因为它看起来更酷。我试着这样做,但我编程练习的方式使它有点难做。我真的需要你的帮助。谢谢!
下面是练习数组:
List<Map<String, dynamic>> workoutMap = [
{
'plan_name': 'My First Plan',
'content': [
{
'name': 'My First Workout',
'exercises': [
{
'name': 'Bicep Curl',
'musclesworked': ['bicep', 'tricep'],
'sets': '5',
'reps': '10',
'weight': '11',
'video':
'https://thumbs.gfycat.com/MistyMisguidedIzuthrush-size_restricted.gif'
},
{
'name': 'Preacher Curl',
'musclesworked': ['bicep', 'tricep'],
'sets': '3',
'reps': '10',
'weight': '11',
'video':
'https://thumbs.gfycat.com/MistyMisguidedIzuthrush-size_restricted.gif'
},
{
'name': 'Bicep Curl',
'musclesworked': ['bicep', 'tricep'],
'sets': '7',
'reps': '12',
'weight': '11',
'video':
'https://thumbs.gfycat.com/MistyMisguidedIzuthrush-size_restricted.gif'
},
{
'name': 'Preacher Curl',
'musclesworked': ['bicep', 'tricep'],
'sets': '5',
'reps': '10',
'weight': '15',
'video':
'https://thumbs.gfycat.com/MistyMisguidedIzuthrush-size_restricted.gif'
},
{
'name': 'Bicep Curl',
'musclesworked': ['bicep', 'tricep'],
'sets': '5',
'reps': '10',
'weight': 'NA',
'video':
'https://thumbs.gfycat.com/MistyMisguidedIzuthrush-size_restricted.gif'
},
{
'name': 'Preacher Curl',
'musclesworked': ['bicep', 'tricep'],
'sets': '5',
'reps': '10',
'weight': '11',
'video':
'https://thumbs.gfycat.com/MistyMisguidedIzuthrush-size_restricted.gif'
},
{
'name': 'Bicep Curl',
'musclesworked': ['bicep', 'tricep'],
'sets': '5',
'reps': '10',
'weight': '11',
'video':
'https://thumbs.gfycat.com/MistyMisguidedIzuthrush-size_restricted.gif'
},
{
'name': 'Preacher Curl',
'musclesworked': ['bicep', 'tricep'],
'sets': '5',
'reps': '10',
'weight': '11',
'video':
'https://thumbs.gfycat.com/MistyMisguidedIzuthrush-size_restricted.gif'
}
]
}
]
},
{
'plan_name': 'My Second Plan',
'content': [
{
'name': 'My Second Workout',
'exercises': [
{
'name': '#2 Bicep Curl',
'musclesworked': ['bicep', 'tricep'],
'sets': '5',
'reps': '10',
'weight': '11',
'video':
'https://thumbs.gfycat.com/MistyMisguidedIzuthrush-size_restricted.gif'
},
{
'name': 'Preacher Curl',
'musclesworked': ['bicep', 'tricep'],
'sets': '3',
'reps': '10',
'weight': '11',
'video':
'https://thumbs.gfycat.com/MistyMisguidedIzuthrush-size_restricted.gif'
},
{
'name': 'Bicep Curl',
'musclesworked': ['bicep', 'tricep'],
'sets': '7',
'reps': '12',
'weight': '11',
'video':
'https://thumbs.gfycat.com/MistyMisguidedIzuthrush-size_restricted.gif'
},
{
'name': 'Preacher Curl',
'musclesworked': ['bicep', 'tricep'],
'sets': '5',
'reps': '10',
'weight': '15',
'video':
'https://thumbs.gfycat.com/MistyMisguidedIzuthrush-size_restricted.gif'
},
{
'name': 'Bicep Curl',
'musclesworked': ['bicep', 'tricep'],
'sets': '5',
'reps': '10',
'weight': 'NA',
'video':
'https://thumbs.gfycat.com/MistyMisguidedIzuthrush-size_restricted.gif'
},
{
'name': 'Preacher Curl',
'musclesworked': ['bicep', 'tricep'],
'sets': '5',
'reps': '10',
'weight': '11',
'video':
'https://thumbs.gfycat.com/MistyMisguidedIzuthrush-size_restricted.gif'
},
{
'name': 'Bicep Curl',
'musclesworked': ['bicep', 'tricep'],
'sets': '5',
'reps': '10',
'weight': '11',
'video':
'https://thumbs.gfycat.com/MistyMisguidedIzuthrush-size_restricted.gif'
},
{
'name': 'Preacher Curl',
'musclesworked': ['bicep', 'tricep'],
'sets': '5',
'reps': '10',
'weight': '11',
'video':
'https://thumbs.gfycat.com/MistyMisguidedIzuthrush-size_restricted.gif'
}
]
}
]
},
];
这是我的代码
class BlackScreen extends StatefulWidget {
final List<Map<String, dynamic>> exercises;
BlackScreen({Key? key, required this.exercises}) : super(key: key);
@override
_BlackScreenState createState() => _BlackScreenState();
}
class _BlackScreenState extends State<BlackScreen> {
int currentExerciseIndex = 0;
bool isPaused = false;
int elapsedTime = 0; // time elapsed for an exercise
@override
void initState() {
super.initState();
startTimer();
}
void startTimer() async {
while (true) {
await Future.delayed(Duration(seconds: 1));
if (isPaused) continue;
if (mounted) {
setState(() {
elapsedTime++;
});
}
}
}
void pauseTimer() {
setState(() {
isPaused = !isPaused;
});
}
void previousExercise() {
if (currentExerciseIndex > 0) {
setState(() {
currentExerciseIndex--;
elapsedTime = 0;
isPaused = false;
});
}
}
String formatDuration(int seconds) {
final minutes = (seconds / 60).floor().toString().padLeft(2, '0');
final remainingSeconds = (seconds % 60).toString().padLeft(2, '0');
return '$minutes:$remainingSeconds';
}
Widget buildButton(IconData iconData, onPressed, double size) {
return GestureDetector(
onTap: onPressed,
child: Container(
height: 50, // provide the height you want for the buttons
width: 50, // provide the width you want for the buttons
child: iconData == Icons.play_arrow || iconData == Icons.pause
? Container(
height: size, // provide the height you want for the buttons
width: size, // provide the width you want for the buttons
decoration: BoxDecoration(
color: Color(0xff11b779),
shape: BoxShape.circle,
),
child: Icon(
iconData,
color: Colors.black,
size: size - 10,
),
alignment: Alignment.center,
)
: Icon(
iconData,
color: Colors.white,
size: size,
),
alignment: Alignment.center,
),
);
}
var totalTime = 0;
@override
Widget build(BuildContext context) {
var size = MediaQuery.of(context).size;
var topPadding = MediaQuery.of(context).padding.top;
// Do nothing if there's no exercises
if (widget.exercises.length == 0) return Container();
// Show the current exercise name
return Container(
height: size.height,
width: size.width,
color: Colors.black,
child: Stack(alignment: Alignment.center, children: [
Positioned(
top: 0,
child: Image.network(
widget.exercises[currentExerciseIndex]['video'],
height: size.height * .7)),
Positioned(
top: topPadding + 10,
left: 10,
child: Row(children: [
GestureDetector(
onTap: () {
Navigator.of(context).pop();
},
child: Icon(Icons.arrow_drop_down,
size: 20, color: Colors.black)),
DefaultTextStyle(
style: TextStyle(fontSize: 20, color: Colors.black),
child: Text('Just Lift'),
),
])),
Positioned(
top: topPadding + 12,
right: 10,
child: DefaultTextStyle(
style: TextStyle(fontSize: 20, color: Colors.black),
child: Text('Exercise ' +
(currentExerciseIndex + 1).toString() +
'/' +
(widget.exercises.length).toString()),
),
),
Positioned(
top: size.height * .7 + 10,
child: Material(
color: Colors.transparent,
child: Column(children: [
DefaultTextStyle(
style: TextStyle(
fontSize: 25,
color: Colors.white,
fontWeight: FontWeight.bold),
child: Text(widget.exercises[currentExerciseIndex]['name']
.toUpperCase()),
),
SizedBox(height: 5),
Text('${formatDuration(elapsedTime)}',
style: TextStyle(color: Colors.white, fontSize: 25)),
SizedBox(height: 5),
Row(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
buildButton(
Icons.arrow_back,
currentExerciseIndex == 0 ? null : previousExercise,
size.height * .05,
),
buildButton(
isPaused ? Icons.play_arrow : Icons.pause,
pauseTimer,
size.height * .07,
),
buildButton(
Icons.arrow_forward,
currentExerciseIndex == widget.exercises.length - 1
? null
: nextExercise,
size.height * .05,
),
],
),
]))),
currentExerciseIndex == widget.exercises.length - 1
? Positioned(
bottom: 2,
width: size.width * .33,
child: ElevatedButton(
onPressed: () => {nextExercise()},
style: ElevatedButton.styleFrom(
primary: Color.fromARGB(255, 17, 183, 183),
padding: EdgeInsets.all(10),
tapTargetSize: MaterialTapTargetSize.shrinkWrap),
child: Text('Finish!',
style: TextStyle(
color: Colors.black,
fontWeight: FontWeight.bold))))
: Positioned(
bottom: 0,
child: Column(children: [
DefaultTextStyle(
style: TextStyle(
fontSize: 15,
color: Colors.grey,
fontWeight: FontWeight.bold),
child: Transform.translate(
offset: Offset(-3, 0), child: Text(' Up Next')),
),
DefaultTextStyle(
style: TextStyle(
fontSize: 15,
color: Color.fromARGB(255, 209, 209, 209),
fontWeight: FontWeight.bold),
child: Text(
widget.exercises[currentExerciseIndex + 1]['name']),
)
]))
]));
}
void nextExercise() {
// Increase the index, or go back if this is the last exercise
if (currentExerciseIndex < widget.exercises.length - 1) {
totalTime += elapsedTime;
setState(() {
currentExerciseIndex++;
elapsedTime = 0;
isPaused = false;
});
} else {
totalTime += elapsedTime;
print(totalTime);
Navigator.of(context).pop();
}
}
}
1条答案
按热度按时间cuxqih211#
您可以尝试
AnimatedSwitcher
小部件:这将在每次替换其子项时隐式动画。因为您可能会使用与它的子部件相同类型的小部件,除了您的“Finish!“小部件,您需要确保为子部件设置
key
。AnimatedSwitcher
小部件是Flutter的youtube频道上的本周小部件,所以在文档页面上有一个关于如何使用它的很棒的小介绍视频。