菜鸡Flutter学习第一步:摸鱼App

136 阅读1分钟

感谢这个老哥AlexV525的摸鱼教程:

juejin.cn/post/704234…

一、参照老哥AlexV525的代码一步步敲

略...

二、加个定时器,形成摸鱼周期闭环

在 _callAnimation 的 if (nextDuration == null) 判断中加个循环

...

if (nextDuration == null) {
  _currentPeriod.value = 0;
  // 定时循环
  Future.delayed(_waitingDuration * 2).then((_) {
    _currentPeriod.value+=1;
    _controller.value = 0;
    _callAnimation();
  });
  return;
}

... 

三、完整的代码

1、main.dart

import 'dart:core';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';

void main() {
  runApp(const MyApp());
}

class MyApp extends StatelessWidget {
  const MyApp({super.key});

  // This widget is the root of your application.
  @override
  Widget build(BuildContext context) {
    return const MaterialApp(
      home: MyHomePage(),
    );
  }
}

class MyHomePage extends StatefulWidget {
  const MyHomePage({super.key});
  @override
  State<MyHomePage> createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> with SingleTickerProviderStateMixin {

  late final AnimationController _controller = AnimationController(vsync: this);
  Duration get _waitingDuration => const Duration(seconds: 5);
  List<Duration> get _periodDurations {
    return <Duration>[
      const Duration(seconds: 5),
      const Duration(seconds: 10),
      const Duration(seconds: 4),
    ];
  }
  final ValueNotifier<int> _currentPeriod = ValueNotifier<int>(1);

  @override
  void initState() {
    super.initState();
    // 等待对应秒数后,开始进度条动画
    Future.delayed(_waitingDuration).then((_) => _callAnimation());
  }

  Future<void> _callAnimation() async {
    // 取当前分段
    final Duration currentDuration = _periodDurations[_currentPeriod.value];
    // 准备下一分段
    _currentPeriod.value++;
    // 如果到了最后一个分段,取空
    final Duration? nextDuration = _currentPeriod.value < _periodDurations.length ? _periodDurations.last : null;
    // 计算当前分段动画的结束值
    final double target = _currentPeriod.value / _periodDurations.length;
    // 执行动画
    await _controller.animateTo(target, duration: currentDuration);
    // 如果下一分段为空,即执行到了最后一个分段,重设当前分段,动画结束
    if (nextDuration == null) {
      _currentPeriod.value = 0;
      // 定时循环
      Future.delayed(_waitingDuration * 2).then((_) {
        _currentPeriod.value+=1;
        _controller.value = 0;
        _callAnimation();
      });
      return;
    }
    // 否则调用下一分段的动画
    await _callAnimation();
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      backgroundColor: CupertinoColors.black,
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: [
            const Spacer(),
            Padding(
              padding: const EdgeInsets.only(top: 200, bottom: 100),
              child: Image.asset('assets/macos.png', color: CupertinoColors.white, width: 100,),
            ),
            Expanded(child: Container(
              width: 200,
              alignment: Alignment.topCenter,
              child:ValueListenableBuilder<int>(
                valueListenable: _currentPeriod,
                builder: (_, int period, __) {
                  // 分段为0时,不展示
                  if (period == 0) {
                    return const SizedBox.shrink();
                  }
                  return DecoratedBox(
                    decoration: BoxDecoration(
                      border: Border.all(color: CupertinoColors.systemGrey),
                      borderRadius: BorderRadius.circular(10),
                    ),
                    child: ClipRRect(
                      borderRadius: BorderRadius.circular(10),
                      child: AnimatedBuilder( // 使用 AnimatedBuilder,在动画进行时触发更新
                        animation: _controller,
                        builder: (_, __) => LinearProgressIndicator(
                          value: _controller.value, // 将 controller 的值绑定给进度
                          backgroundColor: CupertinoColors.lightBackgroundGray.withOpacity(.2),
                          color: CupertinoColors.white,
                          minHeight: 5,
                        ),
                      ),
                    ),
                  );
                },
              )),
            ),
            const Spacer()
          ],
        )
      )
    );
  }
}

四、再次感谢老哥AlexV525,摸鱼路上有你们不孤单。