mirror of
https://github.com/flutter/flutter
synced 2024-08-27 03:50:33 +00:00
Hero
: Add an example for createRectTween
(#102650)
This commit is contained in:
parent
709b26d0b3
commit
eef4aa7caa
|
@ -6,29 +6,26 @@
|
|||
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
void main() => runApp(const MyApp());
|
||||
void main() => runApp(const HeroApp());
|
||||
|
||||
class MyApp extends StatelessWidget {
|
||||
const MyApp({Key? key}) : super(key: key);
|
||||
|
||||
static const String _title = 'Flutter Code Sample';
|
||||
class HeroApp extends StatelessWidget {
|
||||
const HeroApp({Key? key}) : super(key: key);
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return MaterialApp(
|
||||
title: _title,
|
||||
home: Scaffold(
|
||||
appBar: AppBar(title: const Text(_title)),
|
||||
appBar: AppBar(title: const Text('Hero Sample')),
|
||||
body: const Center(
|
||||
child: MyStatelessWidget(),
|
||||
child: HeroExample(),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class MyStatelessWidget extends StatelessWidget {
|
||||
const MyStatelessWidget({Key? key}) : super(key: key);
|
||||
class HeroExample extends StatelessWidget {
|
||||
const HeroExample({Key? key}) : super(key: key);
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
|
@ -41,17 +38,18 @@ class MyStatelessWidget extends StatelessWidget {
|
|||
ListTile(
|
||||
leading: Hero(
|
||||
tag: 'hero-rectangle',
|
||||
child: _blueRectangle(const Size(50, 50)),
|
||||
child: _box(const Size(50, 50)),
|
||||
),
|
||||
onTap: () => _gotoDetailsPage(context),
|
||||
title:
|
||||
const Text('Tap on the icon to view hero animation transition.'),
|
||||
title: const Text(
|
||||
'Tap on the icon to view hero animation transition.',
|
||||
),
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
Widget _blueRectangle(Size size) {
|
||||
Widget _box(Size size) {
|
||||
return Container(
|
||||
width: size.width,
|
||||
height: size.height,
|
||||
|
@ -63,7 +61,7 @@ class MyStatelessWidget extends StatelessWidget {
|
|||
Navigator.of(context).push(MaterialPageRoute<void>(
|
||||
builder: (BuildContext context) => Scaffold(
|
||||
appBar: AppBar(
|
||||
title: const Text('second Page'),
|
||||
title: const Text('Second Page'),
|
||||
),
|
||||
body: Center(
|
||||
child: Column(
|
||||
|
@ -71,7 +69,7 @@ class MyStatelessWidget extends StatelessWidget {
|
|||
children: <Widget>[
|
||||
Hero(
|
||||
tag: 'hero-rectangle',
|
||||
child: _blueRectangle(const Size(200, 200)),
|
||||
child: _box(const Size(200, 200)),
|
||||
),
|
||||
],
|
||||
),
|
||||
|
|
110
examples/api/lib/widgets/heroes/hero.1.dart
Normal file
110
examples/api/lib/widgets/heroes/hero.1.dart
Normal file
|
@ -0,0 +1,110 @@
|
|||
// 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),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
));
|
||||
}
|
||||
}
|
71
examples/api/test/widgets/heroes/hero.0_test.dart
Normal file
71
examples/api/test/widgets/heroes/hero.0_test.dart
Normal file
|
@ -0,0 +1,71 @@
|
|||
// 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));
|
||||
});
|
||||
}
|
135
examples/api/test/widgets/heroes/hero.1_test.dart
Normal file
135
examples/api/test/widgets/heroes/hero.1_test.dart
Normal file
|
@ -0,0 +1,135 @@
|
|||
// 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 {
|
|||
pop,
|
||||
}
|
||||
|
||||
|
||||
/// A widget that marks its child as being a candidate for
|
||||
/// [hero animations](https://flutter.dev/docs/development/ui/animations/hero-animations).
|
||||
///
|
||||
|
@ -116,6 +115,13 @@ enum HeroFlightDirection {
|
|||
/// ** See code in examples/api/lib/widgets/heroes/hero.0.dart **
|
||||
/// {@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
|
||||
///
|
||||
/// Heroes and the [Navigator]'s [Overlay] [Stack] must be axis-aligned for
|
||||
|
|
|
@ -2649,7 +2649,6 @@ Future<void> main() async {
|
|||
end: const Size(100, 100),
|
||||
).chain(CurveTween(curve: Curves.fastOutSlowIn));
|
||||
|
||||
|
||||
await tester.pumpWidget(
|
||||
MaterialApp(
|
||||
navigatorKey: navigator,
|
||||
|
|
Loading…
Reference in a new issue