-
Notifications
You must be signed in to change notification settings - Fork 27.5k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Allow arbitrary foreground and background elements for ButtonStyle
#139456
Comments
Good suggestion here and, as you've pointed out, getting the design right means sorting out how to make common cases - like a gradient background - easy, and the tricky cases possible. Leaving the Material background in place is probably important, since it deals with the button's shape. Providing a way to stack a background widget on top of the Material (and clipped to the Material) does seem like a good general purpose idea. If you're interested in pursuing this further, prototyping some common cases and looking for ways to simplify writing them would be a helpful to continue. |
I played around with the ShaderMask part of your example a little (DartPad). The result is still a little complicated: ElevatedButton(
onPressed: () { },
style: ElevatedButton.styleFrom(
textStyle: theme.textTheme.displayLarge,
).copyWith(
// Lighten the hovered overlay color a little so that it doesn't
// obscure the faded part of the shader masked child.
overlayColor: MaterialStateProperty.resolveWith(
(Set<MaterialState> states) {
if (states.contains(MaterialState.hovered)) {
return colorScheme.primary.withOpacity(0.04);
}
return null; // defer to the default
},
),
),
child: ShaderMask(
shaderCallback: (Rect bounds) {
return LinearGradient(
begin: Alignment.bottomCenter,
end: Alignment.topCenter,
colors: <Color>[
colorScheme.primary,
colorScheme.primaryContainer,
],
).createShader(bounds);
},
blendMode: BlendMode.srcATop,
child: const Text('Elevated Button'),
),
) Doing so highlighted the fact it's not really practical for the child to respond to state changes in the same way that we'd like to have a background widget (stacked behind the child) also respond to state changes. As well as being informed of the button's shape and the child's insets. I have a vague idea about how to address these limitations without breaking backwards compatibility. The vague idea is that the background (currently the a Material widget) and the foreground (currently just the child) would be constructed by callbacks along the lines of what you've proposed earlier. Will try and make a concrete proposal here soon. |
Giving a button a gradient background isn't too difficult. Here's an example (DartPad) based on one provided by @TahaTesser in #130335. It requires one to restore the button's padding, by padding the button's child, and the configuration requires turning on clipping and using an Ink widget. As you can see by comparing this example with the previous one, my quick guess about the padding wasn't quite right. This isn't too complicated: ElevatedButton(
onPressed: () {},
clipBehavior: Clip.antiAlias, // Buttons don't clip their child by default.
style: ElevatedButton.styleFrom(
padding: EdgeInsets.zero, // So that the gradient fills the entire button.
textStyle: theme.textTheme.displayLarge,
),
child: Ink( // So that the button's overlay continues to appear.
decoration: BoxDecoration(
gradient: LinearGradient(
colors: <Color>[
colorScheme.primaryContainer,
colorScheme.tertiaryContainer,
],
begin: Alignment.topLeft,
end: Alignment.bottomRight,
),
),
child: const Padding(
padding: EdgeInsets.symmetric(horizontal: 16),
child: Text('Elevated Button'),
),
),
) Because the gradient background is introduced as part of the child, it's not possible to configure the ElevatedButtonTheme to give all elevated buttons a gradient background (this is also true for the previous example). And, as before, this example doesn't address creating a background that changes based on the button's state. |
I've addressed most of the issues described here in #141818. There's a detailed explanation of the new API in the PR's description. |
…#141818) Fixes #139456, #130335, #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'), ) ```
…ndBuilder" (#142748) Reverts #141818 Initiated by: XilaiZhang This change reverts the following previous change: Original Description: Fixes #139456, #130335, #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'), ) ```
This thread has been automatically locked since there has not been any recent activity after it was closed. If you are still experiencing a similar issue, please open a new bug, including the output of |
Is there an existing issue for this?
Use case
I want to add fairly arbitrary visual details to my app's
ElevatedButton
's (this feature request applies to all the material button types, but I'll useElevatedButton
as a stand in).Here are some examples:
As-is,
ButtonStyle
limits me to a very narrow range of style customization: shape, color, elevation...I could create my own button system, but the material buttons do an enormous amount of extremely helpful things (manage splash factory, handle material state, tune visual density to match the platform, etc) that would be a huge hassle to reverse engineer.
Here are some examples of random apps in the wild that have buttons that are not achievable without heavy workarounds.
My app. I use a linear gradient and a border using a complicated work around that puts every elevated button in a stack:
Marvel snap. Marvel snap uses a particularly complex system containing tons of elements:
Proposal
I think there are a lot of different ways to add greater customization to
ButtonStyle
. I will list a few I've thought of here, I'm very open to more suggestions!Container
's foreground and backgroundBoxDecoration
argumentsI don't love this solution as it's fairly limiting. For example, you can't use a
Stack
to stack elements on top of each other in this context.EdgeInsets
by which the button is padded with (as they should be able to draw in and outside of the button without having to reverse engineer the complicated padding logic).I like this much more, as it gives me completely arbitrary design control. For example, even Marvel Snap's insanely complicated button would probably be doable with this system. The implementation would need to ensure the foreground child doesn't interfere with hit testing. The disadvantage is that even pretty simple customizations (like adding a linear gradient) would be pretty complicated.
In both cases, the background argument would be placed between the button's child and the background
Material
. And/or theMaterial
could be left out entirely if the background argument is non null.Maybe to ensure that simple customization is easy while complex customization is still possible, BOTH
BoxDecoration
and builder based customization could be provided?What this might look like to use (coded off the top of my head, probably has minor syntax errors):
The text was updated successfully, but these errors were encountered: