Unverified Commit 05a80eb8 authored by LongCatIsLooong's avatar LongCatIsLooong Committed by GitHub

Handle infinite/NaN rects in Hero flights. Less exclamation marks. (#72946)

parent 373ec58d
......@@ -2780,4 +2780,212 @@ Future<void> main() async {
expect(find.byKey(secondKey), isInCard);
expect(find.byKey(secondKey), isOnstage);
});
testWidgets('kept alive Hero does not throw when the transition begins', (WidgetTester tester) async {
final GlobalKey<NavigatorState> navigatorKey = GlobalKey<NavigatorState>();
await tester.pumpWidget(
MaterialApp(
navigatorKey: navigatorKey,
home: Scaffold(
body: ListView(
addAutomaticKeepAlives: false,
addRepaintBoundaries: false,
addSemanticIndexes: false,
children: <Widget>[
const KeepAlive(
keepAlive: true,
child: Hero(
tag: 'a',
child: Placeholder(),
),
),
Container(height: 1000.0),
],
),
),
),
);
// Scroll to make the Hero invisible.
await tester.drag(find.byType(ListView), const Offset(0.0, -1000.0));
await tester.pump();
expect(find.byType(TextField), findsNothing);
navigatorKey.currentState?.push(
MaterialPageRoute<void>(
builder: (BuildContext context) {
return const Scaffold(
body: Center(
child: Hero(
tag: 'a',
child: Placeholder(),
),
),
);
},
),
);
await tester.pumpAndSettle();
expect(tester.takeException(), isNull);
// The Hero on the new route should be visible .
expect(find.byType(Placeholder), findsOneWidget);
});
testWidgets('toHero becomes unpaintable after the transition begins', (WidgetTester tester) async {
final GlobalKey<NavigatorState> navigatorKey = GlobalKey<NavigatorState>();
final ScrollController controller = ScrollController();
RenderOpacity? findRenderOpacity() {
AbstractNode? parent = tester.renderObject(find.byType(Placeholder));
while (parent is RenderObject && parent is! RenderOpacity) {
parent = parent.parent;
}
return parent is RenderOpacity ? parent : null;
}
await tester.pumpWidget(
MaterialApp(
navigatorKey: navigatorKey,
home: Scaffold(
body: ListView(
controller: controller,
addAutomaticKeepAlives: false,
addRepaintBoundaries: false,
addSemanticIndexes: false,
children: <Widget>[
const KeepAlive(
keepAlive: true,
child: Hero(
tag: 'a',
child: Placeholder(),
),
),
Container(height: 1000.0),
],
),
),
),
);
navigatorKey.currentState?.push(
MaterialPageRoute<void>(
builder: (BuildContext context) {
return const Scaffold(
body: Center(
child: Hero(
tag: 'a',
child: Placeholder(),
),
),
);
},
),
);
await tester.pump();
await tester.pumpAndSettle();
// Pop the new route, and before the animation finishes we scroll the toHero
// to make it unpaintable.
navigatorKey.currentState?.pop();
await tester.pump();
controller.jumpTo(1000);
// Starts Hero animation and scroll animation almost simutaneously.
// Scroll to make the Hero invisible.
await tester.pump();
expect(findRenderOpacity()?.opacity, anyOf(isNull, 1.0));
// In this frame the Hero animation finds out the toHero is not paintable,
// and starts fading.
await tester.pump();
await tester.pump(const Duration(milliseconds: 100));
expect(findRenderOpacity()?.opacity, lessThan(1.0));
await tester.pumpAndSettle();
// The Hero on the new route should be invisible.
expect(find.byType(Placeholder), findsNothing);
});
testWidgets('diverting to a keepalive but unpaintable hero', (WidgetTester tester) async {
final GlobalKey<NavigatorState> navigatorKey = GlobalKey<NavigatorState>();
await tester.pumpWidget(
CupertinoApp(
navigatorKey: navigatorKey,
home: CupertinoPageScaffold(
child: ListView(
addAutomaticKeepAlives: false,
addRepaintBoundaries: false,
addSemanticIndexes: false,
children: <Widget>[
const KeepAlive(
keepAlive: true,
child: Hero(
tag: 'a',
child: Placeholder(),
),
),
Container(height: 1000.0),
],
),
),
),
);
// Scroll to make the Hero invisible.
await tester.drag(find.byType(ListView), const Offset(0.0, -1000.0));
await tester.pump();
expect(find.byType(Placeholder), findsNothing);
expect(find.byType(Placeholder, skipOffstage: false), findsOneWidget);
navigatorKey.currentState?.push(
MaterialPageRoute<void>(
builder: (BuildContext context) {
return const Scaffold(
body: Center(
child: Hero(
tag: 'a',
child: Placeholder(),
),
),
);
},
),
);
await tester.pumpAndSettle();
// Yet another route that contains Hero 'a'.
navigatorKey.currentState?.push(
MaterialPageRoute<void>(
builder: (BuildContext context) {
return const Scaffold(
body: Center(
child: Hero(
tag: 'a',
child: Placeholder(),
),
),
);
},
),
);
await tester.pumpAndSettle();
// Pop both routes.
navigatorKey.currentState?.pop();
await tester.pump();
await tester.pump(const Duration(milliseconds: 10));
navigatorKey.currentState?.pop();
await tester.pump();
await tester.pump(const Duration(milliseconds: 10));
expect(find.byType(Placeholder), findsOneWidget);
await tester.pumpAndSettle();
expect(tester.takeException(), isNull);
});
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment