Black flash when returning to a PageRoute

We were trying to do a hero animation from a page to itself, which doesn't make
any sense. Now we only render the "to" page offstage if it is different from
the "from" page and if its performance isn't already complete.
This commit is contained in:
Adam Barth 2015-10-31 15:36:32 -07:00
parent 56b2576308
commit 6ee6ae03c9
2 changed files with 121 additions and 2 deletions

View File

@ -45,8 +45,10 @@ class HeroController {
return;
}
_to = current;
current.offstage = true;
scheduler.requestPostFrameCallback(_updateQuest);
if (_from != _to) {
current.offstage = current.performance.status != PerformanceStatus.completed;
scheduler.requestPostFrameCallback(_updateQuest);
}
}
void _handleQuestFinished() {

View File

@ -0,0 +1,117 @@
import 'package:flutter/material.dart';
import 'package:test/test.dart';
import 'widget_tester.dart';
class TestOverlayRoute extends OverlayRoute {
List<Widget> createWidgets() => <Widget>[ new Text('Overlay') ];
}
bool _isOnStage(Element element) {
expect(element, isNotNull);
bool result = true;
element.visitAncestorElements((Element ancestor) {
if (ancestor.widget is OffStage) {
result = false;
return false;
}
return true;
});
return result;
}
class _IsOnStage extends Matcher {
const _IsOnStage();
bool matches(item, Map matchState) => _isOnStage(item);
Description describe(Description description) => description.add('onstage');
}
class _IsOffStage extends Matcher {
const _IsOffStage();
bool matches(item, Map matchState) => !_isOnStage(item);
Description describe(Description description) => description.add('offstage');
}
const Matcher isOnStage = const _IsOnStage();
const Matcher isOffStage = const _IsOffStage();
void main() {
test('Can pop ephemeral route without black flash', () {
testWidgets((WidgetTester tester) {
GlobalKey containerKey = new GlobalKey();
final Map<String, RouteBuilder> routes = <String, RouteBuilder>{
'/': (_) => new Container(key: containerKey, child: new Text('Home')),
'/settings': (_) => new Container(child: new Text('Settings')),
};
tester.pumpWidget(new MaterialApp(routes: routes));
expect(tester.findText('Home'), isOnStage);
expect(tester.findText('Settings'), isNull);
expect(tester.findText('Overlay'), isNull);
NavigatorState navigator = Navigator.of(containerKey.currentContext);
navigator.pushNamed('/settings');
tester.pump();
expect(tester.findText('Home'), isOnStage);
expect(tester.findText('Settings'), isOffStage);
expect(tester.findText('Overlay'), isNull);
tester.pump(const Duration(milliseconds: 16));
expect(tester.findText('Home'), isOnStage);
expect(tester.findText('Settings'), isOnStage);
expect(tester.findText('Overlay'), isNull);
tester.pump(const Duration(seconds: 1));
expect(tester.findText('Home'), isNull);
expect(tester.findText('Settings'), isOnStage);
expect(tester.findText('Overlay'), isNull);
navigator.push(new TestOverlayRoute());
tester.pump();
expect(tester.findText('Home'), isNull);
expect(tester.findText('Settings'), isOnStage);
expect(tester.findText('Overlay'), isOnStage);
tester.pump(const Duration(seconds: 1));
expect(tester.findText('Home'), isNull);
expect(tester.findText('Settings'), isOnStage);
expect(tester.findText('Overlay'), isOnStage);
navigator.pop();
tester.pump();
expect(tester.findText('Home'), isNull);
expect(tester.findText('Settings'), isOnStage);
expect(tester.findText('Overlay'), isNull);
tester.pump(const Duration(seconds: 1));
expect(tester.findText('Home'), isNull);
expect(tester.findText('Settings'), isOnStage);
expect(tester.findText('Overlay'), isNull);
navigator.pop();
tester.pump();
expect(tester.findText('Home'), isOnStage);
expect(tester.findText('Settings'), isOnStage);
expect(tester.findText('Overlay'), isNull);
tester.pump(const Duration(seconds: 1));
expect(tester.findText('Home'), isOnStage);
expect(tester.findText('Settings'), isNull);
expect(tester.findText('Overlay'), isNull);
});
});
}