Unverified Commit eef4aa7c authored by Taha Tesser's avatar Taha Tesser Committed by GitHub

`Hero`: Add an example for `createRectTween` (#102650)

parent 709b26d0
...@@ -6,29 +6,26 @@ ...@@ -6,29 +6,26 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
void main() => runApp(const MyApp()); void main() => runApp(const HeroApp());
class MyApp extends StatelessWidget { class HeroApp extends StatelessWidget {
const MyApp({Key? key}) : super(key: key); const HeroApp({Key? key}) : super(key: key);
static const String _title = 'Flutter Code Sample';
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return MaterialApp( return MaterialApp(
title: _title,
home: Scaffold( home: Scaffold(
appBar: AppBar(title: const Text(_title)), appBar: AppBar(title: const Text('Hero Sample')),
body: const Center( body: const Center(
child: MyStatelessWidget(), child: HeroExample(),
), ),
), ),
); );
} }
} }
class MyStatelessWidget extends StatelessWidget { class HeroExample extends StatelessWidget {
const MyStatelessWidget({Key? key}) : super(key: key); const HeroExample({Key? key}) : super(key: key);
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
...@@ -41,17 +38,18 @@ class MyStatelessWidget extends StatelessWidget { ...@@ -41,17 +38,18 @@ class MyStatelessWidget extends StatelessWidget {
ListTile( ListTile(
leading: Hero( leading: Hero(
tag: 'hero-rectangle', tag: 'hero-rectangle',
child: _blueRectangle(const Size(50, 50)), child: _box(const Size(50, 50)),
), ),
onTap: () => _gotoDetailsPage(context), onTap: () => _gotoDetailsPage(context),
title: title: const Text(
const Text('Tap on the icon to view hero animation transition.'), 'Tap on the icon to view hero animation transition.',
),
), ),
], ],
); );
} }
Widget _blueRectangle(Size size) { Widget _box(Size size) {
return Container( return Container(
width: size.width, width: size.width,
height: size.height, height: size.height,
...@@ -63,7 +61,7 @@ class MyStatelessWidget extends StatelessWidget { ...@@ -63,7 +61,7 @@ class MyStatelessWidget extends StatelessWidget {
Navigator.of(context).push(MaterialPageRoute<void>( Navigator.of(context).push(MaterialPageRoute<void>(
builder: (BuildContext context) => Scaffold( builder: (BuildContext context) => Scaffold(
appBar: AppBar( appBar: AppBar(
title: const Text('second Page'), title: const Text('Second Page'),
), ),
body: Center( body: Center(
child: Column( child: Column(
...@@ -71,7 +69,7 @@ class MyStatelessWidget extends StatelessWidget { ...@@ -71,7 +69,7 @@ class MyStatelessWidget extends StatelessWidget {
children: <Widget>[ children: <Widget>[
Hero( Hero(
tag: 'hero-rectangle', tag: 'hero-rectangle',
child: _blueRectangle(const Size(200, 200)), child: _box(const Size(200, 200)),
), ),
], ],
), ),
......
// Copyright 2014 The Flutter Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
// Flutter code sample for Hero
import 'package:flutter/material.dart';
import 'package:flutter/scheduler.dart';
void main() {
// Slow down time to see Hero flight animation.
timeDilation = 15.0;
runApp(const HeroApp());
}
class HeroApp extends StatelessWidget {
const HeroApp({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
appBar: AppBar(title: const Text('Hero Sample')),
body: const Center(
child: HeroExample(),
),
),
);
}
}
class HeroExample extends StatelessWidget {
const HeroExample({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
return Column(
children: <Widget>[
ListTile(
leading: Hero(
tag: 'hero-default-tween',
child: _box(size: 50.0, color: Colors.red[700]!.withOpacity(0.5)),
),
title: const Text(
'This red icon will use a default rect tween during the hero flight.',
),
),
const SizedBox(height: 10.0),
ListTile(
leading: Hero(
tag: 'hero-custom-tween',
createRectTween: (Rect? begin, Rect? end) {
return MaterialRectCenterArcTween(begin: begin, end: end);
},
child: _box(size: 50.0, color: Colors.blue[700]!.withOpacity(0.5)),
),
title: const Text(
'This blue icon will use a custom rect tween during the hero flight.',
),
),
const SizedBox(height: 10),
ElevatedButton(
onPressed: () => _gotoDetailsPage(context),
child: const Text('Tap to trigger hero flight'),
),
],
);
}
Widget _box({double? size, Color? color}) {
return Container(
color: color,
child: FlutterLogo(size: size),
);
}
void _gotoDetailsPage(BuildContext context) {
Navigator.of(context).push(MaterialPageRoute<void>(
builder: (BuildContext context) => Scaffold(
appBar: AppBar(
title: const Text('Second Page'),
),
body: Align(
alignment: Alignment.bottomRight,
child: Stack(
children: <Widget>[
Hero(
tag: 'hero-custom-tween',
createRectTween: (Rect? begin, Rect? end) {
return MaterialRectCenterArcTween(begin: begin, end: end);
},
child: _box(
size: 400.0,
color: Colors.blue[700]!.withOpacity(0.5),
),
),
Hero(
tag: 'hero-default-tween',
child: _box(
size: 400.0,
color: Colors.red[700]!.withOpacity(0.5),
),
),
],
),
),
),
));
}
}
// Copyright 2014 The Flutter 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/material.dart';
import 'package:flutter_api_samples/widgets/heroes/hero.0.dart' as example;
import 'package:flutter_test/flutter_test.dart';
void main() {
testWidgets('Has Hero animation', (WidgetTester tester) async {
await tester.pumpWidget(
const example.HeroApp(),
);
expect(find.text('Hero Sample'), findsOneWidget);
await tester.tap(find.byType(Container));
await tester.pump();
Size heroSize = tester.getSize(find.byType(Container));
// Jump 25% into the transition (total length = 300ms)
await tester.pump(const Duration(milliseconds: 75)); // 25% of 300ms
heroSize = tester.getSize(find.byType(Container));
expect(heroSize.width.roundToDouble(), 103.0);
expect(heroSize.height.roundToDouble(), 60.0);
// Jump to 50% into the transition.
await tester.pump(const Duration(milliseconds: 75)); // 25% of 300ms
heroSize = tester.getSize(find.byType(Container));
expect(heroSize.width.roundToDouble(), 189.0);
expect(heroSize.height.roundToDouble(), 146.0);
// Jump to 75% into the transition.
await tester.pump(const Duration(milliseconds: 75)); // 25% of 300ms
heroSize = tester.getSize(find.byType(Container));
expect(heroSize.width.roundToDouble(), 199.0);
expect(heroSize.height.roundToDouble(), 190.0);
// Jump to 100% into the transition.
await tester.pump(const Duration(milliseconds: 75)); // 25% of 300ms
heroSize = tester.getSize(find.byType(Container));
expect(heroSize, const Size(200.0, 200.0));
expect(find.byIcon(Icons.arrow_back), findsOneWidget);
await tester.tap(find.byIcon(Icons.arrow_back));
await tester.pump();
// Jump 25% into the transition (total length = 300ms)
await tester.pump(const Duration(milliseconds: 75)); // 25% of 300ms
heroSize = tester.getSize(find.byType(Container));
expect(heroSize.width.roundToDouble(), 199.0);
expect(heroSize.height.roundToDouble(), 190.0);
// Jump to 50% into the transition.
await tester.pump(const Duration(milliseconds: 75)); // 25% of 300ms
heroSize = tester.getSize(find.byType(Container));
expect(heroSize.width.roundToDouble(), 189.0);
expect(heroSize.height.roundToDouble(), 146.0);
// Jump to 75% into the transition.
await tester.pump(const Duration(milliseconds: 75)); // 25% of 300ms
heroSize = tester.getSize(find.byType(Container));
expect(heroSize.width.roundToDouble(), 103.0);
expect(heroSize.height.roundToDouble(), 60.0);
// Jump to 100% into the transition.
await tester.pump(const Duration(milliseconds: 75)); // 25% of 300ms
heroSize = tester.getSize(find.byType(Container));
expect(heroSize, const Size(50.0, 50.0));
});
}
// Copyright 2014 The Flutter 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/material.dart';
import 'package:flutter_api_samples/widgets/heroes/hero.1.dart' as example;
import 'package:flutter_test/flutter_test.dart';
void main() {
testWidgets('Hero flight animation with default rect tween', (WidgetTester tester) async {
await tester.pumpWidget(
const example.HeroApp(),
);
expect(find.text('Hero Sample'), findsOneWidget);
await tester.tap(find.byType(ElevatedButton));
await tester.pump();
Size heroSize = tester.getSize(find.byType(Container).first);
expect(heroSize, const Size(50.0, 50.0));
// Jump 25% into the transition (total length = 300ms)
await tester.pump(const Duration(milliseconds: 75)); // 25% of 300ms
heroSize = tester.getSize(find.byType(Container).first);
expect(heroSize.width.roundToDouble(), 171.0);
expect(heroSize.height.roundToDouble(), 73.0);
// Jump to 50% into the transition.
await tester.pump(const Duration(milliseconds: 75)); // 25% of 300ms
heroSize = tester.getSize(find.byType(Container).first);
expect(heroSize.width.roundToDouble(), 371.0);
expect(heroSize.height.roundToDouble(), 273.0);
// Jump to 75% into the transition.
await tester.pump(const Duration(milliseconds: 75)); // 25% of 300ms
heroSize = tester.getSize(find.byType(Container).first);
expect(heroSize.width.roundToDouble(), 398.0);
expect(heroSize.height.roundToDouble(), 376.0);
// Jump to 100% into the transition.
await tester.pump(const Duration(milliseconds: 75)); // 25% of 300ms
heroSize = tester.getSize(find.byType(Container).first);
expect(heroSize, const Size(400.0, 400.0));
expect(find.byIcon(Icons.arrow_back), findsOneWidget);
await tester.tap(find.byIcon(Icons.arrow_back));
await tester.pump();
// Jump 25% into the transition (total length = 300ms)
await tester.pump(const Duration(milliseconds: 75)); // 25% of 300ms
heroSize = tester.getSize(find.byType(Container).first);
expect(heroSize.width.roundToDouble(), 398.0);
expect(heroSize.height.roundToDouble(), 376.0);
// Jump to 50% into the transition.
await tester.pump(const Duration(milliseconds: 75)); // 25% of 300ms
heroSize = tester.getSize(find.byType(Container).first);
expect(heroSize.width.roundToDouble(), 371.0);
expect(heroSize.height.roundToDouble(), 273.0);
// Jump to 75% into the transition.
await tester.pump(const Duration(milliseconds: 75)); // 25% of 300ms
heroSize = tester.getSize(find.byType(Container).first);
expect(heroSize.width.roundToDouble(), 171.0);
expect(heroSize.height.roundToDouble(), 73.0);
// Jump to 100% into the transition.
await tester.pump(const Duration(milliseconds: 75)); // 25% of 300ms
heroSize = tester.getSize(find.byType(Container).first);
expect(heroSize, const Size(50.0, 50.0));
});
testWidgets('Hero flight animation with custom rect tween', (WidgetTester tester) async {
await tester.pumpWidget(
const example.HeroApp(),
);
expect(find.text('Hero Sample'), findsOneWidget);
await tester.tap(find.byType(ElevatedButton));
await tester.pump();
Size heroSize = tester.getSize(find.byType(Container).last);
expect(heroSize, const Size(50.0, 50.0));
// Jump 25% into the transition (total length = 300ms)
await tester.pump(const Duration(milliseconds: 75)); // 25% of 300ms
heroSize = tester.getSize(find.byType(Container).last);
expect(heroSize.width.roundToDouble(), 133.0);
expect(heroSize.height.roundToDouble(), 133.0);
// Jump to 50% into the transition.
await tester.pump(const Duration(milliseconds: 75)); // 25% of 300ms
heroSize = tester.getSize(find.byType(Container).last);
expect(heroSize.width.roundToDouble(), 321.0);
expect(heroSize.height.roundToDouble(), 321.0);
// Jump to 75% into the transition.
await tester.pump(const Duration(milliseconds: 75)); // 25% of 300ms
heroSize = tester.getSize(find.byType(Container).first);
expect(heroSize.width.roundToDouble(), 398.0);
expect(heroSize.height.roundToDouble(), 376.0);
// Jump to 100% into the transition.
await tester.pump(const Duration(milliseconds: 75)); // 25% of 300ms
heroSize = tester.getSize(find.byType(Container).last);
expect(heroSize, const Size(400.0, 400.0));
expect(find.byIcon(Icons.arrow_back), findsOneWidget);
await tester.tap(find.byIcon(Icons.arrow_back));
await tester.pump();
// Jump 25% into the transition (total length = 300ms)
await tester.pump(const Duration(milliseconds: 75)); // 25% of 300ms
heroSize = tester.getSize(find.byType(Container).last);
expect(heroSize.width.roundToDouble(), 386.0);
expect(heroSize.height.roundToDouble(), 386.0);
// Jump to 50% into the transition.
await tester.pump(const Duration(milliseconds: 75)); // 25% of 300ms
heroSize = tester.getSize(find.byType(Container).last);
expect(heroSize.width.roundToDouble(), 321.0);
expect(heroSize.height.roundToDouble(), 321.0);
// Jump to 75% into the transition.
await tester.pump(const Duration(milliseconds: 75)); // 25% of 300ms
heroSize = tester.getSize(find.byType(Container).last);
expect(heroSize.width.roundToDouble(), 133.0);
expect(heroSize.height.roundToDouble(), 133.0);
// Jump to 100% into the transition.
await tester.pump(const Duration(milliseconds: 75)); // 25% of 300ms
heroSize = tester.getSize(find.byType(Container).last);
expect(heroSize, const Size(50.0, 50.0));
});
}
...@@ -71,7 +71,6 @@ enum HeroFlightDirection { ...@@ -71,7 +71,6 @@ enum HeroFlightDirection {
pop, pop,
} }
/// A widget that marks its child as being a candidate for /// A widget that marks its child as being a candidate for
/// [hero animations](https://flutter.dev/docs/development/ui/animations/hero-animations). /// [hero animations](https://flutter.dev/docs/development/ui/animations/hero-animations).
/// ///
...@@ -116,6 +115,13 @@ enum HeroFlightDirection { ...@@ -116,6 +115,13 @@ enum HeroFlightDirection {
/// ** See code in examples/api/lib/widgets/heroes/hero.0.dart ** /// ** See code in examples/api/lib/widgets/heroes/hero.0.dart **
/// {@end-tool} /// {@end-tool}
/// ///
/// {@tool dartpad}
/// This sample shows [Hero] flight animations using default tween
/// and custom rect tween.
///
/// ** See code in examples/api/lib/widgets/heroes/hero.1.dart **
/// {@end-tool}
///
/// ## Discussion /// ## Discussion
/// ///
/// Heroes and the [Navigator]'s [Overlay] [Stack] must be axis-aligned for /// Heroes and the [Navigator]'s [Overlay] [Stack] must be axis-aligned for
......
...@@ -2649,7 +2649,6 @@ Future<void> main() async { ...@@ -2649,7 +2649,6 @@ Future<void> main() async {
end: const Size(100, 100), end: const Size(100, 100),
).chain(CurveTween(curve: Curves.fastOutSlowIn)); ).chain(CurveTween(curve: Curves.fastOutSlowIn));
await tester.pumpWidget( await tester.pumpWidget(
MaterialApp( MaterialApp(
navigatorKey: navigator, navigatorKey: navigator,
......
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