Add HeroController to CupertinoApp (#19326)

This commit is contained in:
xster 2018-07-13 16:46:01 -07:00 committed by GitHub
parent 8359d99e48
commit e32e44799a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 57 additions and 4 deletions

View File

@ -42,6 +42,9 @@ const TextStyle _kDefaultTextStyle = const TextStyle(
/// If [home], [routes], [onGenerateRoute], and [onUnknownRoute] are all null,
/// and [builder] is not null, then no [Navigator] is created.
///
/// This widget also configures the observer of the top-level [Navigator] (if
/// any) to perform [Hero] animations.
///
/// Using this widget with caution on Android since it may produce behaviors
/// Android users are not expecting such as:
///
@ -171,7 +174,7 @@ class CupertinoApp extends StatefulWidget {
/// When a named route is pushed with [Navigator.pushNamed], the route name is
/// looked up in this map. If the name is present, the associated
/// [WidgetBuilder] is used to construct a [CupertinoPageRoute] that performs
/// an appropriate transition to the new route.
/// an appropriate transition, including [Hero] animations, to the new route.
///
/// If the app only has one page, then you can specify it using [home] instead.
///
@ -246,8 +249,8 @@ class CupertinoApp extends StatefulWidget {
///
/// Unless a [Navigator] is provided, either implicitly from [builder] being
/// null, or by a [builder] including its `child` argument, or by a [builder]
/// explicitly providing a [Navigator] of its own, APIs such as
/// [Navigator.push] and [Navigator.pop], will not function.
/// explicitly providing a [Navigator] of its own, widgets and APIs such as
/// [Hero], [Navigator.push] and [Navigator.pop], will not function.
final TransitionBuilder builder;
/// {@macro flutter.widgets.widgetsApp.title}
@ -317,9 +320,13 @@ class _AlwaysCupertinoScrollBehavior extends ScrollBehavior {
}
class _CupertinoAppState extends State<CupertinoApp> {
HeroController _heroController;
List<NavigatorObserver> _navigatorObservers;
@override
void initState() {
super.initState();
_heroController = new HeroController(); // Linear tweening.
_updateNavigator();
}
@ -335,6 +342,9 @@ class _CupertinoAppState extends State<CupertinoApp> {
widget.routes.isNotEmpty ||
widget.onGenerateRoute != null ||
widget.onUnknownRoute != null;
_navigatorObservers =
new List<NavigatorObserver>.from(widget.navigatorObservers)
..add(_heroController);
}
Widget defaultBuilder(BuildContext context, Widget child) {
@ -351,7 +361,7 @@ class _CupertinoAppState extends State<CupertinoApp> {
routes: widget.routes,
onGenerateRoute: widget.onGenerateRoute,
onUnknownRoute: widget.onUnknownRoute,
navigatorObservers: widget.navigatorObservers,
navigatorObservers: _navigatorObservers,
);
if (widget.builder != null) {
return widget.builder(context, navigator);

View File

@ -0,0 +1,43 @@
// Copyright 2018 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 'package:flutter_test/flutter_test.dart';
import 'package:flutter/cupertino.dart';
void main() {
testWidgets('Heroes work', (WidgetTester tester) async {
await tester.pumpWidget(new CupertinoApp(
home:
new ListView(
children: <Widget>[
const Hero(tag: 'a', child: const Text('foo')),
new Builder(builder: (BuildContext context) {
return new CupertinoButton(
child: const Text('next'),
onPressed: () {
Navigator.push(
context,
new CupertinoPageRoute<void>(
builder: (BuildContext context) {
return const Hero(tag: 'a', child: const Text('foo'));
}
),
);
},
);
}),
],
)
));
await tester.tap(find.text('next'));
await tester.pump();
await tester.pump(const Duration(milliseconds: 100));
// During the hero transition, the hero widget is lifted off of both
// page routes and exists as its own overlay on top of both routes.
expect(find.widgetWithText(CupertinoPageRoute, 'foo'), findsNothing);
expect(find.widgetWithText(Navigator, 'foo'), findsOneWidget);
});
}