Skip to content

Commit 7b0cccb

Browse files
committed
address follow up to flutter#20354
1 parent e7d87af commit 7b0cccb

File tree

8 files changed

+55
-41
lines changed

8 files changed

+55
-41
lines changed

packages/flutter/lib/src/animation/animation_controller.dart

Lines changed: 10 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,6 @@ import 'dart:ui' as ui show lerpDouble;
77

88
import 'package:flutter/foundation.dart';
99
import 'package:flutter/physics.dart';
10-
import 'package:flutter/semantics.dart';
1110
import 'package:flutter/scheduler.dart';
1211

1312
import 'animation.dart';
@@ -44,7 +43,7 @@ const Tolerance _kFlingTolerance = Tolerance(
4443
/// When [AccessibilityFeatures.disableAnimations] is true, the device is asking
4544
/// flutter to reduce or disable animations as much as possible. To honor this,
4645
/// we reduce the duration and the corresponding number of frames for animations.
47-
/// This enum is used to allow certain [AnimationControllers] to opt out of this
46+
/// This enum is used to allow certain [AnimationController]s to opt out of this
4847
/// behavior.
4948
///
5049
/// For example, the [AnimationController] which controls the physics simulation
@@ -200,9 +199,9 @@ class AnimationController extends Animation<double>
200199
/// The behavior of the controller when [AccessibilityFeatures.disableAnimations]
201200
/// is true.
202201
///
203-
/// Defaults to [AnimationBehavior.normal] for the [new AnimationBehavior]
202+
/// Defaults to [AnimationBehavior.normal] for the [new AnimationController]
204203
/// constructor, and [AnimationBehavior.preserve] for the
205-
/// [new AnimationBehavior.unbounded] constructor.
204+
/// [new AnimationController.unbounded] constructor.
206205
final AnimationBehavior animationBehavior;
207206

208207
/// Returns an [Animation<double>] for this animation controller, so that a
@@ -401,9 +400,12 @@ class AnimationController extends Animation<double>
401400
TickerFuture _animateToInternal(double target, { Duration duration, Curve curve = Curves.linear, AnimationBehavior animationBehavior }) {
402401
final AnimationBehavior behavior = animationBehavior ?? this.animationBehavior;
403402
double scale = 1.0;
404-
if (SemanticsBinding.instance.disableAnimations) {
403+
if (_ticker.disableAnimations) {
405404
switch (behavior) {
406405
case AnimationBehavior.normal:
406+
// Since the framework cannot handle zero duration animations, we run it at 5% of the normal
407+
// duration to limit most animations to a single frame.
408+
// TODO(jonahwilliams): determine a better process for setting duration.
407409
scale = 0.05;
408410
break;
409411
case AnimationBehavior.preserve:
@@ -487,16 +489,16 @@ class AnimationController extends Animation<double>
487489
/// The most recently returned [TickerFuture], if any, is marked as having been
488490
/// canceled, meaning the future never completes and its [TickerFuture.orCancel]
489491
/// derivative future completes with a [TickerCanceled] error.
490-
TickerFuture fling({ double velocity = 1.0, AnimationBehavior animationBehavior}) {
492+
TickerFuture fling({ double velocity = 1.0, AnimationBehavior animationBehavior }) {
491493
_direction = velocity < 0.0 ? _AnimationDirection.reverse : _AnimationDirection.forward;
492494
final double target = velocity < 0.0 ? lowerBound - _kFlingTolerance.distance
493495
: upperBound + _kFlingTolerance.distance;
494496
double scale = 1.0;
495497
final AnimationBehavior behavior = animationBehavior ?? this.animationBehavior;
496-
if (SemanticsBinding.instance.disableAnimations) {
498+
if (_ticker.disableAnimations) {
497499
switch (behavior) {
498500
case AnimationBehavior.normal:
499-
scale = 200.0;
501+
scale = 200.0; // TODO(jonahwilliams): determine a better process for setting velocity.
500502
break;
501503
case AnimationBehavior.preserve:
502504
break;

packages/flutter/lib/src/scheduler/ticker.dart

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,7 @@ class Ticker {
5959
///
6060
/// An optional label can be provided for debugging purposes. That label
6161
/// will appear in the [toString] output in debug builds.
62-
Ticker(this._onTick, { this.debugLabel }) {
62+
Ticker(this._onTick, { this.debugLabel, this.disableAnimations = false}) {
6363
assert(() {
6464
_debugCreationStack = StackTrace.current;
6565
return true;
@@ -68,6 +68,12 @@ class Ticker {
6868

6969
TickerFuture _future;
7070

71+
/// Whether the platform is requesting that animations be disabled.
72+
///
73+
/// See also:
74+
/// [AccessibilityFeatures.disableAnimations], for the setting this value comes from.
75+
bool disableAnimations;
76+
7177
/// Whether this ticker has been silenced.
7278
///
7379
/// While silenced, a ticker's clock can still run, but the callback will not

packages/flutter/lib/src/semantics/binding.dart

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -5,12 +5,12 @@
55
import 'dart:ui' as ui show AccessibilityFeatures, window;
66

77
import 'package:flutter/foundation.dart';
8-
import 'package:flutter/services.dart';
98

9+
export 'dart:ui' show AccessibilityFeatures;
1010

1111
/// The glue between the semantics layer and the Flutter engine.
1212
// TODO(jonahwilliams): move the remaining semantic related bindings here.
13-
class SemanticsBinding extends BindingBase with ServicesBinding {
13+
class SemanticsBinding extends BindingBase {
1414
// This class is intended to be used as a mixin, and should not be
1515
// extended directly.
1616
factory SemanticsBinding._() => null;
@@ -43,7 +43,4 @@ class SemanticsBinding extends BindingBase with ServicesBinding {
4343
/// [WidgetsBindingObserver] and listen to [didChangeAccessibilityFeatures].
4444
ui.AccessibilityFeatures get accessibilityFeatures => _accessibilityFeatures;
4545
ui.AccessibilityFeatures _accessibilityFeatures;
46-
47-
/// Whether the device is requesting that animations be disabled.
48-
bool get disableAnimations => accessibilityFeatures.disableAnimations;
4946
}

packages/flutter/lib/src/widgets/ticker_provider.dart

Lines changed: 13 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import 'package:flutter/foundation.dart';
66
import 'package:flutter/scheduler.dart';
77

88
import 'framework.dart';
9+
import 'media_query.dart';
910

1011
export 'package:flutter/scheduler.dart' show TickerProvider;
1112

@@ -83,6 +84,7 @@ abstract class SingleTickerProviderStateMixin<T extends StatefulWidget> extends
8384

8485
@override
8586
Ticker createTicker(TickerCallback onTick) {
87+
final bool disableAnimations = MediaQuery.of(context).disableAnimations;
8688
assert(() {
8789
if (_ticker == null)
8890
return true;
@@ -94,7 +96,7 @@ abstract class SingleTickerProviderStateMixin<T extends StatefulWidget> extends
9496
'mixing in a SingleTickerProviderStateMixin, use a regular TickerProviderStateMixin.'
9597
);
9698
}());
97-
_ticker = new Ticker(onTick, debugLabel: 'created by $this');
99+
_ticker = new Ticker(onTick, debugLabel: 'created by $this', disableAnimations: disableAnimations);
98100
// We assume that this is called from initState, build, or some sort of
99101
// event handler, and that thus TickerMode.of(context) would return true. We
100102
// can't actually check that here because if we're in initState then we're
@@ -122,8 +124,10 @@ abstract class SingleTickerProviderStateMixin<T extends StatefulWidget> extends
122124

123125
@override
124126
void didChangeDependencies() {
125-
if (_ticker != null)
127+
if (_ticker != null) {
126128
_ticker.muted = !TickerMode.of(context);
129+
_ticker.disableAnimations = MediaQuery.of(context).disableAnimations;
130+
}
127131
super.didChangeDependencies();
128132
}
129133

@@ -166,8 +170,9 @@ abstract class TickerProviderStateMixin<T extends StatefulWidget> extends State<
166170

167171
@override
168172
Ticker createTicker(TickerCallback onTick) {
173+
final bool disableAnimations = MediaQuery.of(context).disableAnimations;
169174
_tickers ??= new Set<_WidgetTicker>();
170-
final _WidgetTicker result = new _WidgetTicker(onTick, this, debugLabel: 'created by $this');
175+
final _WidgetTicker result = new _WidgetTicker(onTick, this, debugLabel: 'created by $this', disableAnimations: disableAnimations);
171176
_tickers.add(result);
172177
return result;
173178
}
@@ -204,9 +209,12 @@ abstract class TickerProviderStateMixin<T extends StatefulWidget> extends State<
204209
@override
205210
void didChangeDependencies() {
206211
final bool muted = !TickerMode.of(context);
212+
final bool disableAnimations = MediaQuery.of(context).disableAnimations;
207213
if (_tickers != null) {
208-
for (Ticker ticker in _tickers)
214+
for (Ticker ticker in _tickers) {
209215
ticker.muted = muted;
216+
ticker.disableAnimations = disableAnimations;
217+
}
210218
}
211219
super.didChangeDependencies();
212220
}
@@ -231,7 +239,7 @@ abstract class TickerProviderStateMixin<T extends StatefulWidget> extends State<
231239
// confusing. Instead we use the less precise but more anodyne "_WidgetTicker",
232240
// which attracts less attention.
233241
class _WidgetTicker extends Ticker {
234-
_WidgetTicker(TickerCallback onTick, this._creator, { String debugLabel }) : super(onTick, debugLabel: debugLabel);
242+
_WidgetTicker(TickerCallback onTick, this._creator, { String debugLabel, bool disableAnimations = false}) : super(onTick, debugLabel: debugLabel, disableAnimations: disableAnimations);
235243

236244
final TickerProviderStateMixin _creator;
237245

packages/flutter/test/animation/animation_controller_test.dart

Lines changed: 9 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -581,17 +581,16 @@ void main() {
581581

582582
group('AnimationBehavior', () {
583583
test('Default values for constructor', () {
584-
final AnimationController controller = new AnimationController(vsync: const TestVSync());
584+
final AnimationController controller = new AnimationController(vsync: const TestVSync(disableAnimations: true));
585585
expect(controller.animationBehavior, AnimationBehavior.normal);
586586

587-
final AnimationController repeating = new AnimationController.unbounded(vsync: const TestVSync());
587+
final AnimationController repeating = new AnimationController.unbounded(vsync: const TestVSync(disableAnimations: true));
588588
expect(repeating.animationBehavior, AnimationBehavior.preserve);
589589
});
590590

591-
testWidgets('AnimationBehavior.preserve runs at normal speed when animatingTo', (WidgetTester tester) async {
592-
tester.binding.disableAnimations = true;
591+
test('AnimationBehavior.preserve runs at normal speed when animatingTo', () async {
593592
final AnimationController controller = new AnimationController(
594-
vsync: const TestVSync(),
593+
vsync: const TestVSync(disableAnimations: true),
595594
animationBehavior: AnimationBehavior.preserve,
596595
);
597596

@@ -610,13 +609,11 @@ void main() {
610609

611610
expect(controller.value, 1.0);
612611
expect(controller.status, AnimationStatus.completed);
613-
tester.binding.disableAnimations = false;
614612
});
615613

616-
testWidgets('AnimationBehavior.normal runs at 20x speed when animatingTo', (WidgetTester tester) async {
617-
tester.binding.disableAnimations = true;
614+
test('AnimationBehavior.normal runs at 20x speed when animatingTo', () async {
618615
final AnimationController controller = new AnimationController(
619-
vsync: const TestVSync(),
616+
vsync: const TestVSync(disableAnimations: true),
620617
animationBehavior: AnimationBehavior.normal,
621618
);
622619

@@ -635,17 +632,14 @@ void main() {
635632

636633
expect(controller.value, 1.0);
637634
expect(controller.status, AnimationStatus.completed);
638-
639-
tester.binding.disableAnimations = false;
640635
});
641636

642-
testWidgets('AnimationBehavior.normal runs "faster" whan AnimationBehavior.preserve', (WidgetTester tester) async {
643-
tester.binding.disableAnimations = true;
637+
test('AnimationBehavior.normal runs "faster" whan AnimationBehavior.preserve', () {
644638
final AnimationController controller = new AnimationController(
645-
vsync: const TestVSync(),
639+
vsync: const TestVSync(disableAnimations: true),
646640
);
647641
final AnimationController fastController = new AnimationController(
648-
vsync: const TestVSync(),
642+
vsync: const TestVSync(disableAnimations: true),
649643
);
650644

651645
controller.fling(velocity: 1.0, animationBehavior: AnimationBehavior.preserve);
@@ -655,7 +649,6 @@ void main() {
655649

656650
// We don't assert a specific faction that normal animation.
657651
expect(controller.value < fastController.value, true);
658-
tester.binding.disableAnimations = false;
659652
});
660653
});
661654
}

packages/flutter/test/rendering/proxy_box_test.dart

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -246,7 +246,7 @@ void main() {
246246

247247
class _FakeTickerProvider implements TickerProvider {
248248
@override
249-
Ticker createTicker(TickerCallback onTick) {
249+
Ticker createTicker(TickerCallback onTick, [bool disableAnimations = false]) {
250250
return new _FakeTicker();
251251
}
252252
}
@@ -273,6 +273,9 @@ class _FakeTicker implements Ticker {
273273
@override
274274
bool get shouldScheduleTick => null;
275275

276+
@override
277+
bool disableAnimations = false;
278+
276279
@override
277280
void dispose() {}
278281

packages/flutter_test/lib/src/binding.dart

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -128,9 +128,6 @@ abstract class TestWidgetsFlutterBinding extends BindingBase
128128
@protected
129129
bool get checkIntrinsicSizes => false;
130130

131-
@override
132-
bool disableAnimations = false;
133-
134131
/// Creates and initializes the binding. This function is
135132
/// idempotent; calling it a second time will just return the
136133
/// previously-created instance.

packages/flutter_test/lib/src/test_vsync.dart

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,16 @@ import 'package:flutter/scheduler.dart';
1010
/// tree.
1111
class TestVSync implements TickerProvider {
1212
/// Creates a ticker provider that creates standalone tickers.
13-
const TestVSync();
13+
const TestVSync({this.disableAnimations = false});
14+
15+
/// Whether to disable the animations of tickers create from this picker.
16+
///
17+
/// See also:
18+
///
19+
/// * [AccessibilityFeatures.disableAnimations], for the setting that controls this flag.
20+
/// * [AnimationBehavior], for how animation controllers change when created from tickers with this flag.
21+
final bool disableAnimations;
1422

1523
@override
16-
Ticker createTicker(TickerCallback onTick) => new Ticker(onTick);
24+
Ticker createTicker(TickerCallback onTick) => new Ticker(onTick, disableAnimations: disableAnimations);
1725
}

0 commit comments

Comments
 (0)