-
Notifications
You must be signed in to change notification settings - Fork 2k
Fix Shell.Background not working #35491
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
Changes from all commits
49082c6
07af7a9
0145fb1
c675ec9
e7b34fa
ddf56f1
8822b26
e38f562
489578c
e877052
663dd74
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,4 +1,5 @@ | ||
| #nullable disable | ||
| using System; | ||
| using Android.Graphics.Drawables; | ||
| using AndroidX.AppCompat.Widget; | ||
| using Microsoft.Maui.Controls.Handlers.Compatibility; | ||
|
|
@@ -26,18 +27,22 @@ public virtual void SetAppearance(AToolbar toolbar, IShellToolbarTracker toolbar | |
| } | ||
|
|
||
| var foreground = appearance.ForegroundColor; | ||
| var background = appearance.BackgroundColor; | ||
| var background = !Brush.IsNullOrEmpty(appearance.Background) | ||
| ? appearance.Background | ||
| : appearance.BackgroundColor is not null | ||
| ? new SolidColorBrush(appearance.BackgroundColor) | ||
| : null; | ||
| var titleColor = appearance.TitleColor; | ||
|
|
||
| SetColors(toolbar, toolbarTracker, foreground, background, titleColor); | ||
| } | ||
|
|
||
| public virtual void ResetAppearance(AToolbar toolbar, IShellToolbarTracker toolbarTracker) | ||
| { | ||
| SetColors(toolbar, toolbarTracker, ShellRenderer.DefaultForegroundColor, ShellRenderer.DefaultBackgroundColor, ShellRenderer.DefaultTitleColor); | ||
| SetColors(toolbar, toolbarTracker, ShellRenderer.DefaultForegroundColor, new SolidColorBrush(ShellRenderer.DefaultBackgroundColor), ShellRenderer.DefaultTitleColor); | ||
| } | ||
|
|
||
| protected virtual void SetColors(AToolbar toolbar, IShellToolbarTracker toolbarTracker, Color foreground, Color background, Color title) | ||
| protected virtual void SetColors(AToolbar toolbar, IShellToolbarTracker toolbarTracker, Color foreground, Brush background, Color title) | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
This changes the shipped This is intentional and correctly tracked, targets (found by: gemini-3.1-pro-preview, claude-opus-4.8)
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. [major] Public API Surface — This changes the shipped protected virtual
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Addressed the concern
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. [major] Public API Surface / Backward Compatibility — Changing this protected virtual from
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
[major] Backward Compatibility / Handler Mapper — |
||
| { | ||
| if (_disposed) | ||
| return; | ||
|
|
@@ -48,10 +53,16 @@ protected virtual void SetColors(AToolbar toolbar, IShellToolbarTracker toolbarT | |
| return; | ||
|
|
||
| shellToolbar.BarTextColor = title ?? ShellRenderer.DefaultTitleColor; | ||
| shellToolbar.BarBackground = new SolidColorBrush(background ?? ShellRenderer.DefaultBackgroundColor); | ||
| shellToolbar.BarBackground = background ?? new SolidColorBrush(ShellRenderer.DefaultBackgroundColor); | ||
| shellToolbar.IconColor = foreground ?? ShellRenderer.DefaultForegroundColor; | ||
| } | ||
|
|
||
| [Obsolete("Use SetColors(AToolbar, IShellToolbarTracker, Color, Brush, Color) instead.")] | ||
| protected virtual void SetColors(AToolbar toolbar, IShellToolbarTracker toolbarTracker, Color foreground, Color background, Color title) | ||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
[major] Backward Compatibility / Handler Mapper — |
||
| { | ||
| SetColors(toolbar, toolbarTracker, foreground, background is not null ? new SolidColorBrush(background) : null, title); | ||
| } | ||
|
|
||
| #region IDisposable | ||
|
|
||
| public void Dispose() | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -131,11 +131,26 @@ void UpdateiOS13NavigationBarAppearance(UINavigationController controller, Shell | |
| navBar.TintColor = _defaultTint; | ||
| } | ||
|
|
||
| // Set BackgroundColor | ||
| var background = appearance.BackgroundColor; | ||
|
|
||
| if (background != null) | ||
| navigationBarAppearance.BackgroundColor = background.ToPlatform(); | ||
| // Set Background (prefer Brush over Color for gradient support) | ||
|
sheiksyedm marked this conversation as resolved.
|
||
| if (!Brush.IsNullOrEmpty(appearance.Background)) | ||
|
sheiksyedm marked this conversation as resolved.
sheiksyedm marked this conversation as resolved.
sheiksyedm marked this conversation as resolved.
sheiksyedm marked this conversation as resolved.
|
||
| { | ||
| if (appearance.Background is SolidColorBrush solidBrush && solidBrush.Color is not null) | ||
| { | ||
| navigationBarAppearance.BackgroundColor = solidBrush.Color.ToPlatform(); | ||
| } | ||
| else | ||
| { | ||
| var backgroundImage = navBar.GetBackgroundImage(appearance.Background); | ||
|
sheiksyedm marked this conversation as resolved.
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. ❌ iOS Shell rendering — The gradient image is rendered once from the nav bar's current bounds, but
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. [major] iOS/MacCatalyst Platform Specifics —
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
[major] iOS Layout / Navigation & Shell — The gradient is rendered once from
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
[major] Layout Timing / Gradient Rendering — |
||
| if (backgroundImage is not null) | ||
| { | ||
| navigationBarAppearance.BackgroundImage = backgroundImage; | ||
| } | ||
| } | ||
| } | ||
| else if (appearance.BackgroundColor is not null) | ||
| { | ||
| navigationBarAppearance.BackgroundColor = appearance.BackgroundColor.ToPlatform(); | ||
| } | ||
|
|
||
| // Set TitleColor | ||
| var titleColor = appearance.TitleColor; | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -184,10 +184,9 @@ public static void UpdateBarBackground(this AToolbar nativeToolbar, Toolbar tool | |
| } | ||
| else | ||
| { | ||
| nativeToolbar.BackgroundTintMode = null; | ||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
[major] Android Toolbar Rendering — This |
||
| nativeToolbar.BackgroundTintList = null; | ||
| nativeToolbar.UpdateBackground(barBackground); | ||
|
|
||
| if (Brush.IsNullOrEmpty(barBackground)) | ||
| nativeToolbar.BackgroundTintMode = null; | ||
| } | ||
| } | ||
|
|
||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,4 +1,5 @@ | ||
| #nullable enable | ||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
[moderate] Build & Public API — This file was rewritten with a UTF-8 BOM ( |
||
| *REMOVED*~static Microsoft.Maui.Controls.VisualStateManager.GetVisualStateGroups(Microsoft.Maui.Controls.VisualElement visualElement) -> System.Collections.Generic.IList<Microsoft.Maui.Controls.VisualStateGroup> | ||
| Microsoft.Maui.Controls.Window.StatusBarTheme.get -> Microsoft.Maui.StatusBarTheme | ||
| Microsoft.Maui.Controls.Window.StatusBarTheme.set -> void | ||
| static readonly Microsoft.Maui.Controls.Window.StatusBarThemeProperty -> Microsoft.Maui.Controls.BindableProperty! | ||
|
|
@@ -115,7 +116,6 @@ static Microsoft.Maui.Controls.ViewExtensions.ScaleXToAsync(this Microsoft.Maui. | |
| static Microsoft.Maui.Controls.ViewExtensions.ScaleYToAsync(this Microsoft.Maui.Controls.VisualElement! view, double scale, uint length, Microsoft.Maui.Easing? easing, System.Threading.CancellationToken cancellationToken) -> System.Threading.Tasks.Task<bool>! | ||
| static Microsoft.Maui.Controls.ViewExtensions.TranslateToAsync(this Microsoft.Maui.Controls.VisualElement! view, double x, double y, uint length, Microsoft.Maui.Easing? easing, System.Threading.CancellationToken cancellationToken) -> System.Threading.Tasks.Task<bool>! | ||
| ~static Microsoft.Maui.Controls.VisualStateManager.GetVisualStateGroups(Microsoft.Maui.Controls.VisualElement visualElement) -> Microsoft.Maui.Controls.VisualStateGroupList | ||
| *REMOVED*~static Microsoft.Maui.Controls.VisualStateManager.GetVisualStateGroups(Microsoft.Maui.Controls.VisualElement visualElement) -> System.Collections.Generic.IList<Microsoft.Maui.Controls.VisualStateGroup> | ||
| ~static Microsoft.Maui.Controls.VisualStateManager.InvalidateVisualStates(Microsoft.Maui.Controls.VisualElement visualElement) -> void | ||
| static Microsoft.Maui.Controls.Xaml.Diagnostics.HotReloadDiagnostics.CurrentVersion.get -> int | ||
| static Microsoft.Maui.Controls.Xaml.Diagnostics.HotReloadDiagnostics.UpdateApplied -> System.EventHandler<Microsoft.Maui.Controls.Xaml.Diagnostics.HotReloadAppliedEventArgs!>? | ||
|
|
@@ -140,6 +140,10 @@ static readonly Microsoft.Maui.Controls.TitleBar.TitleFontAttributesProperty -> | |
| ~static readonly Microsoft.Maui.Controls.ToolbarItem.BadgeColorProperty -> Microsoft.Maui.Controls.BindableProperty | ||
| ~static readonly Microsoft.Maui.Controls.ToolbarItem.BadgeTextColorProperty -> Microsoft.Maui.Controls.BindableProperty | ||
| ~static readonly Microsoft.Maui.Controls.ToolbarItem.BadgeTextProperty -> Microsoft.Maui.Controls.BindableProperty | ||
| ~Microsoft.Maui.Controls.ShellAppearance.Background.get -> Microsoft.Maui.Controls.Brush | ||
| ~static Microsoft.Maui.Controls.Shell.GetBackground(Microsoft.Maui.Controls.BindableObject obj) -> Microsoft.Maui.Controls.Brush | ||
| ~static Microsoft.Maui.Controls.Shell.SetBackground(Microsoft.Maui.Controls.BindableObject obj, Microsoft.Maui.Controls.Brush value) -> void | ||
| ~static readonly Microsoft.Maui.Controls.Shell.BackgroundProperty -> Microsoft.Maui.Controls.BindableProperty | ||
| override Microsoft.Maui.Controls.BindablePropertyConverter.CanConvertFrom(System.ComponentModel.ITypeDescriptorContext? context, System.Type! sourceType) -> bool | ||
| override Microsoft.Maui.Controls.BindablePropertyConverter.CanConvertTo(System.ComponentModel.ITypeDescriptorContext? context, System.Type? destinationType) -> bool | ||
| override Microsoft.Maui.Controls.BindablePropertyConverter.ConvertFrom(System.ComponentModel.ITypeDescriptorContext? context, System.Globalization.CultureInfo? culture, object! value) -> object? | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -479,6 +479,13 @@ static void OnFlyoutBehaviorChanged(BindableObject bindable, object oldValue, ob | |
| BindableProperty.CreateAttached("UnselectedColor", typeof(Color), typeof(Shell), null, | ||
| propertyChanged: OnShellAppearanceValueChanged); | ||
|
|
||
| /// <summary> | ||
| /// Defines the background brush for the Shell toolbar. Supports gradient brushes. | ||
| /// </summary> | ||
| public static readonly new BindableProperty BackgroundProperty = | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Concrete footgun verified at HEAD: This is the dominant unresolved item on the PR (already raised in the PR discussion and a prior net11 fleet-review). It is an API-design decision that should go through API review before shipping, even on net11.0. Consider honoring/reusing (found by: gpt-5.5, claude-opus-4.6, claude-opus-4.8)
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This follows the existing Shell pattern — Shell.BackgroundColorProperty (line 467) also uses public static readonly new to shadow VisualElement.BackgroundColorProperty. The same attached-vs-instance split already exists for BackgroundColor. This is established Shell architecture, not new to this PR.
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. [major] Public API Surface — This adds public
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Addressed the concern
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. ❌ Public API baselines — Adding |
||
| BindableProperty.CreateAttached("Background", typeof(Brush), typeof(Shell), Brush.Default, | ||
| propertyChanged: OnShellAppearanceValueChanged); | ||
|
Comment on lines
+482
to
+487
|
||
|
|
||
| /// <summary> | ||
| /// The backdrop of the flyout, which is the appearance of the flyout overlay. | ||
| /// </summary> | ||
|
|
@@ -663,6 +670,20 @@ static void OnFlyoutBehaviorChanged(BindableObject bindable, object oldValue, ob | |
| /// <param name="value">The brushed used in the backdrop of the flyout.</param> | ||
| public static void SetFlyoutBackdrop(BindableObject obj, Brush value) => obj.SetValue(FlyoutBackdropProperty, value); | ||
|
|
||
| /// <summary> | ||
| /// Gets the background brush for the Shell toolbar. | ||
| /// </summary> | ||
| /// <param name="obj">The object from which to get the background brush.</param> | ||
| /// <returns>The background brush for the Shell toolbar.</returns> | ||
| public static Brush GetBackground(BindableObject obj) => (Brush)obj.GetValue(BackgroundProperty); | ||
|
|
||
| /// <summary> | ||
| /// Sets the background brush for the Shell toolbar. | ||
| /// </summary> | ||
| /// <param name="obj">The object on which to set the background brush.</param> | ||
| /// <param name="value">The brush to use as the Shell toolbar background.</param> | ||
| public static void SetBackground(BindableObject obj, Brush value) => obj.SetValue(BackgroundProperty, value); | ||
|
|
||
| static void OnShellAppearanceValueChanged(BindableObject bindable, object oldValue, object newValue) | ||
| { | ||
| var item = (Element)bindable; | ||
|
|
@@ -766,7 +787,14 @@ void UpdateToolbarAppearanceFeatures(Element pivot, ShellAppearance appearance) | |
| { | ||
| appearance = appearance ?? GetAppearanceForPivot(pivot); | ||
| Toolbar.BarTextColor = appearance?.TitleColor ?? DefaultTitleColor; | ||
| Toolbar.BarBackground = appearance?.BackgroundColor ?? DefaultBackgroundColor; | ||
| if (!Brush.IsNullOrEmpty(appearance?.Background)) | ||
| { | ||
| Toolbar.BarBackground = appearance.Background; | ||
| } | ||
| else | ||
| { | ||
| Toolbar.BarBackground = appearance?.BackgroundColor ?? DefaultBackgroundColor; | ||
| } | ||
| Toolbar.IconColor = appearance?.ForegroundColor ?? DefaultForegroundColor; | ||
| } | ||
| } | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,45 @@ | ||
| namespace Maui.Controls.Sample.Issues; | ||
|
|
||
| [Issue(IssueTracker.Github, 10445, "Shell.Background does not support gradient brushes", PlatformAffected.All)] | ||
| public class Issue10445 : TestShell | ||
| { | ||
| protected override void Init() | ||
| { | ||
| FlyoutBehavior = FlyoutBehavior.Disabled; | ||
| var gradientBrush = new LinearGradientBrush | ||
| { | ||
| StartPoint = new Point(0, 0), | ||
| EndPoint = new Point(1, 1), | ||
| GradientStops = new GradientStopCollection | ||
| { | ||
| new GradientStop(Colors.Yellow, 0.0f), | ||
| new GradientStop(Colors.Green, 1.0f) | ||
| } | ||
| }; | ||
|
|
||
| Shell.SetBackground(this, gradientBrush); | ||
|
|
||
| var page = new ContentPage | ||
| { | ||
| Title = "Gradient Shell", | ||
| Content = new VerticalStackLayout | ||
| { | ||
| Padding = 20, | ||
| Spacing = 10, | ||
| VerticalOptions = LayoutOptions.Center, | ||
| HorizontalOptions = LayoutOptions.Center, | ||
| Children = | ||
| { | ||
| new Label | ||
| { | ||
| Text = "Shell.Background should display a gradient (Yellow to Green) in the navigation bar above.", | ||
| AutomationId = "GradientInfoLabel", | ||
| HorizontalTextAlignment = TextAlignment.Center | ||
| } | ||
| } | ||
| } | ||
| }; | ||
|
|
||
| AddContentPage(page, "Home"); | ||
| } | ||
| } |
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.
This changes the
protected virtualsignature fromColor backgroundtoBrush background. It is correctly tracked in PublicAPI with a*REMOVED*/added pair and is reasonable for the net11.0 target, but it is binary/source-breaking for subclasses that override the oldColoroverload: after this changeSetAppearancecalls theBrushoverload, so an existing override of theColoroverload silently stops being invoked. Worth confirming during API review that dropping the old overload (vs. keeping it as an[Obsolete]overload that delegates to the new one) is the intended net11 break — this is the kind of decision that pairs with the broaderShell.BackgroundAPI-design discussion on this PR.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 flagging this! Yes, this is an intentional change for .NET 11 — we've updated the signature from Color to Brush to enable gradient background support. It's properly tracked in PublicAPI.Unshipped.txt with the REMOVED/added pair. For anyone with a custom subclass overriding the old Color overload, the migration is straightforward — just update the parameter type to Brush. Happy to discuss further if there are concerns!