2 votes

Comment démarrer un compteur à partir de zéro dans Flutter ?

J'ai essayé d'afficher un timer (format dd HH mm ss) pour compter le temps entre chaque action (action d'un bouton par exemple). Et cela doit fonctionner même si l'application est fermée et reconstruite. Actuellement je charge une chaîne de date que j'ai sauvegardé avec sharedpreference quand j'ai appuyé sur un bouton qui représente le temps quand j'ai appuyé sur le bouton. Je formate tous les temps décimaux pour comparer et afficher la différence de temps. Je pense que ce n'est pas beau, pas ce que je cherche, et je n'ai pas réussi à afficher l'horloge dans le format (dd HH mm ss). Si quelqu'un a un exemple plus simple :)

load_records_pulsion() async{

    /*var current_time = DateFormat('yyyy-MM-dd HH').format(DateTime.now());*/
    SharedPreferences prefs = await SharedPreferences.getInstance();
    setState(() {
      RegExp regExp = new RegExp(            //Here is the regex time pulsion
        r"([12]\d{3})-(0[1-9]|1[0-2])-(0[1-9]|[12]\d|3[01])",
      );
      last_pulsion = (prefs.getString('last_pulsion'))??0;

      var match = regExp.firstMatch("$last_pulsion");
      annees = match.group(1);   // hh:mm
      mois = match.group(2);   // hh:mm
      jours = match.group(3);   // hh:mm

      int annees_int = int.tryParse("$annees") ;
      int mois_int = int.tryParse("$mois") ;
      int jours_int = int.tryParse("$jours") ;
      print("$annees_int");
      print("$mois_int");
      print("$jours_int");

      final last_pulsion2 = DateTime(annees_int, mois_int, jours_int);
      final date_now = DateTime.now();
      difference_pulsion = date_now.difference(last_pulsion2).inDays;

      if(difference_pulsion==0){
        difference_pulsion ="";
        prefix_pulsion ="Aujourd'hui";
      }else{
        prefix_pulsion ="jours";
      }

    });
  }

J'ai également essayé ce code, c'est OK, la minuterie augmente quand j'appelle la fonction, mais je ne veux pas de datenow, j'ai juste besoin de commencer avec un temps zéro.

int _start = 0;
  void startTimer() {
    _start=0;
    var now = new DateTime.now();
    const oneSec = const Duration(seconds: 1);
    _timer = new Timer.periodic(
        oneSec,
            (Timer timer) => setState(() {
        {
          chrono = now.add(new Duration(seconds: _start));
            _start = _start + 1;
          }
        }));
  }

Edit : J'ai trouvé cette solution mais j'ai des erreurs de cycle de vie, et si je ferme l'application, je perds le timer.

 Stopwatch stopwatch = new Stopwatch();

  void rightButtonPressed() {
    setState(() {
      if (stopwatch.isRunning) {
        stopwatch.reset();
      } else {
        stopwatch.reset();
        stopwatch.start();
      }
    });
  }
 @override
  Widget build(BuildContext context)
  {
...
     new Container(height: 80.0,
            child: new Center(
              child: new TimerText(stopwatch: stopwatch),
            )),

...
class TimerText extends StatefulWidget {
  TimerText({this.stopwatch});
  final Stopwatch stopwatch;

  TimerTextState createState() => new TimerTextState(stopwatch: stopwatch);
}

class TimerTextState extends State<TimerText> {

  Timer timer;
  final Stopwatch stopwatch;

  TimerTextState({this.stopwatch}) {
    timer = new Timer.periodic(new Duration(milliseconds: 30), callback);
  }

  void callback(Timer timer) {
    if (stopwatch.isRunning) {
      setState(() {

      });
    }
  }

  @override
  Widget build(BuildContext context) {
    final TextStyle timerTextStyle = const TextStyle(fontSize: 50.0, fontFamily: "Open Sans");
    String formattedTime = TimerTextFormatter.format(stopwatch.elapsedMilliseconds);
    return new Text(formattedTime, style: timerTextStyle);
  }
}

class TimerTextFormatter {
  static String format(int milliseconds) {

    int seconds = (milliseconds / 1000).truncate();
    int minutes = (seconds / 60).truncate();
    int hours = (minutes / 60).truncate();
    int days = (hours / 24).truncate();
    String minutesStr = (minutes % 60).toString().padLeft(2, '0');
    String secondsStr = (seconds % 60).toString().padLeft(2, '0');
    String hoursStr = (hours % 60).toString().padLeft(2, '0');
    String daysStr = (days % 24).toString().padLeft(2, '0');
    return "$daysStr:$hoursStr:$minutesStr:$secondsStr";
  }
}

2voto

ZeRj Points 1059

Si vous voulez que le compteur persiste après la fermeture de l'application, il n'y a aucun moyen de ne pas enregistrer la valeur quelque part (comme les préférences partagées).

L'utilisation de dateTime.toIso8601String() et DateTime.parse() rendra la sauvegarde et le chargement moins disgracieux. Pour calculer le temps écoulé, vous pouvez utiliser DateTime.now().difference(lastButtonPressed).

Il devrait y avoir une fonction pour formater la durée ( https://api.flutter.dev/flutter/intl/DateFormat/formatDurationFrom.html ) mais il n'est pas encore mis en œuvre. J'en ai trouvé un ici : Formatage d'une durée comme HH:mm:ss

Voici un petit exemple :

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

class TestWidget extends StatefulWidget {
  @override
  _TestWidgetState createState() => _TestWidgetState();
}

class _TestWidgetState extends State<TestWidget> {
  DateTime _lastButtonPress;
  String _pressDuration;
  Timer _ticker;

  @override
  Widget build(BuildContext context) {
    return Center(
      child: Column(
        mainAxisAlignment: MainAxisAlignment.center,
        children: <Widget>[
          Text("Time since button pressed"),
          Text(_pressDuration),
          RaisedButton(
            child: Text("Press me"),
            onPressed: () {
              _lastButtonPress = DateTime.now();
              _updateTimer();
              sharedPreferences.setString("lastButtonPress",_lastButtonPress.toIso8601String());
            },
          )
        ],
      ),
    );
  }

  @override
  void initState() {
    super.initState();
    final lastPressString = sharedPreferences.getString("lastButtonPress");
    _lastButtonPress = lastPressString!=null ? DateTime.parse(lastPressString) : DateTime.now();
    _updateTimer();
    _ticker = Timer.periodic(Duration(seconds:1),(_)=>_updateTimer());
  }

  @override
  void dispose() {
    _ticker.cancel();
    super.dispose();
  }

  void _updateTimer() {
    final duration = DateTime.now().difference(_lastButtonPress);
    final newDuration = _formatDuration(duration);
    setState(() {
      _pressDuration = newDuration;
    });
  }

  String _formatDuration(Duration duration) {
    String twoDigits(int n) {
      if (n >= 10) return "$n";
      return "0$n";
    }

    String twoDigitMinutes = twoDigits(duration.inMinutes.remainder(60));
    String twoDigitSeconds = twoDigits(duration.inSeconds.remainder(60));
    return "${twoDigits(duration.inHours)}:$twoDigitMinutes:$twoDigitSeconds";
  }
}

Pour simplifier, j'ai initialisé les préférences partagées dans la méthode main, dans la portée globale. Example

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X