From 8815f60a5aa5acbd538f1489c895310524beb2a8 Mon Sep 17 00:00:00 2001 From: Taha Tesser Date: Wed, 19 Oct 2022 20:12:19 +0300 Subject: [PATCH] Add `AnimatedIcons` previews and examples (#113700) --- .../animated_icon/animated_icon.0.dart | 71 ++++++++++++ .../animated_icon/animated_icon.1.dart | 104 ++++++++++++++++++ .../animated_icon/animated_icon.0_test.dart | 31 ++++++ .../animated_icon/animated_icon.1_test.dart | 34 ++++++ .../animated_icons/animated_icons.dart | 25 +++-- .../animated_icons/animated_icons_data.dart | 28 +++++ packages/flutter/lib/src/material/icons.dart | 1 + 7 files changed, 283 insertions(+), 11 deletions(-) create mode 100644 examples/api/lib/material/animated_icon/animated_icon.0.dart create mode 100644 examples/api/lib/material/animated_icon/animated_icon.1.dart create mode 100644 examples/api/test/material/animated_icon/animated_icon.0_test.dart create mode 100644 examples/api/test/material/animated_icon/animated_icon.1_test.dart diff --git a/examples/api/lib/material/animated_icon/animated_icon.0.dart b/examples/api/lib/material/animated_icon/animated_icon.0.dart new file mode 100644 index 0000000000..aa772650fc --- /dev/null +++ b/examples/api/lib/material/animated_icon/animated_icon.0.dart @@ -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. + +/// Flutter code sample for [AnimatedIcon]. + +import 'package:flutter/material.dart'; + +void main() { + runApp(const AnimatedIconApp()); +} + +class AnimatedIconApp extends StatelessWidget { + const AnimatedIconApp({super.key}); + + @override + Widget build(BuildContext context) { + return MaterialApp( + theme: ThemeData( + colorSchemeSeed: const Color(0xff6750a4), + useMaterial3: true, + ), + home: const Scaffold( + body: AnimatedIconExample(), + ), + ); + } +} + +class AnimatedIconExample extends StatefulWidget { + const AnimatedIconExample({super.key}); + + @override + State createState() => _AnimatedIconExampleState(); +} + +class _AnimatedIconExampleState extends State with SingleTickerProviderStateMixin { + late AnimationController controller; + late Animation animation; + + @override + void initState() { + super.initState(); + controller = AnimationController( + vsync: this, + duration: const Duration(seconds: 2), + )..forward() + ..repeat(reverse: true); + animation = Tween(begin: 0.0, end: 1.0).animate(controller); + } + + @override + void dispose() { + controller.dispose(); + super.dispose(); + } + + @override + Widget build(BuildContext context) { + return Scaffold( + body: Center( + child: AnimatedIcon( + icon: AnimatedIcons.menu_arrow, + progress: animation, + size: 72.0, + semanticLabel: 'Show menu', + ), + ), + ); + } +} diff --git a/examples/api/lib/material/animated_icon/animated_icon.1.dart b/examples/api/lib/material/animated_icon/animated_icon.1.dart new file mode 100644 index 0000000000..5613f30920 --- /dev/null +++ b/examples/api/lib/material/animated_icon/animated_icon.1.dart @@ -0,0 +1,104 @@ +// 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 [AnimatedIcon]. + +import 'package:flutter/material.dart'; + +final Map iconsList = { + 'add_event': AnimatedIcons.add_event, + 'arrow_menu': AnimatedIcons.arrow_menu, + 'close_menu': AnimatedIcons.close_menu, + 'ellipsis_search': AnimatedIcons.ellipsis_search, + 'event_add': AnimatedIcons.event_add, + 'home_menu': AnimatedIcons.home_menu, + 'list_view': AnimatedIcons.list_view, + 'menu_arrow': AnimatedIcons.menu_arrow, + 'menu_close': AnimatedIcons.menu_close, + 'menu_home': AnimatedIcons.menu_home, + 'pause_play': AnimatedIcons.pause_play, + 'play_pause': AnimatedIcons.play_pause, + 'search_ellipsis': AnimatedIcons.search_ellipsis, + 'view_list': AnimatedIcons.view_list, +}; + +void main() { + runApp(const AnimatedIconApp()); +} + +class AnimatedIconApp extends StatelessWidget { + const AnimatedIconApp({super.key}); + + @override + Widget build(BuildContext context) { + return MaterialApp( + theme: ThemeData( + colorSchemeSeed: const Color(0xff6750a4), + useMaterial3: true, + ), + home: const Scaffold( + body: AnimatedIconExample(), + ), + ); + } +} + +class AnimatedIconExample extends StatefulWidget { + const AnimatedIconExample({super.key}); + + @override + State createState() => _AnimatedIconExampleState(); +} + +class _AnimatedIconExampleState extends State with SingleTickerProviderStateMixin { + late AnimationController controller; + late Animation animation; + + @override + void initState() { + super.initState(); + controller = AnimationController( + vsync: this, + duration: const Duration(seconds: 2), + )..forward() + ..repeat(reverse: true); + animation = Tween(begin: 0.0, end: 1.0).animate(controller); + } + + @override + void dispose() { + controller.dispose(); + super.dispose(); + } + + @override + Widget build(BuildContext context) { + return Scaffold( + body: GridView( + gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount( + crossAxisCount: 4, + ), + children: iconsList.entries.map((MapEntry entry) { + return Card( + child: Center( + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + AnimatedIcon( + icon: entry.value, + progress: animation, + size: 72.0, + semanticLabel: entry.key, + ), + const SizedBox(height: 8.0), + Text(entry.key), + ], + ), + ), + ); + }).toList(), + ), + ); + } +} diff --git a/examples/api/test/material/animated_icon/animated_icon.0_test.dart b/examples/api/test/material/animated_icon/animated_icon.0_test.dart new file mode 100644 index 0000000000..d0a8a75e54 --- /dev/null +++ b/examples/api/test/material/animated_icon/animated_icon.0_test.dart @@ -0,0 +1,31 @@ +// 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/material/animated_icon/animated_icon.0.dart' + as example; +import 'package:flutter_test/flutter_test.dart'; + +void main() { + testWidgets('AnimatedIcon animates', (WidgetTester tester) async { + await tester.pumpWidget( + const example.AnimatedIconApp(), + ); + + // Test the AnimatedIcon size. + final Size iconSize = tester.getSize(find.byType(AnimatedIcon)); + expect(iconSize.width, 72.0); + expect(iconSize.height, 72.0); + + // Check if AnimatedIcon is animating. + await tester.pump(const Duration(milliseconds: 500)); + AnimatedIcon animatedIcon = tester.widget(find.byType(AnimatedIcon)); + expect(animatedIcon.progress.value, 0.25); + + // Check if animation is completed. + await tester.pump(const Duration(milliseconds: 1500)); + animatedIcon = tester.widget(find.byType(AnimatedIcon)); + expect(animatedIcon.progress.value, 1.0); + }); +} diff --git a/examples/api/test/material/animated_icon/animated_icon.1_test.dart b/examples/api/test/material/animated_icon/animated_icon.1_test.dart new file mode 100644 index 0000000000..dce882dd5a --- /dev/null +++ b/examples/api/test/material/animated_icon/animated_icon.1_test.dart @@ -0,0 +1,34 @@ +// 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/material/animated_icon/animated_icon.1.dart' + as example; +import 'package:flutter_test/flutter_test.dart'; + +void main() { + testWidgets('Show all the animated icons', (WidgetTester tester) async { + await tester.pumpWidget( + const example.AnimatedIconApp(), + ); + + // Check if the total number of AnimatedIcons matches the icons list. + expect(find.byType(AnimatedIcon, skipOffstage: false), findsNWidgets(example.iconsList.length)); + + // Test the AnimatedIcon size. + final Size iconSize = tester.getSize(find.byType(AnimatedIcon).first); + expect(iconSize.width, 72.0); + expect(iconSize.height, 72.0); + + // Check if AnimatedIcon is animating. + await tester.pump(const Duration(milliseconds: 500)); + AnimatedIcon animatedIcon = tester.widget(find.byType(AnimatedIcon).first); + expect(animatedIcon.progress.value, 0.25); + + // Check if animation is completed. + await tester.pump(const Duration(milliseconds: 1500)); + animatedIcon = tester.widget(find.byType(AnimatedIcon).first); + expect(animatedIcon.progress.value, 1.0); + }); +} diff --git a/packages/flutter/lib/src/material/animated_icons/animated_icons.dart b/packages/flutter/lib/src/material/animated_icons/animated_icons.dart index 42765fcc06..8ec51fde77 100644 --- a/packages/flutter/lib/src/material/animated_icons/animated_icons.dart +++ b/packages/flutter/lib/src/material/animated_icons/animated_icons.dart @@ -9,26 +9,29 @@ part of material_animated_icons; // See: https://github.com/flutter/flutter/issues/1831 for details regarding // generic vector graphics support in Flutter. -// Examples can assume: -// late AnimationController controller; - /// Shows an animated icon at a given animation [progress]. /// /// The available icons are specified in [AnimatedIcons]. /// /// {@youtube 560 315 https://www.youtube.com/watch?v=pJcbh8pbvJs} /// -/// {@tool snippet} +/// {@tool dartpad} +/// This example shows how to create an animated icon. The icon is animated +/// forward and reverse in a loop. /// -/// ```dart -/// AnimatedIcon( -/// icon: AnimatedIcons.menu_arrow, -/// progress: controller, -/// semanticLabel: 'Show menu', -/// ) -/// ``` +/// ** See code in examples/api/lib/material/animated_icon/animated_icon.0.dart ** /// {@end-tool} /// +/// {@tool dartpad} +/// This example showcases all the available [AnimatedIcons] in a [GridView]. +/// The icons are animated forward and reverse in a loop. +/// +/// ** See code in examples/api/lib/material/animated_icon/animated_icon.1.dart ** +/// {@end-tool} +/// +/// See also: +/// +/// * [Icons], for the list of available static Material Icons. class AnimatedIcon extends StatelessWidget { /// Creates an AnimatedIcon. /// diff --git a/packages/flutter/lib/src/material/animated_icons/animated_icons_data.dart b/packages/flutter/lib/src/material/animated_icons/animated_icons_data.dart index 7a348a720a..9c4babdf0e 100644 --- a/packages/flutter/lib/src/material/animated_icons/animated_icons_data.dart +++ b/packages/flutter/lib/src/material/animated_icons/animated_icons_data.dart @@ -16,45 +16,73 @@ part of material_animated_icons; abstract class AnimatedIcons { /// The Material Design add to event icon animation. + /// + /// {@animation 72 72 https://flutter.github.io/assets-for-api-docs/assets/widgets/add_event.mp4} static const AnimatedIconData add_event = _$add_event; /// The Material Design arrow to menu icon animation. + /// + /// {@animation 72 72 https://flutter.github.io/assets-for-api-docs/assets/widgets/arrow_menu.mp4} static const AnimatedIconData arrow_menu = _$arrow_menu; /// The Material Design close to menu icon animation. + /// + /// {@animation 72 72 https://flutter.github.io/assets-for-api-docs/assets/widgets/close_menu.mp4} static const AnimatedIconData close_menu = _$close_menu; /// The Material Design ellipsis to search icon animation. + /// + /// {@animation 72 72 https://flutter.github.io/assets-for-api-docs/assets/widgets/ellipsis_search.mp4} static const AnimatedIconData ellipsis_search = _$ellipsis_search; /// The Material Design event to add icon animation. + /// + /// {@animation 72 72 https://flutter.github.io/assets-for-api-docs/assets/widgets/event_add.mp4} static const AnimatedIconData event_add = _$event_add; /// The Material Design home to menu icon animation. + /// + /// {@animation 72 72 https://flutter.github.io/assets-for-api-docs/assets/widgets/home_menu.mp4} static const AnimatedIconData home_menu = _$home_menu; /// The Material Design list to view icon animation. + /// + /// {@animation 72 72 https://flutter.github.io/assets-for-api-docs/assets/widgets/list_view.mp4} static const AnimatedIconData list_view = _$list_view; /// The Material Design menu to arrow icon animation. + /// + /// {@animation 72 72 https://flutter.github.io/assets-for-api-docs/assets/widgets/menu_arrow.mp4} static const AnimatedIconData menu_arrow = _$menu_arrow; /// The Material Design menu to close icon animation. + /// + /// {@animation 72 72 https://flutter.github.io/assets-for-api-docs/assets/widgets/menu_close.mp4} static const AnimatedIconData menu_close = _$menu_close; /// The Material Design menu to home icon animation. + /// + /// {@animation 72 72 https://flutter.github.io/assets-for-api-docs/assets/widgets/menu_home.mp4} static const AnimatedIconData menu_home = _$menu_home; /// The Material Design pause to play icon animation. + /// + /// {@animation 72 72 https://flutter.github.io/assets-for-api-docs/assets/widgets/pause_play.mp4} static const AnimatedIconData pause_play = _$pause_play; /// The Material Design play to pause icon animation. + /// + /// {@animation 72 72 https://flutter.github.io/assets-for-api-docs/assets/widgets/play_pause.mp4} static const AnimatedIconData play_pause = _$play_pause; /// The Material Design search to ellipsis icon animation. + /// + /// {@animation 72 72 https://flutter.github.io/assets-for-api-docs/assets/widgets/search_ellipsis.mp4} static const AnimatedIconData search_ellipsis = _$search_ellipsis; /// The Material Design view to list icon animation. + /// + /// {@animation 72 72 https://flutter.github.io/assets-for-api-docs/assets/widgets/view_list.mp4} static const AnimatedIconData view_list = _$view_list; } diff --git a/packages/flutter/lib/src/material/icons.dart b/packages/flutter/lib/src/material/icons.dart index 754ba917e1..ff8fe5c1ed 100644 --- a/packages/flutter/lib/src/material/icons.dart +++ b/packages/flutter/lib/src/material/icons.dart @@ -148,6 +148,7 @@ class PlatformAdaptiveIcons implements Icons { /// * [Icon] /// * [IconButton] /// * +/// * [AnimatedIcons], for the list of available animated Material Icons. class Icons { // This class is not meant to be instantiated or extended; this constructor // prevents instantiation and extension.