flutter/examples/api/test/material
auto-submit[bot] 07ca92a69e
Reverts "Added ButtonStyle.foregroundBuilder and ButtonStyle.backgroundBuilder" (#142748)
Reverts flutter/flutter#141818
Initiated by: XilaiZhang
This change reverts the following previous change:
Original Description:
Fixes https://github.com/flutter/flutter/issues/139456, https://github.com/flutter/flutter/issues/130335, https://github.com/flutter/flutter/issues/89563.

Two new properties have been added to ButtonStyle to make it possible to insert arbitrary state-dependent widgets in a button's background or foreground. These properties can be specified for an individual button, using the style parameter, or for all buttons using a button theme's style parameter.

The new ButtonStyle properties are `backgroundBuilder` and `foregroundBuilder` and their (function) types are:

```dart
typedef ButtonLayerBuilder = Widget Function(
  BuildContext context,
  Set<MaterialState> states,
  Widget? child
);
```

The new builder functions are called whenever the button is built and the `states` parameter communicates the pressed/hovered/etc state fo the button.

## `backgroundBuilder`

Creates a widget that becomes the child of the button's Material and whose child is the rest of the button, including the button's `child` parameter.  By default the returned widget is clipped to the Material's ButtonStyle.shape.

The `backgroundBuilder` can be used to add a gradient to the button's background. Here's an example that creates a yellow/orange gradient background:

![opaque-gradient-bg](https://github.com/flutter/flutter/assets/1377460/80df8368-e7cf-49ef-aee7-2776a573644c)

```dart
TextButton(
  onPressed: () {},
  style: TextButton.styleFrom(
    backgroundBuilder: (BuildContext context, Set<MaterialState> states, Widget? child) {
      return DecoratedBox(
        decoration: BoxDecoration(
          gradient: LinearGradient(colors: [Colors.orange, Colors.yellow]),
        ),
        child: child,
      );
    },
  ),
  child: Text('Text Button'),
)
```

Because the background widget becomes the child of the button's Material, if it's opaque (as it is in this case) then it obscures the overlay highlights which are painted on the button's Material. To ensure that the highlights show through one can decorate the background with an `Ink` widget.  This version also overrides the overlay color to be (shades of) red, because that makes the highlights look a little nicer with the yellow/orange background.

![ink-gradient-bg](https://github.com/flutter/flutter/assets/1377460/68a49733-f30e-44a1-a948-dc8cc95e1716)

```dart
TextButton(
  onPressed: () {},
  style: TextButton.styleFrom(
    overlayColor: Colors.red,
    backgroundBuilder: (BuildContext context, Set<MaterialState> states, Widget? child) {
      return Ink(
        decoration: BoxDecoration(
          gradient: LinearGradient(colors: [Colors.orange, Colors.yellow]),
        ),
        child: child,
      );
    },
  ),
  child: Text('Text Button'),
)
```

Now the button's overlay highlights are painted on the Ink widget. An Ink widget isn't needed if the background is sufficiently translucent. This version of the example creates a translucent backround widget. 

![translucent-graident-bg](https://github.com/flutter/flutter/assets/1377460/3b016e1f-200a-4d07-8111-e20d29f18014)

```dart
TextButton(
  onPressed: () {},
  style: TextButton.styleFrom(
    overlayColor: Colors.red,
    backgroundBuilder: (BuildContext context, Set<MaterialState> states, Widget? child) {
      return DecoratedBox(
        decoration: BoxDecoration(
          gradient: LinearGradient(colors: [
            Colors.orange.withOpacity(0.5),
            Colors.yellow.withOpacity(0.5),
          ]),
        ),
        child: child,
      );
    },
  ),
  child: Text('Text Button'),
)
```

One can also decorate the background with an image. In this example, the button's background is an burlap texture image. The foreground color has been changed to black to make the button's text a little clearer relative to the mottled brown backround.

![burlap-bg](https://github.com/flutter/flutter/assets/1377460/f2f61ab1-10d9-43a4-bd63-beecdce33b45)

```dart
TextButton(
  onPressed: () {},
  style: TextButton.styleFrom(
    foregroundColor: Colors.black,
    backgroundBuilder: (BuildContext context, Set<MaterialState> states, Widget? child) {
      return Ink(
        decoration: BoxDecoration(
          image: DecorationImage(
            image: NetworkImage(burlapUrl),
            fit: BoxFit.cover,
          ),
        ),
        child: child,
      );
    },
  ),
  child: Text('Text Button'),
)
```

The background widget can depend on the `states` parameter. In this example the blue/orange gradient flips horizontally when the button is hovered/pressed.

![gradient-flip](https://github.com/flutter/flutter/assets/1377460/c6c6fe26-ae47-445b-b82d-4605d9583bd8)

```dart
TextButton(
  onPressed: () {},
  style: TextButton.styleFrom(
    backgroundBuilder: (BuildContext context, Set<MaterialState> states, Widget? child) {
      final Color color1 = Colors.blue.withOpacity(0.5);
      final Color color2 = Colors.orange.withOpacity(0.5);
      return DecoratedBox(
        decoration: BoxDecoration(
          gradient: LinearGradient(
            colors: switch (states.contains(MaterialState.hovered)) {
              true => <Color>[color1, color2],
              false => <Color>[color2, color1],
            },
          ),
        ),
        child: child,
      );
    },
  ),
  child: Text('Text Button'),
)
```

The preceeding examples have not included a BoxDecoration border because ButtonStyle already supports `ButtonStyle.shape` and `ButtonStyle.side` parameters that can be uesd to define state-dependent borders. Borders defined with the ButtonStyle side parameter match the button's shape. To add a border that changes color when the button is hovered or pressed, one must specify the side property using `copyWith`, since there's no `styleFrom` shorthand for this case.

![border-gradient-bg](https://github.com/flutter/flutter/assets/1377460/63cffcd3-0dcf-4eb1-aed5-d14adf1e57f6)

```dart
TextButton(
  onPressed: () {},
  style: TextButton.styleFrom(
    foregroundColor: Colors.indigo,
    backgroundBuilder: (BuildContext context, Set<MaterialState> states, Widget? child) {
      final Color color1 = Colors.blue.withOpacity(0.5);
      final Color color2 = Colors.orange.withOpacity(0.5);
      return DecoratedBox(
        decoration: BoxDecoration(
          gradient: LinearGradient(
            colors: switch (states.contains(MaterialState.hovered)) {
              true => <Color>[color1, color2],
              false => <Color>[color2, color1],
            },
          ),
        ),
        child: child,
      );
    },
  ).copyWith(
    side: MaterialStateProperty.resolveWith<BorderSide?>((Set<MaterialState> states) {
      if (states.contains(MaterialState.hovered)) {
        return BorderSide(width: 3, color: Colors.yellow);
      }
      return null; // defer to the default
    }),
  ),
  child: Text('Text Button'),
)
```

Although all of the examples have created a ButtonStyle locally and only applied it to one button, they could have configured the `ThemeData.textButtonTheme` instead and applied the style to all TextButtons. And, of course, all of this works for all of the ButtonStyleButton classes, not just TextButton.

## `foregroundBuilder`

Creates a Widget that contains the button's child parameter. The returned widget is clipped by the button's [ButtonStyle.shape] inset by the button's [ButtonStyle.padding] and aligned by the button's [ButtonStyle.alignment].

The `foregroundBuilder` can be used to wrap the button's child, e.g. with a border or a `ShaderMask` or as a state-dependent substitute for the child.

This example adds a border that's just applied to the child. The border only appears when the button is hovered/pressed.

![border-fg](https://github.com/flutter/flutter/assets/1377460/687a3245-fe68-4983-a04e-5fcc77f8aa21)

```dart
ElevatedButton(
  onPressed: () {},
  style: ElevatedButton.styleFrom(
    foregroundBuilder: (BuildContext context, Set<MaterialState> states, Widget? child) {
      final ColorScheme colorScheme = Theme.of(context).colorScheme;
      return DecoratedBox(
        decoration: BoxDecoration(
          border: states.contains(MaterialState.hovered)
            ? Border(bottom: BorderSide(color: colorScheme.primary))
            : Border(), // essentially "no border"
        ),
        child: child,
      );
    },
  ),
  child: Text('Text Button'),
)
```

The foregroundBuilder can be used with `ShaderMask` to change the way the button's child is rendered. In this example the ShaderMask's gradient causes the button's child to fade out on top.

![shader_mask_fg](https://github.com/flutter/flutter/assets/1377460/54010f24-e65d-4551-ae58-712135df3d8d)

```dart
ElevatedButton(
  onPressed: () { },
  style: ElevatedButton.styleFrom(
    foregroundBuilder: (BuildContext context, Set<MaterialState> states, Widget? child) {
      final ColorScheme colorScheme = Theme.of(context).colorScheme;
      return ShaderMask(
        shaderCallback: (Rect bounds) {
          return LinearGradient(
            begin: Alignment.bottomCenter,
            end: Alignment.topCenter,
            colors: <Color>[
              colorScheme.primary,
              colorScheme.primaryContainer,
            ],
          ).createShader(bounds);
        },
        blendMode: BlendMode.srcATop,
        child: child,
      );
    },
  ),
  child:  const Text('Elevated Button'),
)
```

A commonly requested configuration for butttons has the developer provide images, one for pressed/hovered/normal state. You can use the foregroundBuilder to create a button that fades between a normal image and another image when the button is pressed. In this case the foregroundBuilder doesn't use the child it's passed, even though we've provided the required TextButton child parameter.

![image-button](https://github.com/flutter/flutter/assets/1377460/f5b1a22f-43ce-4be3-8e70-06de4c958380)

```dart
TextButton(
  onPressed: () {},
  style: TextButton.styleFrom(
    foregroundBuilder: (BuildContext context, Set<MaterialState> states, Widget? child) {
      final String url = states.contains(MaterialState.pressed) ? smiley2Url : smiley1Url;
      return AnimatedContainer(
        width: 100,
        height: 100,
        duration: Duration(milliseconds: 300),
        decoration: BoxDecoration(
          image: DecorationImage(
            image: NetworkImage(url),
            fit: BoxFit.contain,
          ),
        ),
      );
    },
  ),
  child: Text('No Child'),
)
```

In this example the button's default overlay appears when the button is hovered and pressed. Another image can be used to indicate the hovered state and the default overlay can be defeated by specifying `Colors.transparent` for the `overlayColor`:

![image-per-state](https://github.com/flutter/flutter/assets/1377460/7ab9da2f-f661-4374-b395-c2e0c7c4cf13)

```dart
TextButton(
  onPressed: () {},
  style: TextButton.styleFrom(
    overlayColor: Colors.transparent,
    foregroundBuilder: (BuildContext context, Set<MaterialState> states, Widget? child) {
      String url = states.contains(MaterialState.hovered) ? smiley3Url : smiley1Url;
      if (states.contains(MaterialState.pressed)) {
        url = smiley2Url;
      }
      return AnimatedContainer(
        width: 100,
        height: 100,
        duration: Duration(milliseconds: 300),
        decoration: BoxDecoration(
          image: DecorationImage(
            image: NetworkImage(url),
            fit: BoxFit.contain,
          ),
        ),
      );
    },
  ),
  child: Text('No Child'),
)
```
2024-02-01 21:11:26 +00:00
..
action_buttons Rename Sample classes (#124080) 2023-04-04 20:34:29 +00:00
action_chip Update Chips examples and rename files (#108538) 2022-07-29 07:17:06 +00:00
animated_icon Move AnimatedIcons example and fix typo in cupertino/text_selection_toolbar.dart (#113937) 2022-10-25 07:27:06 +00:00
app [Reland] Introduce AnimationStyle (#138721) 2023-11-20 15:24:41 -08:00
app_bar Renamed appbar to app_bar directory in API Examples Tests (#139922) 2023-12-11 22:54:13 +00:00
autocomplete Fix bug in Autocomplete example (#127219) 2023-05-22 16:55:21 +00:00
bottom_navigation_bar Write tests for API examples of BottomNavigationBar and IconButton (#138188) 2023-11-27 17:26:37 +00:00
bottom_sheet Fix Material 3 BottomSheet example (#116112) 2022-11-30 02:08:21 +00:00
card Write Tests for API Examples of snack_bar.0, elevated_button.0, stepper.0, radio.0, filled_button.0, outlined_button.0 & card.0 (#138987) 2023-11-28 23:57:10 +00:00
checkbox_list_tile Add Material 3 SwitchListTile example and update existing examples (#119714) 2023-02-06 09:02:37 +00:00
choice_chip Fix typos (#121171) 2023-02-23 19:43:21 +00:00
context_menu Implement SelectionArea single click/tap gestures (#132682) 2023-09-28 01:42:16 +00:00
data_table Write Tests for API Examples of cupertino_text_field.0, data_table.0, icon_button.2 & ink_well.0 (#139258) 2023-11-30 20:07:00 +00:00
date_picker Update date picker examples, remove unused variables and add missing tests (#121528) 2023-02-28 08:31:51 +00:00
dialog Adaptive alert dialog (#124336) 2023-04-18 23:00:03 +00:00
divider Rename Sample classes (#124080) 2023-04-04 20:34:29 +00:00
drawer Add missing example links (#130521) 2023-07-17 18:24:49 +00:00
dropdown Treat hidden IndexedStack children as offstage for test finder (#123129) 2023-03-29 19:58:58 +00:00
dropdown_menu Improve DropdownMenu sample code for requestFocusOnTap on mobile platforms (#134867) 2023-09-18 08:33:14 +00:00
elevated_button Write Tests for API Examples of snack_bar.0, elevated_button.0, stepper.0, radio.0, filled_button.0, outlined_button.0 & card.0 (#138987) 2023-11-28 23:57:10 +00:00
expansion_panel Update ExpansionPanel example for the updated expansionCallback callback (#132837) 2023-08-21 20:13:22 +00:00
expansion_tile Add AnimationStyle to ExpansionTile (#139664) 2023-12-06 16:40:24 +00:00
filled_button Write Tests for API Examples of snack_bar.0, elevated_button.0, stepper.0, radio.0, filled_button.0, outlined_button.0 & card.0 (#138987) 2023-11-28 23:57:10 +00:00
filter_chip Update Chips examples and rename files (#108538) 2022-07-29 07:17:06 +00:00
floating_action_button Add FAB Additional Color Mappings example (#133453) 2023-08-29 17:31:02 +00:00
icon_button Write Tests for API Examples of cupertino_text_field.0, data_table.0, icon_button.2 & ink_well.0 (#139258) 2023-11-30 20:07:00 +00:00
ink Rename Sample classes (#124080) 2023-04-04 20:34:29 +00:00
ink_well Write Tests for API Examples of cupertino_text_field.0, data_table.0, icon_button.2 & ink_well.0 (#139258) 2023-11-30 20:07:00 +00:00
input_chip Add an example for InputChip generated by user input (#130645) 2023-09-01 00:02:04 +00:00
input_decorator Updated InputDecoratorExamples for M3 (#128065) 2023-06-01 15:22:03 -07:00
list_tile Updated custom ListTile examples (#128071) 2023-06-01 16:21:42 -07:00
menu_anchor Convert menus to use OverlayPortal (#130534) 2023-10-18 20:13:08 +00:00
navigation_bar Add Badge widget to NavigationBar and NavigationRail examples (#129834) 2023-07-11 09:30:05 +00:00
navigation_drawer Add missing example links (#130521) 2023-07-17 18:24:49 +00:00
navigation_rail Fixed a lot of typos (#141431) 2024-01-12 22:10:25 +00:00
outlined_button Write Tests for API Examples of snack_bar.0, elevated_button.0, stepper.0, radio.0, filled_button.0, outlined_button.0 & card.0 (#138987) 2023-11-28 23:57:10 +00:00
page_transitions_theme Remove 1745 decorative breaks (#123259) 2023-03-22 21:12:22 +00:00
paginated_data_table PaginatedDataTable improvements (#131374) 2023-08-15 00:55:07 +00:00
popup_menu [Reland] Introduce AnimationStyle (#138721) 2023-11-20 15:24:41 -08:00
progress_indicator Add Material 3 ProgressIndicator examples (#113950) 2022-10-25 07:27:08 +00:00
radio Write Tests for API Examples of snack_bar.0, elevated_button.0, stepper.0, radio.0, filled_button.0, outlined_button.0 & card.0 (#138987) 2023-11-28 23:57:10 +00:00
radio_list_tile Add Material 3 RadioListTile example and update existing examples (#119716) 2023-02-03 16:27:43 +00:00
refresh_indicator Rename Sample classes (#124080) 2023-04-04 20:34:29 +00:00
reorderable_list Add a ReorderableListView example with cards + cleanup existing tests (#126155) 2023-05-05 16:39:11 +00:00
scaffold Reland: "Add example and troubleshooting comment for showSnackBar" (#105195) 2022-08-09 22:06:05 +00:00
scrollbar fix a Scrollbar example crash (#127925) 2023-09-08 09:40:49 +00:00
search_anchor make suggestionsBuilder in SearchAnchor asyncable (#127019) 2023-05-24 13:12:47 -07:00
segmented_button Add SegmentedButton.styleFrom (#137542) 2024-01-03 21:26:02 +00:00
slider Add Material 3 Slider example (#115638) 2022-12-01 00:00:19 +00:00
snack_bar Write Tests for API Examples of snack_bar.0, elevated_button.0, stepper.0, radio.0, filled_button.0, outlined_button.0 & card.0 (#138987) 2023-11-28 23:57:10 +00:00
stepper Adds support for StepStyle visual property bundle to the Step widget (#140825) 2024-01-12 16:35:08 +00:00
switch Adaptive Switch (#130425) 2023-11-07 10:26:23 -08:00
switch_list_tile Add Material 3 SwitchListTile example and update existing examples (#119714) 2023-02-06 09:02:37 +00:00
tabs Updated TabBar and ToggleButtons examples (#128088) 2023-06-02 01:05:31 +00:00
text_button Reverts "Added ButtonStyle.foregroundBuilder and ButtonStyle.backgroundBuilder" (#142748) 2024-02-01 21:11:26 +00:00
text_field Rename Sample classes (#124080) 2023-04-04 20:34:29 +00:00
theme_data Updated the ThemeData API example (#130954) 2023-07-20 13:12:34 -07:00
time_picker Convert TimePicker to Material 3 (#116396) 2022-12-14 00:09:52 +00:00
toggle_buttons Updated TabBar and ToggleButtons examples (#128088) 2023-06-02 01:05:31 +00:00
tooltip Introduce exitDuration to Tooltip for mouse pointer devices (#138321) 2023-12-07 21:20:06 +00:00