-
Notifications
You must be signed in to change notification settings - Fork 28.9k
BottomAppBar: Fix doubled layers of color and shadow #123294
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
BottomAppBar: Fix doubled layers of color and shadow #123294
Conversation
It's now a bit easier to read complete pictures of the Material 3 behavior and of the Material 2 behavior. Soon we'll remove the PhysicalShape widget from the Material 3 case entirely -- its job isn't needed in Material 3 because the bottom app bar's "notched" shape isn't part of the spec anymore: https://m3.material.io/components/bottom-app-bar/specs
Fixes flutter#123283. Fixes flutter#122667. Fixes flutter#123064. The Material 3 spec removes the "notched" shape for bottom app bars that was present Material 2: https://m3.material.io/components/bottom-app-bar/specs So, remove the `PhysicalShape` widget that was providing that notched shape, and throw if callers in Material 3 ask for a notch. Callers expecting a notch with Material 3 will have been disappointed since da7b832, when the `Material` widget (which doesn't support a notch) started painting its background color through any notch provided by the `PhysicalShape` widget. This is issue flutter#123283. As a bonus, this fixes some bugs observed in Material 3 that were invited by BottomAppBar's two-layer implementation (the `PhysicalShape` and the `Material`): - flutter#122667, "BottomAppBar: Material 3 makes the color too opaque" - flutter#123064, "BottomAppBar: Elevation effect (shadow) doubled in Material 3"
Done by removing the line in bottom_app_bar_template.dart then: dart dev/tools/gen_defaults/bin/gen_defaults.dart and undoing some unrelated-looking changes that made in these files: packages/flutter/lib/src/material/bottom_sheet.dart packages/flutter/lib/src/material/search_anchor.dart
`Material.surfaceTintColor` is ignored in Material 2. From the doc: https://github.com/flutter/flutter/blob/2ad6cd72c0/packages/flutter/lib/src/material/material.dart#L283 > If [ThemeData.useMaterial3] is false, then this property is not used. It was added for Material 3 support in 6a66aa2.
…terial We already pass these to the `PhysicalShape`; the transparent Material doesn't need them too. As noted in flutter#123064 (comment) , I don't think this redundancy in the Material 2 case has actually caused a bug where an elevation effect gets doubled, because: - A `Material` with `type: MaterialType.transparency` doesn't display a shadow: https://github.com/flutter/flutter/blob/f4c3facfd/packages/flutter/lib/src/material/material.dart#L522-L529 - `BottomAppBar` tries to apply an elevation overlay effect using `color` (with `ElevationOverlay.applyOverlay`), but `color` gets ignored by `Material` if `type` is `MaterialType.transparency`: https://github.com/flutter/flutter/blob/f4c3facfd/packages/flutter/lib/src/material/material.dart#L522-L529 Still, that's not trivial to verify, and it's more confusing to keep passing these arguments. (Note that this addresses the Material 2 case. In a recent commit, we removed the `PhysicalShape` in the Material 3 case, fixing some live bugs where some effects had in fact been duplicated by the presence of the `PhysicalShape` together with the `Material`.)
child = PhysicalShape( | ||
clipper: clipper, | ||
elevation: elevation, | ||
shadowColor: shadowColor, | ||
color: ElevationOverlay.applyOverlay(context, color, elevation), | ||
clipBehavior: widget.clipBehavior, | ||
child: Material( | ||
key: materialKey, | ||
type: MaterialType.transparency, | ||
child: SafeArea(child: child), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for the fix! Generally this looks good.
@@ -174,6 +189,8 @@ class _BottomAppBarState extends State<BottomAppBar> { | |||
Widget build(BuildContext context) { | |||
final ThemeData theme = Theme.of(context); | |||
final bool isMaterial3 = theme.useMaterial3; | |||
assert(!isMaterial3 || widget.shape == null); // `shape` not accepted in Material 3 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The information in the comment should go in an assertion message instead, so the developer sees it when they hit the assertion. For example:
assert(!isMaterial3 || widget.shape == null); // `shape` not accepted in Material 3 | |
assert(!isMaterial3 || widget.shape == null, | |
'The [BottomAppBar.shape] field is not permitted in Material 3.'); |
(Could also throw a FlutterError
for a fancier error message, but this might be enough.)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If throwing a FlutterError
, would we want to do that in production too? AIUI assert
s only throw in debug mode.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
No, the check and the throw would both go inside an assert
. For example, here's [State.context]:
BuildContext get context {
assert(() {
if (_element == null) {
throw FlutterError(
'This widget has been unmounted, so the State no longer has a context (and should be considered defunct). \n'
'Consider canceling any active work during "dispose" or using the "mounted" getter to determine if the State is still active.',
);
}
return true;
}());
return _element!;
}
Thanks for the review, @gnprice! Changes pushed; PTAL. 🙂 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM! One nit.
Thanks for the review! Fix pushed. |
I'm reworking this following @HansMuller's comment at #123283 (comment):
|
This pull request has been changed to a draft. The currently pending flutter-gold status will not be able to resolve until a new commit is pushed or the change is marked ready for review again. For more guidance, visit Writing a golden file test for Reviewers: Read the Tree Hygiene page and make sure this patch meets those guidelines before LGTMing. |
Sounds good, I'm happy to give a secondary review when this is back out of draft mode. Edit: By the way, the Google testing failures look like there's a small pixel difference at the right edge of the BottomAppBar in some image diff tests. Likely it's intended, but I'll take another look after the PR is updated. |
Thanks for the review!
Done. |
Google testing failed. This is likely the same failures @justinmc mentioned above:
Customer testing also failed, in a way unrelated to this PR: #123385 |
@chrisbobbe Can you merge master into this PR? That will fix the customer tests and update the Google tests so I can take a look. |
Sure! Done. |
Thanks, looks like the customer tests are fixed. I'll check on the Google tests next week. |
The Google test failure looks unrelated... Can you try pushing another merge commit? Sorry for all the headache with this. |
Sure, no problem! Done. |
Hmm, Google testing is still showing as "pending" after 7+ hours. Could be #123289? This time I'm going to try and see if I can update the branch without leaving GitHub's UI. There's a helpful-looking "Update branch" button that I'm going to click now. (If that does something wrong, I can always reset the branch back to b084982, my merge commit from earlier today.) |
@XilaiZhang - apparently this PR has failed "Google Testng" however the details link doesn't reveal anything: "There is no unmerged PR.". I tried the "Test a PR" button to start another test and that failed with: How can we move the process along? |
temp workaround: the test failures are at test/521647510 and the cl is cl/521647510 Thanks for reporting the issue! will keep track of it in b/260764527 |
The Google testing failures don't appear to have anything to do with this PR. Will try updating the branch... |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM 👍
I think that Google testing is broken right now, so we'll have to try pushing another merge commit in a day or so when it's fixed.
@@ -33,7 +33,8 @@ import 'theme.dart'; | |||
/// {@end-tool} | |||
/// | |||
/// {@tool dartpad} | |||
/// This example shows the [BottomAppBar], which can be configured to have a notch using the | |||
/// This example shows the [BottomAppBar], which (in Material 2) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
As mentioned in #123283 (comment) we ideally want to keep the ability to have a notch with useMaterial3: true
. I'm guessing but I imagine there will be a significant amount of people that want a Material 3-looking app with a notch.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ah, this is already addressed in this revision (I suspect your review-draft crossed with my sending that new revision). I've updated the PR description to match this revision. 🙂
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks, yeah this review was messed up somehow...
@@ -218,19 +284,18 @@ void main() { | |||
), | |||
bottomNavigationBar: BottomAppBar( | |||
color: Color(0xff0000ff), | |||
surfaceTintColor: Colors.transparent, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Could you file a new issue about the docs being wrong?
Thanks for the review!
Sure, I'll try that now. |
Thanks for pushing the merge commit. It looks like there are real Google test failures, but they are just nearly invisible image diffs due to the changes here. I've accepted the changes and should be able to merge this soon. |
Thanks @justinmc and everyone for your help in taking care of Google testing! |
Yeah, thanks all! 🎉 |
Fixes BottomAppBar with translucent colors.
Fixes #123283.
Fixes #122667.
Fixes #123064.
(EDITED for the current revision, following #123283 (comment).)
The
BottomAppBar
implementation uses both aMaterial
and aPhysicalShape
because it needs them both in order to support the "notch" for a FAB in Material 2.In the current version of the Material 3 support, it ends up putting a color and shadow on both of these, so that there are two color layers and two shadows. This gives wrong results when the color is translucent: #122667, #123064.
Also in Material 3, it doesn't work right if you ask for a notch, because the
Material
paints through the notch: #123283. (The Material 3 spec doesn't allow for a notch in the bottom app bar, but we plan to support one anyway: #123283 (comment).)So, fix these bugs by making the
Material
transparent (and without overlay or shadow, usingMaterialType.transparency
), like we do in Material 2.Pre-launch Checklist
///
).If you need help, consider asking for advice on the #hackers-new channel on Discord.