mirror of
https://github.com/flutter/flutter.git
synced 2026-02-20 02:29:02 +08:00
Merge pull request #750 from Hixie/yak3-performance-view-listener-refactor
Refactor PerformanceView listeners.
This commit is contained in:
commit
d46aff8a46
@ -8,10 +8,11 @@
|
||||
library animation;
|
||||
|
||||
export 'src/animation/animated_value.dart';
|
||||
export 'src/animation/performance.dart';
|
||||
export 'src/animation/clamped_simulation.dart';
|
||||
export 'src/animation/curves.dart';
|
||||
export 'src/animation/forces.dart';
|
||||
export 'src/animation/listener_helpers.dart';
|
||||
export 'src/animation/performance.dart';
|
||||
export 'src/animation/scroll_behavior.dart';
|
||||
export 'src/animation/simulation_stepper.dart';
|
||||
export 'src/animation/ticker.dart';
|
||||
|
||||
88
packages/flutter/lib/src/animation/listener_helpers.dart
Normal file
88
packages/flutter/lib/src/animation/listener_helpers.dart
Normal file
@ -0,0 +1,88 @@
|
||||
// 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:ui' show VoidCallback;
|
||||
|
||||
/// The status of an animation
|
||||
enum PerformanceStatus {
|
||||
/// The animation is stopped at the beginning
|
||||
dismissed,
|
||||
|
||||
/// The animation is running from beginning to end
|
||||
forward,
|
||||
|
||||
/// The animation is running backwards, from end to beginning
|
||||
reverse,
|
||||
|
||||
/// The animation is stopped at the end
|
||||
completed,
|
||||
}
|
||||
|
||||
typedef void PerformanceStatusListener(PerformanceStatus status);
|
||||
|
||||
abstract class _ListenerMixin {
|
||||
void didRegisterListener();
|
||||
void didUnregisterListener();
|
||||
}
|
||||
|
||||
abstract class LazyListenerMixin implements _ListenerMixin {
|
||||
int _listenerCounter = 0;
|
||||
void didRegisterListener() {
|
||||
assert(_listenerCounter >= 0);
|
||||
if (_listenerCounter == 0)
|
||||
didStartListening();
|
||||
_listenerCounter += 1;
|
||||
}
|
||||
void didUnregisterListener() {
|
||||
assert(_listenerCounter >= 1);
|
||||
_listenerCounter -= 1;
|
||||
if (_listenerCounter == 0)
|
||||
didStopListening();
|
||||
}
|
||||
void didStartListening();
|
||||
void didStopListening();
|
||||
bool get isListening => _listenerCounter > 0;
|
||||
}
|
||||
|
||||
abstract class EagerListenerMixin implements _ListenerMixin {
|
||||
void didRegisterListener() { }
|
||||
void didUnregisterListener() { }
|
||||
|
||||
/// Release any resources used by this object.
|
||||
void dispose();
|
||||
}
|
||||
|
||||
abstract class LocalPerformanceListenersMixin extends _ListenerMixin {
|
||||
final List<VoidCallback> _listeners = <VoidCallback>[];
|
||||
void addListener(VoidCallback listener) {
|
||||
didRegisterListener();
|
||||
_listeners.add(listener);
|
||||
}
|
||||
void removeListener(VoidCallback listener) {
|
||||
_listeners.remove(listener);
|
||||
didUnregisterListener();
|
||||
}
|
||||
void notifyListeners() {
|
||||
List<VoidCallback> localListeners = new List<VoidCallback>.from(_listeners);
|
||||
for (VoidCallback listener in localListeners)
|
||||
listener();
|
||||
}
|
||||
}
|
||||
|
||||
abstract class LocalPerformanceStatusListenersMixin extends _ListenerMixin {
|
||||
final List<PerformanceStatusListener> _statusListeners = <PerformanceStatusListener>[];
|
||||
void addStatusListener(PerformanceStatusListener listener) {
|
||||
didRegisterListener();
|
||||
_statusListeners.add(listener);
|
||||
}
|
||||
void removeStatusListener(PerformanceStatusListener listener) {
|
||||
_statusListeners.remove(listener);
|
||||
didUnregisterListener();
|
||||
}
|
||||
void notifyStatusListeners(PerformanceStatus status) {
|
||||
List<PerformanceStatusListener> localListeners = new List<PerformanceStatusListener>.from(_statusListeners);
|
||||
for (PerformanceStatusListener listener in localListeners)
|
||||
listener(status);
|
||||
}
|
||||
}
|
||||
@ -10,23 +10,7 @@ import 'package:newton/newton.dart';
|
||||
import 'animated_value.dart';
|
||||
import 'forces.dart';
|
||||
import 'simulation_stepper.dart';
|
||||
|
||||
/// The status of an animation
|
||||
enum PerformanceStatus {
|
||||
/// The animation is stopped at the beginning
|
||||
dismissed,
|
||||
|
||||
/// The animation is running from beginning to end
|
||||
forward,
|
||||
|
||||
/// The animation is running backwards, from end to beginning
|
||||
reverse,
|
||||
|
||||
/// The animation is stopped at the end
|
||||
completed,
|
||||
}
|
||||
|
||||
typedef void PerformanceStatusListener(PerformanceStatus status);
|
||||
import 'listener_helpers.dart';
|
||||
|
||||
/// An interface that is implemented by [Performance] that exposes a
|
||||
/// read-only view of the underlying performance. This is used by classes that
|
||||
@ -89,10 +73,9 @@ class AlwaysCompletePerformance extends PerformanceView {
|
||||
}
|
||||
const AlwaysCompletePerformance alwaysCompletePerformance = const AlwaysCompletePerformance();
|
||||
|
||||
class ReversePerformance extends PerformanceView {
|
||||
ReversePerformance(this.masterPerformance) {
|
||||
masterPerformance.addStatusListener(_statusChangeHandler);
|
||||
}
|
||||
class ReversePerformance extends PerformanceView
|
||||
with LazyListenerMixin, LocalPerformanceStatusListenersMixin {
|
||||
ReversePerformance(this.masterPerformance);
|
||||
|
||||
final PerformanceView masterPerformance;
|
||||
|
||||
@ -101,27 +84,24 @@ class ReversePerformance extends PerformanceView {
|
||||
}
|
||||
|
||||
void addListener(VoidCallback listener) {
|
||||
didRegisterListener();
|
||||
masterPerformance.addListener(listener);
|
||||
}
|
||||
void removeListener(VoidCallback listener) {
|
||||
masterPerformance.removeListener(listener);
|
||||
didUnregisterListener();
|
||||
}
|
||||
|
||||
final List<PerformanceStatusListener> _statusListeners = new List<PerformanceStatusListener>();
|
||||
|
||||
void addStatusListener(PerformanceStatusListener listener) {
|
||||
_statusListeners.add(listener);
|
||||
void didStartListening() {
|
||||
masterPerformance.addStatusListener(_statusChangeHandler);
|
||||
}
|
||||
|
||||
void removeStatusListener(PerformanceStatusListener listener) {
|
||||
_statusListeners.remove(listener);
|
||||
void didStopListening() {
|
||||
masterPerformance.removeStatusListener(_statusChangeHandler);
|
||||
}
|
||||
|
||||
void _statusChangeHandler(PerformanceStatus status) {
|
||||
status = _reverseStatus(status);
|
||||
List<PerformanceStatusListener> localListeners = new List<PerformanceStatusListener>.from(_statusListeners);
|
||||
for (PerformanceStatusListener listener in localListeners)
|
||||
listener(status);
|
||||
notifyStatusListeners(_reverseStatus(status));
|
||||
}
|
||||
|
||||
PerformanceStatus get status => _reverseStatus(masterPerformance.status);
|
||||
@ -153,11 +133,16 @@ enum _TrainHoppingMode { minimize, maximize }
|
||||
/// going in the opposite direction, or because the one overtakes the other),
|
||||
/// the performance hops over to proxying the second performance, and the second
|
||||
/// performance becomes the new "first" performance.
|
||||
class TrainHoppingPerformance extends PerformanceView {
|
||||
///
|
||||
/// Since this object must track the two performances even when it has no
|
||||
/// listeners of its own, instead of shutting down when all its listeners are
|
||||
/// removed, it exposes a [dispose()] method. Call this method to shut this
|
||||
/// object down.
|
||||
class TrainHoppingPerformance extends PerformanceView
|
||||
with EagerListenerMixin, LocalPerformanceListenersMixin, LocalPerformanceStatusListenersMixin {
|
||||
TrainHoppingPerformance(this._currentTrain, this._nextTrain, { this.onSwitchedTrain }) {
|
||||
assert(_currentTrain != null);
|
||||
if (_nextTrain != null) {
|
||||
|
||||
if (_currentTrain.progress > _nextTrain.progress) {
|
||||
_mode = _TrainHoppingMode.maximize;
|
||||
} else {
|
||||
@ -187,37 +172,11 @@ class TrainHoppingPerformance extends PerformanceView {
|
||||
variable.setProgress(progress, curveDirection);
|
||||
}
|
||||
|
||||
final List<VoidCallback> _listeners = new List<VoidCallback>();
|
||||
|
||||
void addListener(VoidCallback listener) {
|
||||
assert(_currentTrain != null);
|
||||
_listeners.add(listener);
|
||||
}
|
||||
|
||||
void removeListener(VoidCallback listener) {
|
||||
assert(_currentTrain != null);
|
||||
_listeners.remove(listener);
|
||||
}
|
||||
|
||||
final List<PerformanceStatusListener> _statusListeners = new List<PerformanceStatusListener>();
|
||||
|
||||
void addStatusListener(PerformanceStatusListener listener) {
|
||||
assert(_currentTrain != null);
|
||||
_statusListeners.add(listener);
|
||||
}
|
||||
|
||||
void removeStatusListener(PerformanceStatusListener listener) {
|
||||
assert(_currentTrain != null);
|
||||
_statusListeners.remove(listener);
|
||||
}
|
||||
|
||||
PerformanceStatus _lastStatus;
|
||||
void _statusChangeHandler(PerformanceStatus status) {
|
||||
assert(_currentTrain != null);
|
||||
if (status != _lastStatus) {
|
||||
List<PerformanceStatusListener> localListeners = new List<PerformanceStatusListener>.from(_statusListeners);
|
||||
for (PerformanceStatusListener listener in localListeners)
|
||||
listener(status);
|
||||
notifyListeners();
|
||||
_lastStatus = status;
|
||||
}
|
||||
assert(_lastStatus != null);
|
||||
@ -250,9 +209,7 @@ class TrainHoppingPerformance extends PerformanceView {
|
||||
}
|
||||
double newProgress = progress;
|
||||
if (newProgress != _lastProgress) {
|
||||
List<VoidCallback> localListeners = new List<VoidCallback>.from(_listeners);
|
||||
for (VoidCallback listener in localListeners)
|
||||
listener();
|
||||
notifyListeners();
|
||||
_lastProgress = newProgress;
|
||||
}
|
||||
assert(_lastProgress != null);
|
||||
@ -276,107 +233,81 @@ class TrainHoppingPerformance extends PerformanceView {
|
||||
}
|
||||
}
|
||||
|
||||
class ProxyPerformance extends PerformanceView {
|
||||
class ProxyPerformance extends PerformanceView
|
||||
with LazyListenerMixin, LocalPerformanceListenersMixin, LocalPerformanceStatusListenersMixin {
|
||||
ProxyPerformance([PerformanceView performance]) {
|
||||
masterPerformance = performance;
|
||||
_masterPerformance = performance;
|
||||
if (_masterPerformance == null) {
|
||||
_status = PerformanceStatus.dismissed;
|
||||
_direction = AnimationDirection.forward;
|
||||
_curveDirection = AnimationDirection.forward;
|
||||
_progress = 0.0;
|
||||
}
|
||||
}
|
||||
|
||||
PerformanceStatus _status;
|
||||
AnimationDirection _direction;
|
||||
AnimationDirection _curveDirection;
|
||||
double _progress;
|
||||
|
||||
PerformanceView get masterPerformance => _masterPerformance;
|
||||
PerformanceView _masterPerformance;
|
||||
void set masterPerformance(PerformanceView value) {
|
||||
if (value == _masterPerformance)
|
||||
return;
|
||||
if (_masterPerformance != null) {
|
||||
_masterPerformance.removeStatusListener(_statusChangeHandler);
|
||||
_masterPerformance.removeListener(_valueChangeHandler);
|
||||
_status = _masterPerformance.status;
|
||||
_direction = _masterPerformance.direction;
|
||||
_curveDirection = _masterPerformance.curveDirection;
|
||||
_progress = _masterPerformance.progress;
|
||||
if (isListening)
|
||||
didStopListening();
|
||||
}
|
||||
_masterPerformance = value;
|
||||
if (_masterPerformance != null) {
|
||||
if (isListening)
|
||||
didStartListening();
|
||||
if (_progress != _masterPerformance.progress)
|
||||
notifyListeners();
|
||||
if (_status != _masterPerformance.status)
|
||||
notifyStatusListeners(_masterPerformance.status);
|
||||
_status = null;
|
||||
_direction = null;
|
||||
_curveDirection = null;
|
||||
_progress = null;
|
||||
}
|
||||
}
|
||||
|
||||
void didStartListening() {
|
||||
if (_masterPerformance != null) {
|
||||
_masterPerformance.addListener(_valueChangeHandler);
|
||||
_masterPerformance.addStatusListener(_statusChangeHandler);
|
||||
_valueChangeHandler();
|
||||
_statusChangeHandler(_masterPerformance.status);
|
||||
}
|
||||
}
|
||||
|
||||
void didStopListening() {
|
||||
if (_masterPerformance != null) {
|
||||
_masterPerformance.removeListener(_valueChangeHandler);
|
||||
_masterPerformance.removeStatusListener(_statusChangeHandler);
|
||||
}
|
||||
}
|
||||
|
||||
void _valueChangeHandler() {
|
||||
notifyListeners();
|
||||
}
|
||||
|
||||
void _statusChangeHandler(PerformanceStatus status) {
|
||||
notifyStatusListeners(status);
|
||||
}
|
||||
|
||||
void updateVariable(Animatable variable) {
|
||||
variable.setProgress(progress, curveDirection);
|
||||
}
|
||||
|
||||
final List<VoidCallback> _listeners = new List<VoidCallback>();
|
||||
|
||||
void addListener(VoidCallback listener) {
|
||||
_listeners.add(listener);
|
||||
}
|
||||
|
||||
void removeListener(VoidCallback listener) {
|
||||
_listeners.remove(listener);
|
||||
}
|
||||
|
||||
final List<PerformanceStatusListener> _statusListeners = new List<PerformanceStatusListener>();
|
||||
|
||||
void addStatusListener(PerformanceStatusListener listener) {
|
||||
_statusListeners.add(listener);
|
||||
}
|
||||
|
||||
void removeStatusListener(PerformanceStatusListener listener) {
|
||||
_statusListeners.remove(listener);
|
||||
}
|
||||
|
||||
PerformanceStatus _status = PerformanceStatus.dismissed;
|
||||
AnimationDirection _direction = AnimationDirection.forward;
|
||||
AnimationDirection _curveDirection = AnimationDirection.forward;
|
||||
void _statusChangeHandler(PerformanceStatus status) {
|
||||
assert(_masterPerformance != null);
|
||||
if (status != _status) {
|
||||
_status = status;
|
||||
_direction = _masterPerformance.direction;
|
||||
List<PerformanceStatusListener> localListeners = new List<PerformanceStatusListener>.from(_statusListeners);
|
||||
for (PerformanceStatusListener listener in localListeners)
|
||||
listener(status);
|
||||
}
|
||||
}
|
||||
|
||||
PerformanceStatus get status => _status;
|
||||
AnimationDirection get direction => _direction;
|
||||
AnimationDirection get curveDirection => _curveDirection;
|
||||
|
||||
double _progress = 0.0;
|
||||
void _valueChangeHandler() {
|
||||
assert(_masterPerformance != null);
|
||||
double newProgress = _masterPerformance.progress;
|
||||
if (newProgress != _progress) {
|
||||
_progress = newProgress;
|
||||
_curveDirection = _masterPerformance.curveDirection;
|
||||
List<VoidCallback> localListeners = new List<VoidCallback>.from(_listeners);
|
||||
for (VoidCallback listener in localListeners)
|
||||
listener();
|
||||
}
|
||||
}
|
||||
|
||||
double get progress => _progress;
|
||||
}
|
||||
|
||||
class _RepeatingSimulation extends Simulation {
|
||||
_RepeatingSimulation(this.min, this.max, Duration period)
|
||||
: _periodInSeconds = period.inMicroseconds.toDouble() / Duration.MICROSECONDS_PER_SECOND {
|
||||
assert(_periodInSeconds > 0.0);
|
||||
}
|
||||
|
||||
final double min;
|
||||
final double max;
|
||||
|
||||
final double _periodInSeconds;
|
||||
|
||||
double x(double timeInSeconds) {
|
||||
assert(timeInSeconds >= 0.0);
|
||||
final double t = (timeInSeconds / _periodInSeconds) % 1.0;
|
||||
return lerpDouble(min, max, t);
|
||||
}
|
||||
|
||||
double dx(double timeInSeconds) => 1.0;
|
||||
|
||||
bool isDone(double timeInSeconds) => false;
|
||||
PerformanceStatus get status => _masterPerformance != null ? _masterPerformance.status : _status;
|
||||
AnimationDirection get direction => _masterPerformance != null ? _masterPerformance.direction : _direction;
|
||||
AnimationDirection get curveDirection => _masterPerformance != null ? _masterPerformance.curveDirection : _curveDirection;
|
||||
double get progress => _masterPerformance != null ? _masterPerformance.progress : _progress;
|
||||
}
|
||||
|
||||
/// A timeline that can be reversed and used to update [Animatable]s.
|
||||
@ -387,7 +318,8 @@ class _RepeatingSimulation extends Simulation {
|
||||
/// may also take direct control of the timeline by manipulating [progress], or
|
||||
/// [fling] the timeline causing a physics-based simulation to take over the
|
||||
/// progression.
|
||||
class Performance extends PerformanceView {
|
||||
class Performance extends PerformanceView
|
||||
with EagerListenerMixin, LocalPerformanceListenersMixin, LocalPerformanceStatusListenersMixin {
|
||||
Performance({ this.duration, double progress, this.debugLabel }) {
|
||||
_timeline = new SimulationStepper(_tick);
|
||||
if (progress != null)
|
||||
@ -464,11 +396,18 @@ class Performance extends PerformanceView {
|
||||
return _animateTo(_direction == AnimationDirection.forward ? 1.0 : 0.0);
|
||||
}
|
||||
|
||||
/// Stop running this animation
|
||||
/// Stop running this animation.
|
||||
void stop() {
|
||||
_timeline.stop();
|
||||
}
|
||||
|
||||
/// Release any resources used by this object.
|
||||
///
|
||||
/// Same as stop().
|
||||
void dispose() {
|
||||
stop();
|
||||
}
|
||||
|
||||
/// Start running this animation according to the given physical parameters
|
||||
///
|
||||
/// Flings the timeline with an optional force (defaults to a critically
|
||||
@ -487,40 +426,11 @@ class Performance extends PerformanceView {
|
||||
return _timeline.animateWith(new _RepeatingSimulation(min, max, period));
|
||||
}
|
||||
|
||||
final List<VoidCallback> _listeners = new List<VoidCallback>();
|
||||
|
||||
void addListener(VoidCallback listener) {
|
||||
_listeners.add(listener);
|
||||
}
|
||||
|
||||
void removeListener(VoidCallback listener) {
|
||||
_listeners.remove(listener);
|
||||
}
|
||||
|
||||
void _notifyListeners() {
|
||||
List<VoidCallback> localListeners = new List<VoidCallback>.from(_listeners);
|
||||
for (VoidCallback listener in localListeners)
|
||||
listener();
|
||||
}
|
||||
|
||||
final List<PerformanceStatusListener> _statusListeners = new List<PerformanceStatusListener>();
|
||||
|
||||
void addStatusListener(PerformanceStatusListener listener) {
|
||||
_statusListeners.add(listener);
|
||||
}
|
||||
|
||||
void removeStatusListener(PerformanceStatusListener listener) {
|
||||
_statusListeners.remove(listener);
|
||||
}
|
||||
|
||||
PerformanceStatus _lastStatus = PerformanceStatus.dismissed;
|
||||
void _checkStatusChanged() {
|
||||
PerformanceStatus currentStatus = status;
|
||||
if (currentStatus != _lastStatus) {
|
||||
List<PerformanceStatusListener> localListeners = new List<PerformanceStatusListener>.from(_statusListeners);
|
||||
for (PerformanceStatusListener listener in localListeners)
|
||||
listener(currentStatus);
|
||||
}
|
||||
if (currentStatus != _lastStatus)
|
||||
notifyStatusListeners(status);
|
||||
_lastStatus = currentStatus;
|
||||
}
|
||||
|
||||
@ -545,7 +455,7 @@ class Performance extends PerformanceView {
|
||||
}
|
||||
|
||||
void didTick(double t) {
|
||||
_notifyListeners();
|
||||
notifyListeners();
|
||||
_checkStatusChanged();
|
||||
}
|
||||
|
||||
@ -570,3 +480,25 @@ class ValuePerformance<T> extends Performance {
|
||||
super.didTick(t);
|
||||
}
|
||||
}
|
||||
|
||||
class _RepeatingSimulation extends Simulation {
|
||||
_RepeatingSimulation(this.min, this.max, Duration period)
|
||||
: _periodInSeconds = period.inMicroseconds.toDouble() / Duration.MICROSECONDS_PER_SECOND {
|
||||
assert(_periodInSeconds > 0.0);
|
||||
}
|
||||
|
||||
final double min;
|
||||
final double max;
|
||||
|
||||
final double _periodInSeconds;
|
||||
|
||||
double x(double timeInSeconds) {
|
||||
assert(timeInSeconds >= 0.0);
|
||||
final double t = (timeInSeconds / _periodInSeconds) % 1.0;
|
||||
return lerpDouble(min, max, t);
|
||||
}
|
||||
|
||||
double dx(double timeInSeconds) => 1.0;
|
||||
|
||||
bool isDone(double timeInSeconds) => false;
|
||||
}
|
||||
|
||||
@ -13,7 +13,9 @@ class TestTransition extends TransitionComponent {
|
||||
this.childFirstHalf,
|
||||
this.childSecondHalf,
|
||||
PerformanceView performance
|
||||
}) : super(key: key, performance: performance);
|
||||
}) : super(key: key, performance: performance) {
|
||||
assert(performance != null);
|
||||
}
|
||||
|
||||
final Widget childFirstHalf;
|
||||
final Widget childSecondHalf;
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user