Handle back swipe completed->completed or completed->dismissed transitions (#27866)

This commit is contained in:
xster 2019-02-12 18:50:06 -08:00 committed by GitHub
parent 7cc694e5d5
commit 8d0346a0ec
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
4 changed files with 150 additions and 9 deletions

View file

@ -634,18 +634,22 @@ class _CupertinoBackGestureController<T> {
controller.animateBack(0.0, duration: Duration(milliseconds: droppedPageBackAnimationTime), curve: animationCurve);
}
assert(controller.isAnimating);
assert(controller.status != AnimationStatus.completed);
assert(controller.status != AnimationStatus.dismissed);
if (controller.isAnimating) {
// Don't end the gesture until the transition completes.
_animating = true;
controller.addStatusListener(_handleStatusChanged);
} else {
// Animate calls could return inline if already at the target destination
// value.
return _handleStatusChanged(controller.status);
}
// Don't end the gesture until the transition completes.
_animating = true;
controller.addStatusListener(_handleStatusChanged);
}
void _handleStatusChanged(AnimationStatus status) {
assert(_animating);
controller.removeStatusListener(_handleStatusChanged);
if (_animating) {
controller.removeStatusListener(_handleStatusChanged);
}
_animating = false;
if (status == AnimationStatus.dismissed)
navigator.pop<T>(); // this will cause the route to get disposed, which will dispose us

View file

@ -155,7 +155,6 @@ abstract class TransitionRoute<T> extends OverlayRoute<T> {
overlayEntries.first.opaque = false;
break;
case AnimationStatus.dismissed:
assert(!overlayEntries.first.opaque);
// We might still be the current route if a subclass is controlling the
// the transition and hits the dismissed status. For example, the iOS
// back gesture drives this animation to the dismissed status before

View file

@ -427,6 +427,74 @@ void main() {
expect(find.text('Page 1'), isOnstage);
expect(find.text('Page 2'), isOnstage);
});
testWidgets('test edge swipe then drop back at starting point works', (WidgetTester tester) async {
await tester.pumpWidget(
CupertinoApp(
onGenerateRoute: (RouteSettings settings) {
return CupertinoPageRoute<void>(
settings: settings,
builder: (BuildContext context) {
final String pageNumber = settings.name == '/' ? '1' : '2';
return Center(child: Text('Page $pageNumber'));
}
);
},
),
);
tester.state<NavigatorState>(find.byType(Navigator)).pushNamed('/next');
await tester.pump();
await tester.pump(const Duration(seconds: 1));
expect(find.text('Page 1'), findsNothing);
expect(find.text('Page 2'), isOnstage);
final TestGesture gesture = await tester.startGesture(const Offset(5, 200));
await gesture.moveBy(const Offset(300, 0));
await tester.pump();
// Bring it exactly back such that there's nothing to animate when releasing.
await gesture.moveBy(const Offset(-300, 0));
await gesture.up();
await tester.pump();
expect(find.text('Page 1'), findsNothing);
expect(find.text('Page 2'), isOnstage);
});
testWidgets('test edge swipe then drop back at ending point works', (WidgetTester tester) async {
await tester.pumpWidget(
CupertinoApp(
onGenerateRoute: (RouteSettings settings) {
return CupertinoPageRoute<void>(
settings: settings,
builder: (BuildContext context) {
final String pageNumber = settings.name == '/' ? '1' : '2';
return Center(child: Text('Page $pageNumber'));
}
);
},
),
);
tester.state<NavigatorState>(find.byType(Navigator)).pushNamed('/next');
await tester.pump();
await tester.pump(const Duration(seconds: 1));
expect(find.text('Page 1'), findsNothing);
expect(find.text('Page 2'), isOnstage);
final TestGesture gesture = await tester.startGesture(const Offset(5, 200));
// The width of the page.
await gesture.moveBy(const Offset(800, 0));
await gesture.up();
await tester.pump();
expect(find.text('Page 1'), isOnstage);
expect(find.text('Page 2'), findsNothing);
});
}
class RtlOverrideWidgetsDelegate extends LocalizationsDelegate<WidgetsLocalizations> {

View file

@ -470,4 +470,74 @@ void main() {
// An exception should've been thrown because the `builder` returned null.
expect(tester.takeException(), isInstanceOf<FlutterError>());
});
testWidgets('test iOS edge swipe then drop back at starting point works', (WidgetTester tester) async {
await tester.pumpWidget(
MaterialApp(
theme: ThemeData(platform: TargetPlatform.iOS),
onGenerateRoute: (RouteSettings settings) {
return MaterialPageRoute<void>(
settings: settings,
builder: (BuildContext context) {
final String pageNumber = settings.name == '/' ? '1' : '2';
return Center(child: Text('Page $pageNumber'));
}
);
},
),
);
tester.state<NavigatorState>(find.byType(Navigator)).pushNamed('/next');
await tester.pump();
await tester.pump(const Duration(seconds: 1));
expect(find.text('Page 1'), findsNothing);
expect(find.text('Page 2'), isOnstage);
final TestGesture gesture = await tester.startGesture(const Offset(5, 200));
await gesture.moveBy(const Offset(300, 0));
await tester.pump();
// Bring it exactly back such that there's nothing to animate when releasing.
await gesture.moveBy(const Offset(-300, 0));
await gesture.up();
await tester.pump();
expect(find.text('Page 1'), findsNothing);
expect(find.text('Page 2'), isOnstage);
});
testWidgets('test iOS edge swipe then drop back at ending point works', (WidgetTester tester) async {
await tester.pumpWidget(
MaterialApp(
theme: ThemeData(platform: TargetPlatform.iOS),
onGenerateRoute: (RouteSettings settings) {
return MaterialPageRoute<void>(
settings: settings,
builder: (BuildContext context) {
final String pageNumber = settings.name == '/' ? '1' : '2';
return Center(child: Text('Page $pageNumber'));
}
);
},
),
);
tester.state<NavigatorState>(find.byType(Navigator)).pushNamed('/next');
await tester.pump();
await tester.pump(const Duration(seconds: 1));
expect(find.text('Page 1'), findsNothing);
expect(find.text('Page 2'), isOnstage);
final TestGesture gesture = await tester.startGesture(const Offset(5, 200));
// The width of the page.
await gesture.moveBy(const Offset(800, 0));
await gesture.up();
await tester.pump();
expect(find.text('Page 1'), isOnstage);
expect(find.text('Page 2'), findsNothing);
});
}