ticker.dart 2.53 KB
Newer Older
1 2 3 4 5 6
// Copyright 2015 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

import 'dart:async';

7
import 'binding.dart';
8

9
/// Signature for the [onTick] constructor argument of the [Ticker] class.
10 11
///
/// The argument is the time that the object had spent enabled so far
12
/// at the time of the callback being called.
13
typedef void TickerCallback(Duration elapsed);
14

Florian Loitsch's avatar
Florian Loitsch committed
15
/// Calls its callback once per animation frame.
16 17 18 19
///
/// When created, a ticker is initially disabled. Call [start] to
/// enable the ticker.
///
20
/// See also [SchedulerBinding.scheduleFrameCallback].
21
class Ticker {
22
  /// Creates a ticker that will call [onTick] once per frame while running.
Adam Barth's avatar
Adam Barth committed
23
  Ticker(TickerCallback onTick) : _onTick = onTick;
24

Adam Barth's avatar
Adam Barth committed
25
  final TickerCallback _onTick;
26

27
  Completer<Null> _completer;
28
  int _animationId;
29
  Duration _startTime;
30

31
  /// Whether this ticker has scheduled a call to call its callback
32 33 34 35
  /// on the next frame.
  bool get isTicking => _completer != null;

  /// Starts calling the ticker's callback once per animation frame.
36 37
  ///
  /// The returned future resolves once the ticker stops ticking.
38
  Future<Null> start() {
39
    assert(!isTicking);
40
    assert(_startTime == null);
41
    _completer = new Completer<Null>();
42 43 44 45
    _scheduleTick();
    return _completer.future;
  }

46
  /// Stops calling the ticker's callback.
47 48
  ///
  /// Causes the future returned by [start] to resolve.
49 50 51 52
  void stop() {
    if (!isTicking)
      return;

53 54
    _startTime = null;

55
    if (_animationId != null) {
56
      SchedulerBinding.instance.cancelFrameCallbackWithId(_animationId);
57 58 59
      _animationId = null;
    }

Adam Barth's avatar
Adam Barth committed
60
    // We take the _completer into a local variable so that isTicking is false
61 62
    // when we actually complete the future (isTicking uses _completer
    // to determine its state).
63
    Completer<Null> localCompleter = _completer;
64 65 66 67 68
    _completer = null;
    assert(!isTicking);
    localCompleter.complete();
  }

69
  void _tick(Duration timeStamp) {
70 71 72 73
    assert(isTicking);
    assert(_animationId != null);
    _animationId = null;

74 75 76 77
    if (_startTime == null)
      _startTime = timeStamp;

    _onTick(timeStamp - _startTime);
78

79 80
    // The onTick callback may have scheduled another tick already.
    if (isTicking && _animationId == null)
81
      _scheduleTick(rescheduling: true);
82 83
  }

84
  void _scheduleTick({ bool rescheduling: false }) {
85 86
    assert(isTicking);
    assert(_animationId == null);
87
    _animationId = SchedulerBinding.instance.scheduleFrameCallback(_tick, rescheduling: rescheduling);
88 89
  }
}