Flutter进阶(4):定时器使用(Timer)

一、Timer简介

Flutter 的 Timer 类是 Dart 语言中的一个内置类,用于创建定时器。定时器可以用于在一段时间后执行代码,或者以固定的时间间隔重复执行代码。Timer 类提供了一种简单的方式来管理这些时间相关的任务。

二、Timer类的详细介绍

2.1 导入dart:async包

要使用 Timer 类,首先需要导入dart:async包,因为它包含了定时器相关的类和函数。

import 'dart:async';

2.2 创建一个定时器

使用 Timer 类的构造函数可以创建一个定时器。构造函数有两个参数,分别是持续时间(Duration)和回调函数(void Function())。

Timer(Duration duration, void Function() callback)
  • duration 参数表示定时器的持续时间,即多长时间后触发回调函数。
  • callback 参数是一个函数,它定义了当定时器触发时要执行的代码。

例如,以下代码创建一个在2秒后执行的定时器:

Timer(Duration(seconds: 2), () {
  print("定时器已触发");
});

2.3 取消定时器

你可以随时取消定时器,以防止回调函数执行。Timer 对象有一个cancel()方法,可以用来取消定时器。

Timer myTimer = Timer(Duration(seconds: 2), () {
  print("定时器已触发");
});

// 取消定时器
myTimer.cancel();

2.4 定时器的周期性执行

如果你想要定时器在固定的时间间隔内重复执行,可以使用periodic构造函数。它与 Timer 构造函数类似,但是会重复触发回调函数。

Timer.periodic(Duration(seconds: 2), (Timer timer) {
  print("定时器已触发");
});

在上面的例子中,回调函数每 2 秒执行一次。


2.5 注意事项

  • 定时器的回调函数会在一个隔离的事件循环中执行,不会阻塞主事件循环。
  • 定时器的精确性依赖于系统的可用性和负载,因此可能会有一些偏差。
  • 如果需要在主 UI 线程中执行操作,例如更新 UI,你需要确保使用setState()runOnUiThread()等机制。

三、计时器示例

下面使用 flutter 实现一个好看的计时器。先看下效果图:

Flutter_get_E.gif


main.dart 文件,代码如下:

import 'package:flutter/material.dart';
import 'dart:async';

void main() => runApp(const MyApp());

class MyApp extends StatelessWidget {
  const MyApp({super.key});  
  @override
  Widget build(BuildContext context) => const MaterialApp(
      title: "My Stopwatch",
      home: StopwatchApp());
}

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

class _StopwatchAppState extends State<StopwatchApp> {
  String timeString = "00:00:00";
  Stopwatch stopwatch = Stopwatch();
  late Timer timer; // 定义定时器

  // 开始计时
  void start() {
    stopwatch.start();
    timer = Timer.periodic(const Duration(milliseconds: 100), update);
  }

  // 更新计时
  void update(Timer t) {
    if (stopwatch.isRunning) {
      setState(() {
        // 拼接时间字符串
        timeString =
            (stopwatch.elapsed.inMinutes % 60).toString().padLeft(2, "0") +
                ":" +
                (stopwatch.elapsed.inSeconds % 60).toString().padLeft(2,
                    "0") +
                ":" +
                (stopwatch.elapsed.inMilliseconds % 1000 / 10).clamp(0, 99)
                    .toStringAsFixed(0)
                    .padLeft(2, "0");
      });
    }
  }
  
  // 停止计时
  void stop() {
    setState(() {
      timer.cancel();
      stopwatch.stop();
    });
  }

  // 重置计时
  void reset() {
    timer.cancel();
    stopwatch.reset();
    setState(() {
      timeString = "00:00:00";
    });
    stopwatch.stop();
  }
  
  @override
  Widget build(BuildContext context) {
    return Scaffold (
        appBar: AppBar(
          title: const Text("My Stopwatch"),
        ),
        backgroundColor: Colors.blue,
        body: Column(
          children: <Widget> [
            Padding(padding: const EdgeInsets.symmetric(horizontal: 80,
                vertical: 60),
              child: Text("STOPWATCH",
                  style: TextStyle(
                    fontSize: 20,
                    fontWeight: FontWeight.bold,
                    color: Colors.grey.shade900,
                  )
              ),
            ),
            Expanded(
              child: Container(
                width: 250,
                height: 250,
                decoration: BoxDecoration(
                    color: Colors.pink,
                    shape: BoxShape.circle,
                    boxShadow: [
                      const BoxShadow(
                          offset: Offset(10,10),
                          color: Colors.red,
                          blurRadius: 5),
                      BoxShadow(
                          offset: const Offset(-10,-10),
                          color: Colors.white.withOpacity(0.85),
                          blurRadius: 5)
                    ]),
                child: Column(
                  mainAxisAlignment: MainAxisAlignment.center,
                  children: <Widget>[
                    Text('$timeString',
                        style: TextStyle(
                          fontSize: 40,
                          color: Colors.grey.shade900,
                        )
                    )
                  ],
                ),
              ),
            ),
            Padding(
              padding: const EdgeInsets.symmetric(horizontal: 10, vertical:
              60),
              child: Row(
                mainAxisAlignment: MainAxisAlignment.spaceEvenly,
                children: <Widget>[
                  TextButton(
                      onPressed: reset,
                      child: Container(
                        height: 100,
                        width: 100,
                        decoration: const BoxDecoration(
                          color: Colors.white,
                          shape: BoxShape.circle,
                        ),
                        child: const Icon(Icons.refresh, size: 60),
                      )
                  ),
                  TextButton(
                    onPressed: () => {
                      stopwatch.isRunning ? stop() : start()
                    },
                    child: Container(
                      height: 100,
                      width: 100,
                      decoration: const BoxDecoration(
                        color: Colors.white,
                        shape: BoxShape.circle,
                      ),
                      child: Icon(stopwatch.isRunning ? Icons.pause :
                      Icons.play_arrow, size: 60),
                    ),
                  )
                ],
              ),
            )
          ],
        )
    );
  }
}

四、倒计时示例

如下图所示为常见 App 的一个启动页面的倒计时显示效果:

Flutter_get_F.gif


全部代码如下:

import 'package:flutter/material.dart';
import 'dart:async';

void main() => runApp(const MyApp());

class MyApp extends StatelessWidget {
  const MyApp({super.key});
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        appBar: AppBar(
          title: const Text("Timer"),
        ),
        body: const TimerDemo(),
      ),
    );
  }
}

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

class _TimerDemoState extends State<TimerDemo> {
  // 声明变量
  late Timer _timer;
  // 记录当前的时间
  int curentTimer = 0;

  @override
  void initState() {
    super.initState();

    // 循环执行
    // 间隔100ms
    _timer = Timer.periodic(const Duration(milliseconds: 100), (timer) {
      // 自增
      curentTimer += 100;
      // 到5秒后重新计时
      if (curentTimer > 5000) {
        curentTimer = 0;
        //_timer.cancel();
      }
      setState(() {});
    });
  }

  @override
  void dispose() {
    // 取消计时器
    _timer.cancel();
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text("倒计时"),
      ),
      backgroundColor: Colors.white,

      // 填充布局
      body: Container(
          padding: const EdgeInsets.all(20),
          width: double.infinity,
          height: double.infinity,
          child: Column(
            children: [
              // 层叠布局将进度与文字叠在一起
              Stack(
                // 子Widget居中
                alignment: Alignment.center,
                children: [
                  // 圆形进度
                  CircularProgressIndicator(
                    // 当前指示的进度 0.0 -1.0
                    value: curentTimer / 5000,
                  ),
                  // 显示的文本
                  Text("${(curentTimer / 1000).toInt()}"),
                ],
              )
            ],
          )),
    );
  }
}

posted @ 2024-11-15 15:58  fengMisaka  阅读(58)  评论(0编辑  收藏  举报