dart 设置屏幕切换抖动动画

vc9ivgsu  于 2023-06-27  发布在  其他
关注(0)|答案(1)|浏览(104)

现在,我正在尝试创建一个基本的锻炼应用程序。我正在研究游戏锻炼功能,有一件事我想改变,我不知道如何做。当用户点击下一个箭头时,我想让下一个锻炼幻灯片进来,而不是仅仅被替换,因为它看起来更酷。我试着这样做,但我编程练习的方式使它有点难做。我真的需要你的帮助。谢谢!
下面是练习数组:

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();
    }
  }
}
cuxqih21

cuxqih211#

您可以尝试AnimatedSwitcher小部件:

这将在每次替换其子项时隐式动画。因为您可能会使用与它的子部件相同类型的小部件,除了您的“Finish!“小部件,您需要确保为子部件设置key
AnimatedSwitcher小部件是Flutter的youtube频道上的本周小部件,所以在文档页面上有一个关于如何使用它的很棒的小介绍视频。

相关问题