diff --git a/.github/copilot-instructions.md b/.github/copilot-instructions.md index 934fe7623e1d..c2d342fc8af4 100644 --- a/.github/copilot-instructions.md +++ b/.github/copilot-instructions.md @@ -200,20 +200,6 @@ git commit -m "Fix: Description of the change" - `.github/instructions/android.instructions.md` - Android handler implementation - `.github/instructions/xaml-unittests.instructions.md` - XAML unit test guidelines -### Opening PRs - -All PRs are required to have this at the top of the description: - -``` - -> [!NOTE] -> Are you waiting for the changes in this PR to be merged? -> It would be very helpful if you could [test the resulting artifacts](https://github.com/dotnet/maui/wiki/Testing-PR-Builds) from this PR and let us know in a comment if this change resolves your issue. Thank you! -``` - -Always put that at the top, without the block quotes. Without it, users will NOT be able to try the PR and your work will have been in vain! - - ## Custom Agents and Skills diff --git a/.github/skills/pr-finalize/SKILL.md b/.github/skills/pr-finalize/SKILL.md index 28ba6916dd8b..9932ac6534c5 100644 --- a/.github/skills/pr-finalize/SKILL.md +++ b/.github/skills/pr-finalize/SKILL.md @@ -127,16 +127,10 @@ Examples: ## Description Requirements PR description should: -1. Start with the required NOTE block (so users can test PR artifacts) -2. Include the base sections from `.github/PULL_REQUEST_TEMPLATE.md` ("Description of Change" and "Issues Fixed"). The skill adds additional structured fields (Root cause, Fix, Key insight, etc.) as recommended enhancements for better agent context. -3. Match the actual implementation +1. Include the base sections from `.github/PULL_REQUEST_TEMPLATE.md` ("Description of Change" and "Issues Fixed"). The skill adds additional structured fields (Root cause, Fix, Key insight, etc.) as recommended enhancements for better agent context. +2. Match the actual implementation ```markdown - -> [!NOTE] -> Are you waiting for the changes in this PR to be merged? -> It would be very helpful if you could [test the resulting artifacts](https://github.com/dotnet/maui/wiki/Testing-PR-Builds) from this PR and let us know in a comment if this change resolves your issue. Thank you! - ### Description of Change [Must match actual implementation] @@ -229,11 +223,6 @@ Example: "Before: Safe area applied by default (opt-out). After: Only views impl Use structured template only when existing description is inadequate: ```markdown - -> [!NOTE] -> Are you waiting for the changes in this PR to be merged? -> It would be very helpful if you could [test the resulting artifacts](https://github.com/dotnet/maui/wiki/Testing-PR-Builds) from this PR and let us know in a comment if this change resolves your issue. Thank you! - ### Root Cause [Why the bug occurred - be specific about the code path] diff --git a/.github/skills/pr-finalize/references/complete-example.md b/.github/skills/pr-finalize/references/complete-example.md index 034da2e3d09d..6f8ff08d1006 100644 --- a/.github/skills/pr-finalize/references/complete-example.md +++ b/.github/skills/pr-finalize/references/complete-example.md @@ -9,10 +9,6 @@ This example shows a PR description optimized for future agent success. ## Description ```markdown -> [!NOTE] -> Are you waiting for the changes in this PR to be merged? -> It would be very helpful if you could [test the resulting artifacts](https://github.com/dotnet/maui/wiki/Testing-PR-Builds) from this PR and let us know in a comment if this change resolves your issue. Thank you! - ### Root Cause In `MauiView.GetAdjustedSafeAreaInsets()` on iOS, views that don't implement `ISafeAreaView` or `ISafeAreaView2` (such as `ContentPresenter`, `Border`) were falling through to return `baseSafeArea`. This applied full device safe area insets to views that never opted into safe area handling, causing double-padding when used inside ControlTemplates. diff --git a/eng/pipelines/common/ui-tests-steps.yml b/eng/pipelines/common/ui-tests-steps.yml index e3c1186e329c..b5b2a8f79a8a 100644 --- a/eng/pipelines/common/ui-tests-steps.yml +++ b/eng/pipelines/common/ui-tests-steps.yml @@ -186,6 +186,8 @@ steps: - task: PublishBuildArtifacts@1 condition: always() displayName: publish artifacts + inputs: + artifactName: drop-$(System.StageName)-$(System.JobName)-$(System.JobAttempt) # Enable Notification Center re-enabled only for catalyst - ${{ if eq(parameters.platform, 'catalyst')}}: diff --git a/eng/pipelines/common/ui-tests.yml b/eng/pipelines/common/ui-tests.yml index fe1231c2292c..258ab00de3e7 100644 --- a/eng/pipelines/common/ui-tests.yml +++ b/eng/pipelines/common/ui-tests.yml @@ -24,7 +24,7 @@ parameters: - 'Cells,CheckBox,ContextActions,CustomRenderers,DatePicker,Dispatcher,DisplayAlert,DisplayPrompt,DragAndDrop' - 'CollectionView' - 'Entry' - - 'Editor,Effects,FlyoutPage,Focus,Fonts,Frame,Gestures,GraphicsView' + - 'Editor,Effects,Essentials,FlyoutPage,Focus,Fonts,Frame,Gestures,GraphicsView' - 'Image,ImageButton,IndicatorView,InputTransparent,IsEnabled,IsVisible' - 'Label' - 'Layout' @@ -38,8 +38,8 @@ parameters: - 'SearchBar,Shape,Slider' - 'SoftInput,Stepper,Switch,SwipeView' - 'Shell' - - 'TabbedPage,TableView,TimePicker,TitleView,ToolbarItem' - - 'ViewBaseTests,Window' + - 'TabbedPage,TableView,TimePicker,TitleView,ToolbarItem,Triggers' + - 'ViewBaseTests,VisualStateManager,Window' - 'WebView' projects: diff --git a/src/BlazorWebView/src/Maui/BlazorWebView.cs b/src/BlazorWebView/src/Maui/BlazorWebView.cs index 15922e86b364..d54ee207cf77 100644 --- a/src/BlazorWebView/src/Maui/BlazorWebView.cs +++ b/src/BlazorWebView/src/Maui/BlazorWebView.cs @@ -1,5 +1,6 @@ using System; using System.Threading.Tasks; +using System.Runtime.Versioning; using Microsoft.AspNetCore.Components.Web; using Microsoft.Extensions.FileProviders; using Microsoft.Maui; @@ -10,8 +11,24 @@ namespace Microsoft.AspNetCore.Components.WebView.Maui /// /// A that can render Blazor content. /// +#if ANDROID + [SupportedOSPlatform(AndroidSupportedOSPlatformVersion)] +#elif IOS + [SupportedOSPlatform(iOSSupportedOSPlatformVersion)] +#elif MACCATALYST + [SupportedOSPlatform(MacCatalystSupportedOSPlatformVersion)] +#endif public partial class BlazorWebView : View, IBlazorWebView { + // NOTE: keep these in *reasonably* in sync with: + // * src\BlazorWebView\src\Maui\Microsoft.AspNetCore.Components.WebView.Maui.csproj + // * src\Templates\src\templates\maui-blazor\MauiApp.1.csproj + // * src\Templates\src\templates\maui-blazor-solution\MauiApp.1\MauiApp.1.csproj + // * https://learn.microsoft.com/dotnet/maui/supported-platforms + internal const string AndroidSupportedOSPlatformVersion = "android24.0"; + internal const string iOSSupportedOSPlatformVersion = "ios15.0"; + internal const string MacCatalystSupportedOSPlatformVersion = "maccatalyst15.0"; + internal static string AppHostAddress { get; } = HostAddressHelper.GetAppHostAddress(); private readonly JSComponentConfigurationStore _jSComponents = new(); @@ -80,9 +97,11 @@ public string StartPath /// #if ANDROID - [System.Runtime.Versioning.SupportedOSPlatform("android23.0")] + [System.Runtime.Versioning.SupportedOSPlatform(AndroidSupportedOSPlatformVersion)] #elif IOS - [System.Runtime.Versioning.SupportedOSPlatform("ios11.0")] + [System.Runtime.Versioning.SupportedOSPlatform(iOSSupportedOSPlatformVersion)] +#elif MACCATALYST + [System.Runtime.Versioning.SupportedOSPlatform(MacCatalystSupportedOSPlatformVersion)] #endif public virtual IFileProvider CreateFileProvider(string contentRootDir) { @@ -97,7 +116,11 @@ public virtual IFileProvider CreateFileProvider(string contentRootDir) /// Returns a representing true if the was called, or false if it was not called because Blazor is not currently running. /// Thrown if is null. #if ANDROID - [System.Runtime.Versioning.SupportedOSPlatform("android23.0")] + [System.Runtime.Versioning.SupportedOSPlatform(AndroidSupportedOSPlatformVersion)] +#elif IOS + [System.Runtime.Versioning.SupportedOSPlatform(iOSSupportedOSPlatformVersion)] +#elif MACCATALYST + [System.Runtime.Versioning.SupportedOSPlatform(MacCatalystSupportedOSPlatformVersion)] #endif public virtual async Task TryDispatchAsync(Action workItem) { diff --git a/src/BlazorWebView/src/Maui/BlazorWebViewHandler.cs b/src/BlazorWebView/src/Maui/BlazorWebViewHandler.cs index 052a96f5586f..df638d6d7cd1 100644 --- a/src/BlazorWebView/src/Maui/BlazorWebViewHandler.cs +++ b/src/BlazorWebView/src/Maui/BlazorWebViewHandler.cs @@ -9,7 +9,11 @@ namespace Microsoft.AspNetCore.Components.WebView.Maui { #if ANDROID - [SupportedOSPlatform("android23.0")] + [SupportedOSPlatform(BlazorWebView.AndroidSupportedOSPlatformVersion)] +#elif IOS + [SupportedOSPlatform(BlazorWebView.iOSSupportedOSPlatformVersion)] +#elif MACCATALYST + [SupportedOSPlatform(BlazorWebView.MacCatalystSupportedOSPlatformVersion)] #endif public partial class BlazorWebViewHandler { diff --git a/src/BlazorWebView/src/Maui/Microsoft.AspNetCore.Components.WebView.Maui.csproj b/src/BlazorWebView/src/Maui/Microsoft.AspNetCore.Components.WebView.Maui.csproj index d4268f64fa8f..115ba0586b46 100644 --- a/src/BlazorWebView/src/Maui/Microsoft.AspNetCore.Components.WebView.Maui.csproj +++ b/src/BlazorWebView/src/Maui/Microsoft.AspNetCore.Components.WebView.Maui.csproj @@ -23,6 +23,10 @@ $(DefaultPackageTags);blazor;webview;aspnet $(MauiRootDirectory)Assets\aspnet-icon.png Build .NET Multi-platform App UI (.NET MAUI) apps with Blazor web UI in the BlazorWebView control. + + 15.0 + 15.0 + 24.0 diff --git a/src/BlazorWebView/src/SharedSource/BlazorWebViewServiceCollectionExtensions.cs b/src/BlazorWebView/src/SharedSource/BlazorWebViewServiceCollectionExtensions.cs index b7b0c748177d..a83a5e187c3c 100644 --- a/src/BlazorWebView/src/SharedSource/BlazorWebViewServiceCollectionExtensions.cs +++ b/src/BlazorWebView/src/SharedSource/BlazorWebViewServiceCollectionExtensions.cs @@ -30,9 +30,11 @@ public static IWindowsFormsBlazorWebViewBuilder AddWindowsFormsBlazorWebView(thi public static IWpfBlazorWebViewBuilder AddWpfBlazorWebView(this IServiceCollection services) #elif WEBVIEW2_MAUI #if ANDROID - [System.Runtime.Versioning.SupportedOSPlatform("android23.0")] + [System.Runtime.Versioning.SupportedOSPlatform(BlazorWebView.AndroidSupportedOSPlatformVersion)] #elif IOS - [System.Runtime.Versioning.SupportedOSPlatform("ios11.0")] + [System.Runtime.Versioning.SupportedOSPlatform(BlazorWebView.iOSSupportedOSPlatformVersion)] +#elif MACCATALYST + [System.Runtime.Versioning.SupportedOSPlatform(BlazorWebView.MacCatalystSupportedOSPlatformVersion)] #endif public static IMauiBlazorWebViewBuilder AddMauiBlazorWebView(this IServiceCollection services) #else diff --git a/src/Compatibility/Core/src/iOS/Renderers/NavigationRenderer.cs b/src/Compatibility/Core/src/iOS/Renderers/NavigationRenderer.cs index ae911866e9ad..09e30a6a4fa8 100644 --- a/src/Compatibility/Core/src/iOS/Renderers/NavigationRenderer.cs +++ b/src/Compatibility/Core/src/iOS/Renderers/NavigationRenderer.cs @@ -762,6 +762,11 @@ void UpdateBarTextColor() void SetStatusBarStyle() { + if (NavPage is null) + { + return; + } + var barTextColor = NavPage.BarTextColor; var statusBarColorMode = NavPage.OnThisPlatform().GetStatusBarTextColorMode(); diff --git a/src/Compatibility/Maps/src/Android/MapRenderer.cs b/src/Compatibility/Maps/src/Android/MapRenderer.cs index fe526759bf13..e0a18f5b2c6d 100644 --- a/src/Compatibility/Maps/src/Android/MapRenderer.cs +++ b/src/Compatibility/Maps/src/Android/MapRenderer.cs @@ -46,6 +46,7 @@ public class MapRenderer : Handlers.Compatibility.ViewRenderer, Go List _polylines; List _polygons; List _circles; + List _trackedMapElements; public MapRenderer(Context context) : base(context) { @@ -581,6 +582,16 @@ void MapElementCollectionChanged(NotifyCollectionChangedEventArgs e) AddMapElements(e.NewItems.Cast()); break; case NotifyCollectionChangedAction.Reset: + // Clear MapElementId from tracked elements (not Element.MapElements, + // which is already empty after ObservableCollection.Clear()) + if (_trackedMapElements != null) + { + foreach (var element in _trackedMapElements) + element.MapElementId = null; + + _trackedMapElements = null; + } + if (_polylines != null) { for (int i = 0; i < _polylines.Count; i++) @@ -612,8 +623,11 @@ void MapElementCollectionChanged(NotifyCollectionChangedEventArgs e) void AddMapElements(IEnumerable mapElements) { + _trackedMapElements ??= new List(); + foreach (var element in mapElements) { + _trackedMapElements.Add(element); element.PropertyChanged += MapElementPropertyChanged; switch (element) diff --git a/src/Compatibility/Maps/src/iOS/MapRenderer.cs b/src/Compatibility/Maps/src/iOS/MapRenderer.cs index c248128a451e..0bcdddc456a4 100644 --- a/src/Compatibility/Maps/src/iOS/MapRenderer.cs +++ b/src/Compatibility/Maps/src/iOS/MapRenderer.cs @@ -31,6 +31,7 @@ public class MapRenderer : Microsoft.Maui.Controls.Handlers.Compatibility.ViewRe bool _shouldUpdateRegion; object _lastTouchedView; bool _disposed; + List _trackedMapElements; #if __MOBILE__ UITapGestureRecognizer _mapClickedGestureRecognizer; @@ -528,6 +529,16 @@ void MapElementCollectionChanged(NotifyCollectionChangedEventArgs e) case NotifyCollectionChangedAction.Reset: var mkMapView = (MKMapView)Control; + // Clear MapElementId from tracked elements (not Element.MapElements, + // which is already empty after ObservableCollection.Clear()) + if (_trackedMapElements != null) + { + foreach (var mapElement in _trackedMapElements) + mapElement.MapElementId = null; + + _trackedMapElements = null; + } + if (mkMapView.Overlays != null) { var overlays = mkMapView.Overlays; @@ -544,8 +555,11 @@ void MapElementCollectionChanged(NotifyCollectionChangedEventArgs e) void AddMapElements(IEnumerable mapElements) { + _trackedMapElements ??= new List(); + foreach (var element in mapElements) { + _trackedMapElements.Add(element); element.PropertyChanged += MapElementPropertyChanged; IMKOverlay overlay = null; diff --git a/src/Controls/samples/Controls.Sample/Pages/Others/LargeTitlesPageiOS.cs b/src/Controls/samples/Controls.Sample/Pages/Others/LargeTitlesPageiOS.cs deleted file mode 100644 index e0ccaf46ba17..000000000000 --- a/src/Controls/samples/Controls.Sample/Pages/Others/LargeTitlesPageiOS.cs +++ /dev/null @@ -1,90 +0,0 @@ -using System.Linq; -using System.Windows.Input; -using Microsoft.Maui.Controls; -using Microsoft.Maui.Controls.PlatformConfiguration; -using Microsoft.Maui.Graphics; -using static Microsoft.Maui.Controls.PlatformConfiguration.iOSSpecific.NavigationPage; -using static Microsoft.Maui.Controls.PlatformConfiguration.iOSSpecific.Page; -using LargeTitleDisplayMode = Microsoft.Maui.Controls.PlatformConfiguration.iOSSpecific.LargeTitleDisplayMode; - -namespace Maui.Controls.Sample.Pages -{ - public class LargeTitlesPageiOS : ContentPage - { - public LargeTitlesPageiOS() - { - Title = "Large Titles"; - - var offscreenPageLimit = new Label(); - var content = new StackLayout - { - VerticalOptions = LayoutOptions.Fill, - HorizontalOptions = LayoutOptions.Fill, - Children = - { - new Button - { - Text = "LargeTitleDisplayMode.Never", - Command = new Command(() => On().SetLargeTitleDisplay(LargeTitleDisplayMode.Never)) - }, - new Button - { - Text = "LargeTitleDisplayMode.Always", - Command = new Command(() => On().SetLargeTitleDisplay(LargeTitleDisplayMode.Always)) - }, - new Button - { - Text = "LargeTitleDisplayMode.Automatic -> next page will have same LargeTitleDisplayMode as this one", - Command = new Command(async () =>{ - var page = new ContentPage { Title = "Page Title" }; - page.On().SetLargeTitleDisplay(LargeTitleDisplayMode.Automatic); - await Navigation.PushAsync(page); - } ) - }, - new Button - { - Text = "Tooggle UseLargeTitles on Navigation", - Command = new Command( () =>{ - var navPage = (NavigationPage)Parent; - navPage.On().SetPrefersLargeTitles(!navPage.On().PrefersLargeTitles()); - } ) - }, - - new Button - { - Text = "UseLargeTitles on Navigation with safe Area", - Command = new Command( () =>{ - var navPage = (NavigationPage)Parent; - navPage.On().SetPrefersLargeTitles(true); - var page = new ContentPage { Title = "New Title", BackgroundColor = Colors.Red }; - page.SafeAreaEdges = Microsoft.Maui.SafeAreaEdges.All; - var listView = new ListView(ListViewCachingStrategy.RecycleElementAndDataTemplate) - { - HasUnevenRows = true, - VerticalOptions = LayoutOptions.Fill - }; - - listView.ItemTemplate = new DataTemplate(()=>{ - var cell = new ViewCell(); - cell.View = new Label { Text ="Hello", FontSize = 30}; - return cell; - }); - listView.ItemsSource = Enumerable.Range(1, 40); - listView.Header = new Label { BackgroundColor = Colors.Pink , Text = "I'm a header, background is red"}; - listView.Footer = new Label { BackgroundColor = Colors.Yellow , Text = "I'm a footer, you should see no white below me"}; - page.Content = listView; - navPage.PushAsync(page); - } ) - }, - offscreenPageLimit - } - }; - - var restoreButton = new Button { Text = "Back To Gallery" }; - restoreButton.Clicked += async (sender, args) => await Navigation.PopAsync(); - content.Children.Add(restoreButton); - - Content = content; - } - } -} diff --git a/src/Controls/samples/Controls.Sample/Pages/PlatformSpecifics/iOS/iOSLargeTitlePage.cs b/src/Controls/samples/Controls.Sample/Pages/PlatformSpecifics/iOS/iOSLargeTitlePage.cs new file mode 100644 index 000000000000..22f70954eaae --- /dev/null +++ b/src/Controls/samples/Controls.Sample/Pages/PlatformSpecifics/iOS/iOSLargeTitlePage.cs @@ -0,0 +1,228 @@ +using System; +using System.Linq; +using Microsoft.Maui; +using Microsoft.Maui.Controls; +using Microsoft.Maui.Controls.PlatformConfiguration; +using Microsoft.Maui.Controls.PlatformConfiguration.iOSSpecific; +using Microsoft.Maui.Graphics; + +namespace Maui.Controls.Sample.Pages; + +public partial class iOSLargeTitlePage : ContentPage +{ + public iOSLargeTitlePage() + { + Title = "Large Titles"; + + // Set the parent NavigationPage's BarTextColor to black when this page appears + Appearing += (s, e) => + { + if (Parent is Microsoft.Maui.Controls.NavigationPage navPage) + { + navPage.BarTextColor = Colors.Black; + } + }; + + var scrollView = new Microsoft.Maui.Controls.ScrollView + { + Content = new StackLayout + { + Padding = new Thickness(10), + Spacing = 15, + Children = + { + // Display Mode Section + new Label + { + Text = "Display Mode", + FontSize = 20, + FontAttributes = FontAttributes.Bold, + Margin = new Thickness(0, 10, 0, 0) + }, + new Button + { + Text = "Never - Hide large title", + Command = new Command(() => On().SetLargeTitleDisplay(LargeTitleDisplayMode.Never)) + }, + new Button + { + Text = "Always - Show large title", + Command = new Command(() => On().SetLargeTitleDisplay(LargeTitleDisplayMode.Always)) + }, + new Button + { + Text = "Automatic - Inherit from previous page", + Command = new Command(async () => + { + var page = new ContentPage { Title = "Automatic Mode" }; + page.On().SetLargeTitleDisplay(LargeTitleDisplayMode.Automatic); + await Navigation.PushAsync(page); + }) + }, + + // Navigation Configuration Section + new BoxView { HeightRequest = 1, Color = Colors.Gray, Margin = new Thickness(0, 10) }, + new Label + { + Text = "Navigation Configuration", + FontSize = 20, + FontAttributes = FontAttributes.Bold + }, + new Button + { + Text = "Toggle PrefersLargeTitles on NavigationPage", + Command = new Command(async () => + { + var navPage = (Microsoft.Maui.Controls.NavigationPage)Parent; + navPage.On().SetPrefersLargeTitles(!navPage.On().PrefersLargeTitles()); + + // Refresh the page to show the change + Navigation.InsertPageBefore(new iOSLargeTitlePage(), this); + await Navigation.PopAsync(false); + }) + }, + + // Scrolling Behavior Section + new BoxView { HeightRequest = 1, Color = Colors.Gray, Margin = new Thickness(0, 10) }, + new Label + { + Text = "Scrolling Behavior", + FontSize = 20, + FontAttributes = FontAttributes.Bold + }, + new Button + { + Text = "ScrollView - Watch title collapse on scroll", + Command = new Command(async () => + { + var navPage = (Microsoft.Maui.Controls.NavigationPage)Parent; + navPage.On().SetPrefersLargeTitles(true); + + var page = new ContentPage { Title = "Scroll Me" }; + page.On().SetLargeTitleDisplay(LargeTitleDisplayMode.Always); + + var scrollContent = new StackLayout { Padding = 20, Spacing = 10 }; + for (int i = 1; i <= 50; i++) + { + scrollContent.Children.Add(new Label + { + Text = $"Item {i} - Scroll to see the large title collapse", + FontSize = 16, + Padding = new Thickness(0, 10) + }); + } + + page.Content = new Microsoft.Maui.Controls.ScrollView { Content = scrollContent }; + await Navigation.PushAsync(page); + }) + }, + new Button + { + Text = "CollectionView - Large title with SafeArea", + Command = new Command(async () => + { + var navPage = (Microsoft.Maui.Controls.NavigationPage)Parent; + navPage.On().SetPrefersLargeTitles(true); + + var page = new ContentPage { Title = "CollectionView Demo", BackgroundColor = Colors.LightBlue }; + page.On().SetLargeTitleDisplay(LargeTitleDisplayMode.Always); + page.SafeAreaEdges = Microsoft.Maui.SafeAreaEdges.All; + + var collectionView = new Microsoft.Maui.Controls.CollectionView + { + VerticalOptions = LayoutOptions.Fill + }; + + collectionView.ItemTemplate = new DataTemplate(() => + { + var label = new Label + { + Text = "Scroll to see title collapse", + FontSize = 18, + Padding = 15 + }; + return label; + }); + + collectionView.ItemsSource = Enumerable.Range(1, 40); + collectionView.Header = new Label { BackgroundColor = Colors.Pink, Text = "Header", Padding = 10, FontSize = 16 }; + collectionView.Footer = new Label { BackgroundColor = Colors.Yellow, Text = "Footer", Padding = 10, FontSize = 16 }; + + page.Content = collectionView; + await navPage.PushAsync(page); + }) + }, + new Button + { + Text = "Transparent NavBar - Content shows through", + Command = new Command(async () => + { + var navPage = (Microsoft.Maui.Controls.NavigationPage)Parent; + navPage.On().SetPrefersLargeTitles(true); + var previousBarColor = navPage.BarBackgroundColor; + navPage.BarBackgroundColor = Colors.Transparent; + + var page = new ContentPage + { + Title = "Transparent Bar", + // Create a gradient background that shows through the nav bar + Background = new LinearGradientBrush + { + StartPoint = new Point(0, 0), + EndPoint = new Point(0, 1), + GradientStops = new GradientStopCollection + { + new GradientStop { Color = Color.FromArgb("#667eea"), Offset = 0.0f }, + new GradientStop { Color = Color.FromArgb("#764ba2"), Offset = 1.0f } + } + } + }; + page.On().SetLargeTitleDisplay(LargeTitleDisplayMode.Always); + + var scrollContent = new StackLayout { Padding = 20, Spacing = 15 }; + scrollContent.Children.Add(new Label + { + Text = "Notice how the gradient background shows through the navigation bar area. This follows Apple's HIG recommendation.", + FontSize = 16, + TextColor = Colors.White, + Margin = new Thickness(0, 20) + }); + + for (int i = 1; i <= 30; i++) + { + scrollContent.Children.Add(new Frame + { + BackgroundColor = Colors.White.WithAlpha(0.9f), + CornerRadius = 10, + Padding = 15, + Content = new Label + { + Text = $"Card {i} - Scroll to see the effect", + FontSize = 16 + } + }); + } + + page.Content = new Microsoft.Maui.Controls.ScrollView { Content = scrollContent }; + await Navigation.PushAsync(page); + + // Restore opaque background when returning + page.Disappearing += (s, e) => navPage.BarBackgroundColor = previousBarColor; + }) + }, + + // Back Button + new BoxView { HeightRequest = 1, Color = Colors.Gray, Margin = new Thickness(0, 10) }, + new Button + { + Text = "← Back To Gallery", + Margin = new Thickness(0, 10, 0, 20), + Command = new Command(async () => await Navigation.PopAsync()) + } + } + } + }; + + Content = scrollView; + } +} \ No newline at end of file diff --git a/src/Controls/samples/Controls.Sample/Pages/PlatformSpecifics/iOS/iOSLargeTitlePage.xaml b/src/Controls/samples/Controls.Sample/Pages/PlatformSpecifics/iOS/iOSLargeTitlePage.xaml deleted file mode 100644 index 20cb2334a915..000000000000 --- a/src/Controls/samples/Controls.Sample/Pages/PlatformSpecifics/iOS/iOSLargeTitlePage.xaml +++ /dev/null @@ -1,12 +0,0 @@ - - - -