13342 Commits

Author SHA1 Message Date
Taha Tesser
2adbc2b8ce
Fix chips constructor docs for callbacks (#143361)
fixes [ActionChip constructor documentation does not match class documentation](https://github.com/flutter/flutter/issues/137964)
2024-02-13 19:09:42 +00:00
Nate
8eea4f175f
Implementing switch expressions in widgets/ (#143293)
This PR is the 7ᵗʰ step in the journey to solve issue #136139 and make the entire Flutter repo more readable.

(previous pull requests: #139048, #139882, #141591, #142279, #142634, #142793)

This pull request covers everything in `packages/flutter/lib/src/widgets/`. Most of it should be really straightforward, but there was some refactoring in the `getOffsetToReveal()` function in `two_dimensional_viewport.dart`. I'll add some comments to describe those changes.
2024-02-13 18:51:03 +00:00
Taha Tesser
1f8d110b8f
Fix InputDecorators suffix and prefix widgets are tappable when hidden (#143308)
fixes [The InputDecoration's suffix and prefix widget can be tapped even if it does not appear](https://github.com/flutter/flutter/issues/139916)

This PR also updates two existing tests to pass the tests for this PR. These tests are trying to tap prefix and  suffix widgets when they're hidden. While the linked issue had visible prefix and suffix widgets https://github.com/flutter/flutter/issues/39376 for reproduction.

### Code sample

<details>
<summary>expand to view the code sample</summary> 

```dart
import 'package:flutter/material.dart';

void main() {
  runApp(MainApp());
}

class MainApp extends StatelessWidget {
  final _messangerKey = GlobalKey<ScaffoldMessengerState>();

  MainApp({super.key});

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      scaffoldMessengerKey: _messangerKey,
      home: Scaffold(
        body: Container(
          alignment: Alignment.center,
          padding: const EdgeInsets.all(16.0),
          child: TextField(
            decoration: InputDecoration(
              labelText: 'Something',
              prefix: GestureDetector(
                onTap: () {
                  _messangerKey.currentState?.showSnackBar(
                      const SnackBar(content: Text('A tap has occurred')));
                },
                child: const Icon(Icons.search),
              ),
              suffix: GestureDetector(
                onTap: () {
                  _messangerKey.currentState?.showSnackBar(
                      const SnackBar(content: Text('A tap has occurred')));
                },
                child: const Icon(Icons.search),
              ),
            ),
          ),
        ),
      ),
    );
  }
}
```

</details>

### Before
![ScreenRecording2024-02-12at18 40 34-ezgif com-video-to-gif-converter](https://github.com/flutter/flutter/assets/48603081/c101e0d6-ce5a-4b28-9626-28bcb83d2a5c)

### After
![ScreenRecording2024-02-12at18 40 10-ezgif com-video-to-gif-converter](https://github.com/flutter/flutter/assets/48603081/923b348e-8adf-4d64-9dc3-e75d30e3e2fb)
2024-02-13 08:48:18 +00:00
Tirth
e93a10d1fb
Pass-Through inputFormatters in DropdownMenu (#143250)
Pass-Through `inputFormatters` in `DropdownMenu`.

Fixes: #142374
2024-02-13 03:57:15 +00:00
Taha Tesser
d271791e8c
Fix insetPadding parameter nullability for dialogs (#143305)
fixes [`insetPadding` should be nullable in dialogs](https://github.com/flutter/flutter/issues/117125)
2024-02-13 00:12:02 +00:00
Ross Llewallyn
525cffd717
Badge class doc typo - missing [ (#143318)
Doc typo fix

No issue made
2024-02-12 23:24:41 +00:00
Kevin Moore
e1645b150f
[web] Move JS interop to extension types (#143274)
Now that we can bump the min SDK to latest.
2024-02-12 11:14:10 -08:00
Valentin Vignal
52f923c360
Add documentation for best practices for StreamBuilder like FutureBuilder (#143295)
Fixes https://github.com/flutter/flutter/issues/142189
2024-02-12 18:25:57 +00:00
Nitesh Sharma
49f620d8ea
Fix dual focus issue in CheckboxListTile, RadioListTile and SwitchListTile (#143213)
These widgets can now only receive focus once when tabbing through the focus tree.
2024-02-12 10:07:51 -08:00
Tirth
10442399fb
Introduce iconAlignment for the buttons with icon (#137348)
Adds `iconAlignment` property to `ButtonStyleButton` widget.

Fixes #89564

### Example

https://github.com/flutter/flutter/assets/13456345/1b5236c4-5c60-4915-b3c6-0a56c43f8a19
2024-02-12 17:08:20 +00:00
LongCatIsLooong
bc49cf8091
Fix text painter longest line resizing logic for TextWidthBasis.longestLine (#143024)
Fixes https://github.com/flutter/flutter/issues/142309.
2024-02-10 23:39:20 +00:00
Polina Cherkasova
b48dfca382
Upgrade leak_tracker. (#143236) 2024-02-09 14:41:22 -08:00
Nate
1887bc410f
Implementing switch expressions in lib/src/material/ (#142793)
This PR is the 6ᵗʰ step in the journey to solve issue #136139 and make the entire Flutter repo more readable.

(previous pull requests: #139048, #139882, #141591, #142279, #142634)

The current focus is on `packages/flutter/lib/src/material/`. The previous 2 PRs covered files in this directory starting with letters `a-m`; this one takes care of everything else.
2024-02-09 22:03:23 +00:00
Henry Riehl
fa71e8029b
Add position data to OnDragEnd callback (#140378)
This PR adds localPosition/globalPosition data to the `DragEndDetails`
argument of the `onDragEnd` callback.
2024-02-09 12:37:20 -08:00
David Martos
f0bb9d57e6
barrierColor property in DialogTheme (#142490) 2024-02-09 01:50:14 -08:00
Michael Goderbauer
0aa9b5e17d
Layout animated GIFs only once (#143188)
Fixes https://github.com/flutter/flutter/issues/138610.

When `RenderImage` receives a new `Image` it only needs to fire up the layout machinery when the dimensions of the image have changed compared to the previous image. If the dimensions are the same, a repaint is sufficient.
2024-02-09 01:12:06 +00:00
Michael Goderbauer
8d3c7b6f6a
Cross-link SliverFixedExtentList/SliverPrototypeExtentList/SliverVariedExtentList (#143184)
Fixes https://github.com/flutter/flutter/issues/141678.
2024-02-08 21:45:06 +00:00
Qun Cheng
cc4abe92fb
Correct menu position when menu is constrained (#143121)
Fixes #142896

The original code below is to always place the selected item above(overlap) the popup button so that the selected item can always be visible: f8a77225f3/packages/flutter/lib/src/material/popup_menu.dart (L723-L732)

But when menu height is constrained and the menu itself is super long, the selected item still assumes there is enough space to push up all the items whose index is smaller than the selected index. As a result, every time when the menu is open, the calculation provides a different result to be the offset for the selected index,  and then with a constrained height, the menu looks jumping all over the place based on the different selected index.

https://github.com/flutter/flutter/assets/36861262/ad761f95-0ff5-4311-a81d-dac56df879c5

Even though the original calculation is to make the selected item visible when open the menu, the menu doesn't auto scroll and only expands itself as much as possible to show the selected one. In this case, if the screen it too small to show the selected item, we still cannot see it. This can be fixed by using `Scrollable.ensureVisible()`(#143118).

So we remove the calculation in this PR and the menu will always show up based on the top left of the anchor(button).

https://github.com/flutter/flutter/assets/36861262/03272f26-9440-4ac4-a701-9a0b41776ff9
2024-02-08 20:36:24 +00:00
Qun Cheng
d85497d91b
Add a unit test for NavigationRail (#143108)
Adding `SingleChildScrollView` to `NavigationRail` may cause exception if the nav rail has some expanded widgets inside, like the issue: https://github.com/flutter/flutter/issues/143061. This PR is just to add a unit test to avoid causing this breaking again.
2024-02-07 23:14:56 +00:00
yim
16e7218cd4
Fixed cursor blinking during selection. (#141380)
The cursor now correctly stops blinking while it's being interacted with.
2024-02-07 13:39:30 -08:00
Ian Hickson
9fccb32a58
Various improvements to text-editing-related documentation. (#142561) 2024-02-07 19:58:06 +00:00
Michael Goderbauer
4becae25b0
Revert "Add SingleChildScrollView for NavigationRail" (#143097)
Reverts flutter/flutter#137415

Reverting due to https://github.com/flutter/flutter/issues/143061. this is breaking some existing use cases, see also https://github.com/flutter/samples/pull/2157. If we try this again, we need to add this in less breaking way.

Fixes https://github.com/flutter/flutter/issues/143061
2024-02-07 19:30:02 +00:00
Ian Hickson
1699ff38fe
Add a test for the isAvailableForEnvironment logic (#142251)
This is part 3 of a broken down version of the #140101 refactor.

There's some TODOs showing where I think we should change the behaviour, but in this PR the behaviour is unchanged.
A future PR will remove the tests that are redundant with these tests, but I wanted to make sure we had both sets in the codebase at the same time first.
This PR includes a change to the golden control test so that we can verify that these specific values do work on main. It would be extremely surprising if not, but in the interests of rigour...
2024-02-07 19:01:48 +00:00
Michael Goderbauer
0202e3bf7a
Add indexInParent to SemanticsNode debug information (#142826)
https://github.com/flutter/flutter/issues/93232
2024-02-07 18:51:04 +00:00
maRci002
8e2da8414c
Handle transitions to AppLifecycleState.detached in lifecycle state generation (#142523)
Generates the correct lifecycle state transitions in ServicesBinding when detaching.
2024-02-07 10:01:22 -08:00
Bruno Leroux
6a7baf573e
Fix M3 text field height + initial step for input decorator M3 test migration (#142981)
## Description

This PR main purpose is to make progress on the M3 test migration for `InputDecorator` (see https://github.com/flutter/flutter/issues/139076).

Before this PR more than 80 of the 156 tests defined in `input_decorator_test.dart` fail on M3.
Migrating all those tests in one shot is not easy at all because many failures are related to wrong positionning due to M3 typography changes. Another reason is that several M3 specific changes are required in order to get a proper M3 compliant text field, for instance:
- https://github.com/flutter/flutter/issues/142972
- https://github.com/flutter/flutter/issues/141354

Most of the tests were relying on an helper function (`buildInputDecorator`) which had a `useMaterial3` parameter. Unfortunately when `useMaterial3: true `was passed to this function it forced `useMaterial3: false` at the top level but overrided it at a lower level, which was very misleading because people could assume that the tests are ok with M3 (but in fact they were run using M2 typography but have some M3 logic in use).
I considered various way to make this change and I finally decided to run all existing tests only on M2 for the moment. Next step will be to move most of those tests to M3. In this PR, I migrated two of these existing tests for illustration.

Because many of the existing tests are checking input decorator height, I think it would also make sense to fix https://github.com/flutter/flutter/issues/142972 first. That's why I choosed to include a fix to https://github.com/flutter/flutter/issues/142972 in this PR.

A M3 filled `TextField` on Android:

| Before this PR | After this PR |
|--------|--------|
| ![image](https://github.com/flutter/flutter/assets/840911/403225b7-4c91-4aee-b19c-0490447ae7e3) | ![image](https://github.com/flutter/flutter/assets/840911/e96cf786-a9f5-4e15-bcdd-078350ff1608) | 

## Related Issue

Fixes https://github.com/flutter/flutter/issues/142972
Related to https://github.com/flutter/flutter/issues/139076

## Tests

Updates many existing tests 
+ adds 2 tests related to the fix for https://github.com/flutter/flutter/issues/142972
+ adds 1 tests for the M3 migration
+ move 1 tests related to M3
2024-02-07 13:57:21 +00:00
Taha Tesser
c539ded64b
[reland] Add AnimationStyle to showSnackBar (#143052)
[Original was reverted due to uncaught analysis failure 
](https://github.com/flutter/flutter/pull/142825#issuecomment-1930620085)

---

fixes [`showSnackBar` is always replacing `animation` parameter of `SnackBar`](https://github.com/flutter/flutter/issues/141646)

### Code sample preview

![Screenshot 2024-02-02 at 21 10 57](https://github.com/flutter/flutter/assets/48603081/66d808f0-d638-4561-b9a4-96d1b93938f4)
2024-02-07 10:26:27 +00:00
Dan Field
7514c16a6a
Dispose precached image info (#143017)
`precacheImage` was failing to dipose the `ImageInfo` it receives. That's part of the contract of being an image listener.

I'm doing this in the frame callback for the same reason as evicting it from the cache.
2024-02-07 03:28:06 +00:00
Polina Cherkasova
ac5c3dec87
Instrument CurvedAnimation. (#143007) 2024-02-07 03:26:40 +00:00
auto-submit[bot]
310a7edbca
Reverts "Activate InkSparkle on CanvasKit" (#143036)
Reverts flutter/flutter#138545

Initiated by: zanderso

Reason for reverting: Failing in post-submit: https://ci.chromium.org/ui/p/flutter/builders/prod/Linux%20web_long_running_tests_5_5/14975/overview

```
══╡ EXCEPTION CAUGHT BY FLUTTER TEST FRAMEWORK ╞═════════════════
The following FormatException was thrown running a test:
Invalid Shader Data

When the exception was thrown, this was the stack:
dart-sdk/lib/_internal/js_dev_runtime/private/ddc_runtime/errors.da

Original PR Author: bleroux

Reviewed By: {Piinks}

This change reverts the following previous change:
Original Description:
## Description

This PR activates the M3 `InkSparkle` splash animation on Android + CanvasKit.
Before it `InkSparkle` was only activated on native Android.

## Related Issue

Fixes https://github.com/flutter/flutter/issues/138487

## Tests

Updates several existing tests.
2024-02-07 02:44:21 +00:00
Bruno Leroux
7f811fb444
Activate InkSparkle on CanvasKit (#138545)
## Description

This PR activates the M3 `InkSparkle` splash animation on Android + CanvasKit.
Before it `InkSparkle` was only activated on native Android.

## Related Issue

Fixes https://github.com/flutter/flutter/issues/138487

## Tests

Updates several existing tests.
2024-02-07 00:28:04 +00:00
Simon Friis Vindum
2911bfb84c
Make destructiveRed a CupertinoDynamicColor (#141364)
`destructiveRed` is an alias for `systemRed`, but, in the definition, the precise type information is lost.

This PR gives `destructiveRed` the type `CupertinoDynamicColor` (and not the superclass `Color`) like all the other colors defined in this file.
2024-02-06 21:26:52 +00:00
Callum Moffat
1aa6ff5614
Fix CupertinoPageScaffold resizeToAvoidBottomInset (#142776)
Need to create a `MediaQuery` to expose the fact that the `viewInsets` have been consumed.

Fixes #142775
2024-02-06 20:57:53 +00:00
auto-submit[bot]
83aca58fa7
Reverts "Add AnimationStyle to showSnackBar" (#143001)
Reverts flutter/flutter#142825

Initiated by: zanderso

Reason for reverting: Analysis failure closing the engine tree https://logs.chromium.org/logs/flutter/buildbucket/cr-buildbucket/8756815302197889649/+/u/Framework_analyze/Framework_analyze/stdout?format=raw

Original PR Author: TahaTesser

Reviewed By: {HansMuller}

This change reverts the following previous change:
Original Description:
fixes [`showSnackBar` is always replacing `animation` parameter of `SnackBar`](https://github.com/flutter/flutter/issues/141646)

### Code sample preview

![Screenshot 2024-02-02 at 21 10 57](https://github.com/flutter/flutter/assets/48603081/66d808f0-d638-4561-b9a4-96d1b93938f4)
2024-02-06 19:35:19 +00:00
David Martos
37fd173e03
Material 3 - Tab indicator stretch animation (#141954)
Fixes #128696 (Motion checkbox)

This PR updates the Material 3 tab indicator animation, so that it stretches, as it can be seen in the showcase videos in the specification https://m3.material.io/components/tabs/accessibility#13ed756b-fb35-4bb3-ac8c-1157e49031d8

One thing to note is that the Material 3 videos have a tab transition duration of 700 ms, whereas currently in Flutter the duration is 300 ms. I recorded 4 comparison videos to see the difference better (current animation vs stretch animation  and  300 ms vs 700 ms)
@Piinks You mentioned the other day that the default tab size could be updated in the future to better reflect the new size in M3. Maybe the `kTabScrollDuration` constant is another one that could end up being updated, as 300 ms for this animation feels too fast.

Here are the comparison videos (Material 3 spec showcase on the left and Flutter on the right)

## Original animation - 300 ms

https://github.com/flutter/flutter/assets/22084723/d5b594fd-52ea-4328-b8e2-ddb597c81f69

## New animation - 300 ms

https://github.com/flutter/flutter/assets/22084723/c822f7ab-3fc4-4403-a53b-872d047f6227

---

## Original animation - 700 ms

https://github.com/flutter/flutter/assets/22084723/fe39a32d-3d10-4c0d-98df-bd5e1c9336d0

## New animation - 700 ms

https://github.com/flutter/flutter/assets/22084723/8d4b0628-6312-40c2-bd99-b4bcb8e23ba9

---

## Code sample

```dart
void main() => runApp(const MyApp());

class MyApp extends StatelessWidget {
  const MyApp({super.key});

  @override
  Widget build(BuildContext context) {
    return const MaterialApp(
      debugShowCheckedModeBanner: false,
      home: TabExample(),
    );
  }
}

class TabExample extends StatelessWidget {
  const TabExample({super.key});

  @override
  Widget build(BuildContext context) {
    return DefaultTabController(
      initialIndex: 1,
      length: 3,
      child: Scaffold(
        appBar: AppBar(
          title: const Text('My saved media'),
          bottom: const TabBar(
            tabs: <Widget>[
              Tab(
                icon: Icon(Icons.videocam_outlined),
                text: "Video",
              ),
              Tab(
                icon: Icon(Icons.photo_outlined),
                text: "Photos",
              ),
              Tab(
                icon: Icon(Icons.audiotrack),
                text: "Audio",
              ),
            ],
          ),
        ),
        body: const TabBarView(
          children: <Widget>[
            Center(
              child: Text("Tab 1"),
            ),
            Center(
              child: Text("Tab 2"),
            ),
            Center(
              child: Text("Tab 3"),
            ),
          ],
        ),
      ),
    );
  }
}
```

*If you had to change anything in the [flutter/tests] repo, include a link to the migration guide as per the [breaking change policy].*
2024-02-06 19:01:49 +00:00
Taha Tesser
0cc381da19
Add AnimationStyle to showSnackBar (#142825)
fixes [`showSnackBar` is always replacing `animation` parameter of `SnackBar`](https://github.com/flutter/flutter/issues/141646)

### Code sample preview

![Screenshot 2024-02-02 at 21 10 57](https://github.com/flutter/flutter/assets/48603081/66d808f0-d638-4561-b9a4-96d1b93938f4)
2024-02-06 18:54:41 +00:00
Renzo Olivares
0903bf7055
TextField context menu should fade on scroll on mobile devices (#138313)
This change affects Android and iOS devices using the TextField's context menu. After this change the context menu will fade out when scrolling the text and fade in when the scroll ends. 

If the scroll ends and the selection is outside of the view, then the toolbar will be scheduled to show in a future scroll end. This toolbar scheduling can be invalidated if the `TextEditingValue` changed anytime between the scheduling and when the toolbar is ready to be shown.

This change also fixes a regression where the TextField context menu would not fade when the selection handles where not visible.

When using the native browser context menu this behavior is not controlled by Flutter.

https://github.com/flutter/flutter/assets/948037/3f46bcbb-ba6f-456c-8473-e42919b9d572

Fixes #52425
Fixes #105804
Fixes #52426
2024-02-06 05:42:40 +00:00
Shaun Byrne
c21fbabc2b
Grey out non-selectable days in CupertinoDatePicker (#136181)
This PR changes the text color of non-selectable days in the CupertinoDatePicker to match non-selectable months and years.

Current:
![Screenshot_1696829290](https://github.com/flutter/flutter/assets/147121557/209fee88-9efc-4b92-803a-453ecc6a7c16)

New:
![Screenshot_1696830232](https://github.com/flutter/flutter/assets/147121557/ecd11266-4c22-49cc-9bb5-2df39d10cf79)

Fixes #136179
2024-02-05 23:49:17 +00:00
BiskupMaik
0b5cd5073a
fix AppBar docs for backgroundColor & foregroundColor (#142430)
Before the M3 migration, the doc made sense. but after, it needed to specify which material version does this issue occur in.
The _AppBarDefaultsM3 don't take the brightness in consideration anymore:

<img width="517" alt="image" src="https://github.com/flutter/flutter/assets/124896814/d4dbe278-5b50-42d7-9143-c54d343efddf">
2024-02-05 05:16:23 +00:00
Justin McCandless
f1eeda7415
Update TextSelectionOverlay (#142463)
Fixes a bug where changing parameters in EditableText that affect the selection overlay didn't update the overlay.
2024-02-02 13:35:11 -08:00
Luccas Clezar
fc3f4ed882
Fix CupertinoTextSelectionToolbar clipping (#138195)
The CupertinoTextSelectionToolbar sets the maxWidth of the whole toolbar to the width of the first page. This ends up clipping other pages from the toolbar. This PR just removes this limitation.

It was easy enough that I thought there was a catch, but I ran the tests locally and they all passed.

|Before|After|
|-|-|
|![Simulator Screenshot - iPhone Xʀ - 2023-11-09 at 19 45 29](https://github.com/flutter/flutter/assets/12024080/c84c40b9-3b02-48bf-9e87-17a9e4cfb461)|![Simulator Screenshot - iPhone Xʀ - 2023-11-09 at 19 44 30](https://github.com/flutter/flutter/assets/12024080/0c3d829b-952e-462b-9f02-8a2833c6f65d)|

https://github.com/flutter/flutter/issues/138177
2024-02-02 20:22:42 +00:00
Justin McCandless
3280be9371
Support navigation during a Cupertino back gesture (#142248)
Fixes a bug where programmatically navigating during an iOS back gesture caused the app to enter an unstable state.
2024-02-02 11:27:20 -08:00
Hans Muller
c6f2cea65e
Reland: Added ButtonStyle.foregroundBuilder and ButtonStyle.backgroundBuilder (#142762)
Reland https://github.com/flutter/flutter/pull/141818 with a fix for a special case: If only `background` is specified for `TextButton.styleFrom` or `OutlinedButton.styleFrom` it applies the button's disabled state, i.e. as if the same value had been specified for disabledBackgroundColor.

The change relative to #141818 is the indicated line below:
```dart
final MaterialStateProperty<Color?>? backgroundColorProp = switch ((backgroundColor, disabledBackgroundColor)) {
  (null, null) => null,
  (_, null) => MaterialStatePropertyAll<Color?>(backgroundColor), // ADDED THIS LINE
  (_, _) => _TextButtonDefaultColor(backgroundColor, disabledBackgroundColor),
};
  ```

This backwards incompatibility cropped up in an internal test, see internal Google issue b/323399158.
2024-02-02 01:48:17 +00:00
Nate
5b947c889b
Implement switch expressions in lib/src/material/ (#142634)
This PR is step 5 in the journey to solve issue #136139 and make the entire Flutter repo more readable.

(previous pull requests: #139048, #139882, #141591, #142279)

The current focus is on `packages/flutter/lib/src/material/`.  
The previous PR covered files in this directory starting with `a`, `b`, and `c`; this pull request is for `d` through `m`.
2024-02-01 22:31:10 +00:00
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
Polina Cherkasova
fdf05c90bf
Fix leaks in tests. (#142677) 2024-02-01 11:49:54 -08:00
Simone Stasi
cd6ed39550
fix CupertinoTabView's Android back button handling with PopScope (#141604)
This PR fixes CupertinoTabView's handling of Android back button with PopScope and nested navigators by calling `NavigatorState.maybePop` instead of `NavigatorState.pop`, so that the Navigator pops only when it should.

Fix #139050
2024-02-01 19:07:45 +00:00
Christopher Fujino
a80333349a
Unpin test (#141427)
Fixes https://github.com/flutter/flutter/issues/140169
2024-02-01 18:53:23 +00:00
Qun Cheng
4d61823ce4
Introduce tone-based surfaces and accent color add-ons - Part 1 (#142654)
This PR is to add 19 new `ColorScheme` roles following the Material Design 3 specs. This PR doesn't apply the new colors to `ThemeData`  or any widgets.

This PR is created to split the big change in #138521, once this is merged, another PR that contains the rest of the changes(apply new color roles to widgets and deprecate 3 more colors) will follow.

**Tone-based surface colors** (7 colors): 
* surfaceBright
* surfaceDim
* surfaceContainer
* surfaceContainerLowest
* surfaceContainerLow
* surfaceContainerHigh
* surfaceContainerHighest

**Accent color add-ons** (12 colors):
* primary/secondary/tertiary-Fixed
* primary/secondary/tertiary-FixedDim
* onPrimary/onSecondary/onTertiary-Fixed
* onPrimary/onSecondary/onTertiary-FixedVariant

Please checkout this [design doc](https://docs.google.com/document/d/1ODqivpM_6c490T4j5XIiWCDKo5YqHy78YEFqDm4S8h4/edit?usp=sharing) for more information:)
2024-02-01 04:59:05 +00:00
Greg Spencer
2652b9a305
Convert button .icon and .tonalIcon constructors to take nullable icons. (#142644)
## Description

This changes the factory constructors for `TextButton.icon`, `ElevatedButton.icon`, `FilledButton.icon`, and `FilledButton.tonalIcon` to take nullable icons. If the icon is null, then the "regular" version of the button is created.

## Tests
 - Added tests for all four constructors.
2024-02-01 00:24:54 +00:00