Flutter后台高强度间歇训练(HIIT)计时器插件background_hiit_timer的使用

发布于 1周前 作者 eggper 来自 Flutter

Flutter后台高强度间歇训练(HIIT)计时器插件 background_hiit_timer 的使用

概述

background_hiit_timer 是一个用于创建高强度间歇训练(HIIT)计时器的Flutter插件,支持后台服务功能。它最初为 OpenHIIT 创建。

目录

  1. 安装
  2. 基本用法
  3. 高级配置
  4. 贡献
  5. 致谢
  6. 许可证

安装

在你的 pubspec.yaml 文件中添加 background_hiit_timer

dependencies:
  flutter:
    sdk: flutter
  background_hiit_timer: ^1.0.0

基本用法

导入包

在你的 Dart 文件中导入 background_hiit_timer

import 'package:background_hiit_timer/background_hiit_timer.dart';

配置步骤

  1. 确保你的应用正确配置了 Android 和 iOS 平台的后台执行。参考 flutter_background_service 获取详细信息。
  2. 定义一组间隔时间(intervals):
final List<IntervalType> intervals = [
    IntervalType(
        id: "0",
        workoutId: "1",
        time: 10, // in seconds
        name: "Get ready",
        color: 0,
        intervalIndex: 0,
        startSound: "",
        halfwaySound: "",
        countdownSound: "countdown-beep",
        endSound: ""),

    IntervalType(
        id: "4",
        workoutId: "1",
        time: 10, // in seconds
        name: "Cooldown",
        color: 0,
        intervalIndex: 4,
        startSound: "long-rest-beep",
        countdownSound: "countdown-beep",
        endSound: "horn",
        halfwaySound: ""),
  ];
  1. 定义控制器:
final CountdownController _controller = CountdownController(autoStart: true);
  1. 创建 Countdown 小部件并配置其间隔设置:
Countdown(
  controller: _controller,
  intervals: intervals,
  onFinished: () {},
  build: (_, TimerState timerState) {
    return Text(timerState.currentMicroSeconds.toString());
  }
)

示例用法

以下是一个完整的示例代码,展示了如何在 Flutter 应用中使用 background_hiit_timer 插件:

import 'package:audio_session/audio_session.dart';
import 'package:background_hiit_timer/models/interval_type.dart';
import 'package:background_hiit_timer/models/timer_state.dart';
import 'package:flutter/material.dart';
import 'package:shared_preferences/shared_preferences.dart';
import 'package:background_hiit_timer/background_timer.dart';
import 'package:background_hiit_timer/background_timer_controller.dart';

Future<void> main() async {
  runApp(const MyApp());
}

class MyApp extends StatelessWidget {
  const MyApp({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Countdown Demo',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: const MyHomePage(title: 'Flutter Demo Countdown'),
    );
  }
}

class MyHomePage extends StatefulWidget {
  final String title;
  const MyHomePage({Key? key, required this.title}) : super(key: key);

  @override
  MyHomePageState createState() => MyHomePageState();
}

class MyHomePageState extends State<MyHomePage> {
  final CountdownController _controller = CountdownController(autoStart: true);
  List<int> listItems = [];
  List<int> removedItems = [];
  bool _paused = false;
  bool _changeVolume = false;
  double _volume = .8;
  late SharedPreferences prefs;

  final List<IntervalType> intervals = [
    IntervalType(
        id: "0",
        workoutId: "1",
        time: 5,
        name: "Get ready",
        color: 0,
        intervalIndex: 0,
        startSound: "",
        halfwaySound: "",
        countdownSound: "countdown-beep",
        endSound: ""),
    IntervalType(
        id: "1",
        workoutId: "1",
        time: 5,
        name: "Warmup",
        color: 0,
        intervalIndex: 1,
        startSound: "long-bell",
        halfwaySound: "",
        countdownSound: "countdown-beep",
        endSound: ""),
    IntervalType(
        id: "2",
        workoutId: "1",
        time: 5,
        name: "Work",
        color: 0,
        intervalIndex: 2,
        startSound: "long-bell",
        halfwaySound: "short-halfway-beep",
        countdownSound: "countdown-beep",
        endSound: ""),
    IntervalType(
        id: "3",
        workoutId: "1",
        time: 5,
        name: "Rest",
        color: 0,
        intervalIndex: 3,
        startSound: "long-rest-beep",
        halfwaySound: "",
        countdownSound: "countdown-beep",
        endSound: ""),
    IntervalType(
        id: "4",
        workoutId: "1",
        time: 5,
        name: "Cooldown",
        color: 0,
        intervalIndex: 4,
        startSound: "long-rest-beep",
        countdownSound: "countdown-beep",
        endSound: "horn",
        halfwaySound: ""),
  ];

  static const Map<String, Color> intervalColors = {
    "Work": Colors.green,
    "Rest": Colors.red,
    "Get ready": Colors.black,
    "Warmup": Colors.orange,
    "Cooldown": Colors.blue,
    "End": Colors.purple,
  };

  @override
  void initState() {
    super.initState();
    initializeAudioSession();
    loadPreferences();
    listItems = intervals.map((interval) => interval.intervalIndex).toList();
  }

  Future<void> initializeAudioSession() async {
    final session = await AudioSession.instance;
    await session.configure(const AudioSessionConfiguration(
      avAudioSessionCategory: AVAudioSessionCategory.playback,
      avAudioSessionCategoryOptions: AVAudioSessionCategoryOptions.mixWithOthers,
      avAudioSessionMode: AVAudioSessionMode.defaultMode,
      avAudioSessionRouteSharingPolicy: AVAudioSessionRouteSharingPolicy.defaultPolicy,
      avAudioSessionSetActiveOptions: AVAudioSessionSetActiveOptions.none,
      androidAudioAttributes: AndroidAudioAttributes(
        contentType: AndroidAudioContentType.sonification,
        flags: AndroidAudioFlags.audibilityEnforced,
        usage: AndroidAudioUsage.notification,
      ),
      androidAudioFocusGainType: AndroidAudioFocusGainType.gain,
      androidWillPauseWhenDucked: true,
    ));
    await session.setActive(true);
  }

  Future<void> loadPreferences() async {
    prefs = await SharedPreferences.getInstance();
    setState(() {
      _volume = prefs.getDouble('volume') ?? .8;
      _changeVolume = prefs.getBool('changeVolume') ?? false;
    });
  }

  Future<void> toggleVolumeSlider() async {
    setState(() {
      _changeVolume = !_changeVolume;
    });
    await prefs.setBool('changeVolume', _changeVolume);
  }

  Future<void> togglePause() async {
    setState(() {
      _paused = !_paused;
    });
    _paused ? _controller.pause() : _controller.resume();
  }

  Color getBackgroundColor(String status) =>
      intervalColors[status] ?? const Color.fromARGB(255, 0, 225, 255);

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: Countdown(
        controller: _controller,
        intervals: intervals,
        onFinished: () {},
        build: (_, TimerState timerState) {
          while (listItems.length + timerState.currentInterval > intervals.length) {
            removedItems.add(listItems[0]);
            listItems.removeAt(0);
          }

          while (listItems.length + timerState.currentInterval < intervals.length) {
            listItems.insert(0, removedItems[removedItems.length - 1]);
            removedItems.removeAt(removedItems.length - 1);
          }

          return Container(
            color: getBackgroundColor(timerState.status),
            child: Column(
              mainAxisAlignment: MainAxisAlignment.center,
              crossAxisAlignment: CrossAxisAlignment.center,
              children: [
                Text(timerState.status,
                    style: const TextStyle(fontSize: 50, color: Colors.white)),
                Text(
                    (timerState.currentMicroSeconds /
                            const Duration(seconds: 1).inMicroseconds)
                        .round()
                        .toString(),
                    style: const TextStyle(fontSize: 100, color: Colors.white)),
                SizedBox(
                  height: 220,
                  child: ListView.builder(
                    itemCount: listItems.length,
                    itemBuilder: (context, index) {
                      return Container(
                          color: const Color.fromARGB(64, 0, 0, 0),
                          child: ListTile(
                            title: Text(
                              intervals[listItems[index]].name,
                              style: const TextStyle(color: Colors.white),
                            ),
                          ));
                    },
                  ),
                )
              ],
            ),
          );
        },
      ),
    );
  }
}

高级配置

查看 高级配置文档 获取更多信息。

贡献

查看 贡献文档。如果提交代码更改,请查阅 测试文档

行为准则

在贡献时,请牢记 行为准则

致谢

这个包受到了 timer_count_down 包的启发。

感谢 flutter_background_service 让后台计时器成为可能。

许可证

MIT 许可证。详情请参见 LICENSE


更多关于Flutter后台高强度间歇训练(HIIT)计时器插件background_hiit_timer的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html

1 回复

更多关于Flutter后台高强度间歇训练(HIIT)计时器插件background_hiit_timer的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html


当然,以下是如何在Flutter项目中集成和使用background_hiit_timer插件的一个示例代码案例。这个插件假设是用于在后台运行高强度间歇训练(HIIT)计时器的。由于这是一个假设的插件,具体实现细节可能会有所不同,但我会提供一个通用的代码框架来展示如何集成和使用这样的插件。

1. 添加依赖

首先,在你的pubspec.yaml文件中添加background_hiit_timer依赖:

dependencies:
  flutter:
    sdk: flutter
  background_hiit_timer: ^latest_version  # 请替换为实际的最新版本号

然后运行flutter pub get来安装依赖。

2. 配置Android和iOS后台权限

为了确保插件能在后台运行,你可能需要在Android和iOS项目中配置相应的权限。具体步骤取决于插件的要求,但通常包括在AndroidManifest.xml中添加权限声明和在iOS的Info.plist中添加后台模式支持。

3. 初始化插件并设置HIIT计时器

在你的Flutter应用中,你可以按照以下方式初始化插件并设置HIIT计时器:

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

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

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        appBar: AppBar(
          title: Text('HIIT Timer Demo'),
        ),
        body: Center(
          child: HIITTimerButton(),
        ),
      ),
    );
  }
}

class HIITTimerButton extends StatefulWidget {
  @override
  _HIITTimerButtonState createState() => _HIITTimerButtonState();
}

class _HIITTimerButtonState extends State<HIITTimerButton> {
  BackgroundHIITTimer? _hiitTimer;

  @override
  void initState() {
    super.initState();
    // 初始化插件
    _hiitTimer = BackgroundHIITTimer();

    // 配置HIIT计时器,例如:30秒工作,15秒休息,共4轮
    _hiitTimer?.configure(
      workIntervals: [30000], // 工作时间,单位毫秒
      restIntervals: [15000], // 休息时间,单位毫秒
      rounds: 4,              // 轮数
    );

    // 监听计时器状态变化
    _hiitTimer?.statusStream.listen((status) {
      print('HIIT Timer Status: $status');
      // 你可以在这里更新UI或执行其他操作
    });
  }

  @override
  void dispose() {
    _hiitTimer?.dispose();
    super.dispose();
  }

  void _startTimer() {
    _hiitTimer?.start();
  }

  @override
  Widget build(BuildContext context) {
    return ElevatedButton(
      onPressed: _startTimer,
      child: Text('Start HIIT Timer'),
    );
  }
}

4. 注意事项

  • 后台执行限制:在iOS上,后台执行受到严格限制。你可能需要申请特定的后台模式,如音频播放、位置更新等,以保持应用在后台运行。
  • 电池优化:后台运行会消耗电池,确保你的应用有合理的电池使用策略,避免不必要的后台活动。
  • 权限处理:在Android上,确保你的应用有必要的权限来处理后台任务,如访问网络、保持CPU唤醒等。

5. 测试和调试

在实际部署之前,务必在真实设备上进行充分的测试和调试,以确保后台计时器按预期工作。

请注意,由于background_hiit_timer是一个假设的插件,实际使用时需要参考具体插件的文档和API进行集成。如果这样的插件不存在,你可能需要自己实现后台计时器功能,或者寻找类似的第三方库。

回到顶部