diff --git a/examples/api/lib/material/text_button/text_button.0.dart b/examples/api/lib/material/text_button/text_button.0.dart index 0f7f0209289..18ad6ecd68b 100644 --- a/examples/api/lib/material/text_button/text_button.0.dart +++ b/examples/api/lib/material/text_button/text_button.0.dart @@ -55,10 +55,27 @@ class _TextButtonExampleState extends State { TextDirection textDirection = TextDirection.ltr; ThemeMode themeMode = ThemeMode.light; late final ScrollController scrollController; + bool isRunning = false; static const Widget verticalSpacer = SizedBox(height: 16); static const Widget horizontalSpacer = SizedBox(width: 32); + static const ImageProvider grassImage = NetworkImage( + 'https://flutter.github.io/assets-for-api-docs/assets/material/text_button_grass.jpeg', + ); + static const ImageProvider defaultImage = NetworkImage( + 'https://flutter.github.io/assets-for-api-docs/assets/material/text_button_nhu_default.png', + ); + static const ImageProvider hoveredImage = NetworkImage( + 'https://flutter.github.io/assets-for-api-docs/assets/material/text_button_nhu_hovered.png', + ); + static const ImageProvider pressedImage = NetworkImage( + 'https://flutter.github.io/assets-for-api-docs/assets/material/text_button_nhu_pressed.png', + ); + static const ImageProvider runningImage = NetworkImage( + 'https://flutter.github.io/assets-for-api-docs/assets/material/text_button_nhu_end.png', + ); + @override void initState() { scrollController = ScrollController(); @@ -302,7 +319,7 @@ class _TextButtonExampleState extends State { return Ink( decoration: const BoxDecoration( image: DecorationImage( - image: NetworkImage(grassUrl), + image: grassImage, fit: BoxFit.cover, ), ), @@ -315,7 +332,8 @@ class _TextButtonExampleState extends State { verticalSpacer, // Override the foregroundBuilder to specify images for the button's pressed - // hovered and inactive states. + // hovered and default states. We switch to an additional image while the + // button's callback is "running". // // This is an example of completely changing the default appearance of a button // by specifying images for each state and by turning off the overlays by @@ -326,13 +344,25 @@ class _TextButtonExampleState extends State { // TextButton's child parameter is required, so we still have // to provide one. TextButton( - onPressed: () {}, + onPressed: () async { + setState(() { isRunning = true; }); + Future.delayed(const Duration(seconds: 1), () { + // Simulate a time consuming action. + setState(() { isRunning = false; }); + }); + }, style: TextButton.styleFrom( overlayColor: Colors.transparent, foregroundBuilder: (BuildContext context, Set states, Widget? child) { - String url = states.contains(MaterialState.hovered) ? smiley3Url : smiley1Url; - if (states.contains(MaterialState.pressed)) { - url = smiley2Url; + late final ImageProvider image; + if (isRunning) { + image = runningImage; + } else if (states.contains(MaterialState.pressed)) { + image = pressedImage; + } else if (states.contains(MaterialState.hovered)) { + image = hoveredImage; + } else { + image = defaultImage; } return AnimatedContainer( width: 64, @@ -341,7 +371,7 @@ class _TextButtonExampleState extends State { curve: Curves.fastOutSlowIn, decoration: BoxDecoration( image: DecorationImage( - image: NetworkImage(url), + image: image, fit: BoxFit.contain, ), ), @@ -459,8 +489,3 @@ class TextButtonExampleSwitches extends StatelessWidget { ); } } - -const String grassUrl = 'https://flutter.github.io/assets-for-api-docs/assets/material/text_button_grass.jpeg'; -const String smiley1Url = 'https://flutter.github.io/assets-for-api-docs/assets/material/text_button_smiley1.png'; -const String smiley2Url = 'https://flutter.github.io/assets-for-api-docs/assets/material/text_button_smiley2.png'; -const String smiley3Url = 'https://flutter.github.io/assets-for-api-docs/assets/material/text_button_smiley3.png'; diff --git a/examples/api/test/material/text_button/text_button.0_test.dart b/examples/api/test/material/text_button/text_button.0_test.dart index e6a13b9dc3a..f444f332cfa 100644 --- a/examples/api/test/material/text_button/text_button.0_test.dart +++ b/examples/api/test/material/text_button/text_button.0_test.dart @@ -54,9 +54,25 @@ void main() { await tester.tap(find.widgetWithText(TextButton, 'TextButton #8')); await tester.pumpAndSettle(); - await tester.tap(find.byType(TextButton).last); // Smiley image button + final Finder smileyButton = find.byType(TextButton).last; + await tester.tap(smileyButton); // Smiley image button await tester.pumpAndSettle(); + String smileyButtonImageUrl() { + final AnimatedContainer container = tester.widget( + find.descendant(of: smileyButton, matching: find.byType(AnimatedContainer)), + ); + final BoxDecoration decoration = container.decoration! as BoxDecoration; + final NetworkImage image = decoration.image!.image as NetworkImage; + return image.url; + } + // The smiley button's onPressed method changes the button image + // for one second to simulate a long action running. The button's + // image changes while the action is running. + expect(smileyButtonImageUrl().endsWith('text_button_nhu_end.png'), isTrue); + await tester.pump(const Duration(seconds: 1)); + expect(smileyButtonImageUrl().endsWith('text_button_nhu_default.png'), isTrue); + await tester.tap(find.byType(Switch).at(0)); // Dark Mode Switch await tester.pumpAndSettle();