[Android] Fix NavigationBar overlapping StatusBar when NavigationBar visibility changes#33359
Conversation
There was a problem hiding this comment.
Pull request overview
This PR fixes an Android-specific issue where the NavigationBar overlaps the StatusBar in a TabbedPage when tabs use mixed HasNavigationBar values. The root cause stems from PR #27294's introduction of default OffscreenPageLimit, which pre-creates tab fragments with cached layout measurements. The fix addresses two related issues: 1) NavigationBar layout not accounting for height changes when switching tabs, and 2) StatusBar color not resetting when returning to tabs without NavigationBar.
Key Changes:
- Explicit insets reapplication when toolbar visibility/height changes
- Proper AppBarLayout content state detection by resetting cached measurements
- Comprehensive UI test with screenshot verification
Reviewed changes
Copilot reviewed 4 out of 6 changed files in this pull request and generated 1 comment.
Show a summary per file
| File | Description |
|---|---|
src/Core/src/Platform/Android/MauiWindowInsetListener.cs |
Initializes appBarHasContent to false before checking child heights to prevent stale measurements from previous tab switches |
src/Controls/src/Core/Platform/Android/Extensions/ToolbarExtensions.cs |
Adds RequestApplyInsets() call after updating toolbar layout parameters to trigger Android insets recalculation |
src/Controls/tests/TestCases.HostApp/Issues/Issue33340.cs |
Creates TabbedPage with bottom toolbar and mixed HasNavigationBar settings to reproduce the issue |
src/Controls/tests/TestCases.Shared.Tests/Tests/Issues/Issue33340.cs |
NUnit test that navigates to Tab4 and verifies layout via screenshot |
src/Controls/tests/TestCases.Android.Tests/snapshots/android/NavigationBarLayoutWithMixedHasNavigationBar.png |
Android screenshot baseline for test verification |
src/Controls/tests/TestCases.iOS.Tests/snapshots/ios/NavigationBarLayoutWithMixedHasNavigationBar.png |
iOS screenshot baseline (binary file) |
| Children.Add(new NavigationPage(page1) { Title = "Tab1" }); | ||
|
|
||
| var page2 = new ContentPage { Title = "Page2", Content = new Label { Text = "Page 2" } }; | ||
| NavigationPage.SetHasNavigationBar(page2, false); | ||
| Children.Add(new NavigationPage(page2) { Title = "Tab2" }); | ||
|
|
||
| var page3 = new ContentPage { Title = "Page3", Content = new Label { Text = "Page 3" } }; | ||
| NavigationPage.SetHasNavigationBar(page3, false); | ||
| Children.Add(new NavigationPage(page3) { Title = "Tab3" }); | ||
|
|
||
| var page4 = new ContentPage { Title = "Page4", Content = new Label { Text = "Page 4 with NavigationBar" } }; | ||
| NavigationPage.SetHasNavigationBar(page4, true); | ||
| Children.Add(new NavigationPage(page4) { Title = "Tab4" }); |
There was a problem hiding this comment.
The UI test is missing AutomationId attributes on the tab buttons in the HostApp code. The test tries to interact with "Tab4" using App.WaitForElement("Tab4") and App.Tap("Tab4"), but the HostApp code does not set any AutomationId properties. While the tab Title is "Tab4", relying on Title text for UI automation is fragile and may not work reliably across platforms. Add AutomationId properties to the NavigationPage instances to ensure the test can reliably locate and interact with the tabs.
PR Review Analysis: #33359 - Fix NavigationBar overlapping StatusBar in TabbedPageDate: 2026-01-02 Executive Summary✅ APPROVE WITH MINOR SUGGESTION This PR fixes a regression where the NavigationBar overlaps the StatusBar in TabbedPage when tabs mix Recommendation: This PR should be merged. Phase 0: Test Validation ✅ (WITH CAVEAT)Test Execution Results
ConclusionThe test correctly detects the issue through visual verification. The failure is due to local device configuration (android-notch-36) lacking a baseline snapshot, not a problem with the test or fix logic. In CI with standard configurations, this test will properly validate the fix. Phase 1: Independent AnalysisIssue Summary
Root Cause AnalysisTechnical Details
Second Issue (Discovered during testing)
Phase 2: Approach ComparisonPR's Fix ApproachFix 1: ToolbarExtensions.cs (1 line)nativeToolbar.LayoutParameters = lp;
AndroidX.Core.View.ViewCompat.RequestApplyInsets(nativeToolbar); // <-- Added
Fix 2: MauiWindowInsetListener.cs (2 lines)// Before:
bool appBarHasContent = appBarLayout?.MeasuredHeight > 0;
if (!appBarHasContent && appBarLayout is not null)
// After:
bool appBarHasContent = false; // <-- Initialize to false
if (appBarLayout is not null) // <-- Always check children
Alternative Approaches Considered
Recommendation: ✅ PR's fix is the optimal approachJustification
Phase 3: Regression AnalysisAffected Code PathsUpdateIsVisible called by:
Potential Regressions Analyzed
Edge Cases Checked
Final Recommendation✅ APPROVE WITH MINOR SUGGESTION Summary
Suggested Improvements (Non-blocking)
This PR should be merged. Technical DetailsFiles Changed
Code Changes AnalysisChange 1: Request Inset Reapplication (ToolbarExtensions.cs)// Line 35-36
nativeToolbar.LayoutParameters = lp;
AndroidX.Core.View.ViewCompat.RequestApplyInsets(nativeToolbar); // NEWImpact: Forces Android to recalculate window insets when toolbar visibility changes. This ensures child views get updated measurements after toolbar layout changes. Pattern Usage: This pattern is already used in 4+ other locations in the MAUI codebase for similar purposes. Change 2: Reset AppBarLayout State (MauiWindowInsetListener.cs)// Before (Line 133-134)
bool appBarHasContent = appBarLayout?.MeasuredHeight > 0;
if (!appBarHasContent && appBarLayout is not null)
// After (Line 133-134)
bool appBarHasContent = false;
if (appBarLayout is not null)Impact: Prevents using stale Testing StrategyTest Coverage
Manual Testing Performed
ConclusionThis is a well-crafted fix that:
The PR should be merged. |
|
/azp run |
|
Azure Pipelines successfully started running 3 pipeline(s). |
PureWeen
left a comment
There was a problem hiding this comment.
A number of tests are failing
|
/rebase |
6fac351 to
ad11f92
Compare
🤖 AI Summary📊 Expand Full Review🔍 Pre-Flight — Context & Validation📝 Review Session — Delete pr-33359.md ·
|
| Source | Comment | Status |
|---|---|---|
| copilot-pull-request-reviewer (Jan 2) | Missing AutomationId on tab buttons in HostApp - test uses "Tab4" which relies on tab title, not AutomationId |
|
| kubaflo (Jan 2) | Approved - test fails without fix, passes with fix (caveat: device baseline) | Historical |
| Vignesh-SF3580 (Jan 12) | Failing tests in CI are from safe area changes; tracked separately in #33473 | Noted |
| rmarinho (Feb 17) | Full agent review - Gate PASSED, APPROVE | Prior review |
Prior Agent Review Status
A prior agent review was completed on 2026-02-17 by rmarinho:
- Gate: ✅ PASSED
- Fix: s/agent-fix-lose (PR's fix was best among all candidates)
- Report: ✅ Final Recommendation: APPROVE
Fix Candidates
| # | Source | Approach | Test Result | Files Changed | Notes |
|---|---|---|---|---|---|
| PR | PR #33359 | Add ViewCompat.RequestApplyInsets(nativeToolbar) after toolbar layout update |
⏳ PENDING (Gate) | ToolbarExtensions.cs (+1) |
Forces insets recalculation when toolbar visibility changes |
🚦 Gate — Test Verification
📝 Review Session — Delete pr-33359.md · 68726db
Result: ✅ PASSED
Platform: android
Mode: Full Verification (RequireFullVerification: true)
Test Filter: Issue33340
- Tests FAIL without fix ✅ (7.80% visual difference in screenshot comparison - NavigationBar overlapping StatusBar)
- Tests PASS with fix ✅ (screenshot matches baseline - NavigationBar correctly positioned below StatusBar)
🔧 Fix — Analysis & Comparison
📝 Review Session — Delete pr-33359.md · 68726db
Fix Candidates
| # | Source | Approach | Test Result | Files Changed | Notes |
|---|---|---|---|---|---|
| 1 | try-fix | RequestLayout() on toolbar + parent view |
❌ FAIL | ToolbarExtensions.cs (+7) |
RequestLayout doesn't trigger inset recalculation; wrong mechanism |
| 2 | try-fix | Direct AppBarLayout padding update (GetRootWindowInsets, synchronous) | ✅ PASS | ToolbarExtensions.cs (+39) |
Works but complex; walks view tree to find AppBarLayout |
| 3 | try-fix | DispatchApplyWindowInsets on navigation content container in TabbedPageManager |
❌ FAIL | TabbedPageManager.cs |
Wrong target; issue is at toolbar/AppBarLayout level |
| 4 | try-fix | ViewTreeObserver.OnGlobalLayout listener + RequestApplyInsets on parent (deferred) |
✅ PASS | ToolbarExtensions.cs (+26) |
Works but verbose; deferred to next layout pass |
| 5 | try-fix | nativeToolbar.Post(() => RequestApplyInsets(nativeToolbar)) (async deferred) |
✅ PASS | ToolbarExtensions.cs (+1) |
Works; defers to next Looper iteration vs PR's synchronous call |
| PR | PR #33359 | ViewCompat.RequestApplyInsets(nativeToolbar) after toolbar layout update |
✅ PASS (Gate) | ToolbarExtensions.cs (+1) |
Immediate synchronous insets reapplication |
Cross-Pollination Round 2
| Model | Response |
|---|---|
| claude-sonnet-4.5 | NEW IDEAS: FitsSystemWindows, RequestApplyInsets on DecorView/Root, SetOnApplyWindowInsetsListener |
| claude-opus-4.6 | NO NEW IDEAS |
| gpt-5.2 | NEW IDEA: SetOnApplyWindowInsetsListener on AppBarLayout/Toolbar |
| gpt-5.2-codex | NEW IDEA: SetOnApplyWindowInsetsListener with margin/padding approach |
| gemini-3-pro-preview | NEW IDEA: FitsSystemWindows=true on nativeToolbar/AppBarLayout |
Cross-pollination new ideas could not be tested due to API rate limits (429 errors). All 3 attempts to run try-fix for new ideas failed.
Fix Analysis
Passing candidates (✅):
- Attempt 2: Direct AppBarLayout padding - works but adds 39 lines of complexity
- Attempt 4: ViewTreeObserver deferred - works but adds 26 lines with a helper class
- Attempt 5:
nativeToolbar.Post(RequestApplyInsets)- works, 1 line, but defers asynchronously - PR fix:
ViewCompat.RequestApplyInsets(nativeToolbar)- works, 1 line, immediate/synchronous
Comparison of 1-line solutions (PR vs Attempt 5):
- PR fix (synchronous): Called immediately after
lpis assigned; insets reapplication happens in the same call frame - Attempt 5 (async via Post): Defers to next message loop iteration; may avoid edge cases where the inset system reads values before layout settles
Both are equally minimal. The PR fix is simpler conceptually (direct call). Attempt 5's async deferral doesn't provide a clear advantage over the PR's synchronous approach.
Exhausted: No (API rate limits prevented testing FitsSystemWindows and SetOnApplyWindowInsetsListener ideas)
Selected Fix: PR's fix - Same simplicity as Attempt 5 (1 line), synchronous is clearer, the RequestApplyInsets pattern is already used in 4+ other places in the codebase (ContentViewGroup.cs, LayoutViewGroup.cs, MauiScrollView.cs), consistent with established patterns.
📋 Report — Final Recommendation
📝 Review Session — Delete pr-33359.md · 68726db
✅ Final Recommendation: APPROVE
Summary
PR #33359 fixes a regression in MAUI 10 where the NavigationBar overlaps the StatusBar in TabbedPage when tabs use mixed HasNavigationBar values (true/false). The fix is a single-line addition of ViewCompat.RequestApplyInsets(nativeToolbar) in ToolbarExtensions.cs. Gate passed: tests fail without the fix (7.80% visual difference) and pass with it. Multi-model try-fix exploration confirmed the PR's approach is the simplest correct solution.
Root Cause
PR #27294 introduced a default OffscreenPageLimit value that pre-creates tab fragments during TabbedPage initialization. When switching to a tab whose HasNavigationBar differs from the first-visited tab, Android's inset system uses cached measurements from pre-creation (when toolbar had different height). UpdateIsVisible() correctly updates lp.Height to the new value but this doesn't trigger inset redispatch — the content area's padding is stale, causing the NavigationBar to overlap the StatusBar.
Fix Quality
The fix is minimal (+1 line) and targeted:
nativeToolbar.LayoutParameters = lp;
AndroidX.Core.View.ViewCompat.RequestApplyInsets(nativeToolbar); // AddedThis pattern (RequestApplyInsets) is already used in 4+ other places in the codebase (ContentViewGroup.cs, LayoutViewGroup.cs, MauiScrollView.cs), making it consistent with established patterns.
Try-Fix Results
| # | Approach | Result | Lines | Notes |
|---|---|---|---|---|
| 1 | RequestLayout() on toolbar + parent |
❌ FAIL | +7 | Wrong mechanism; doesn't trigger inset dispatch |
| 2 | Direct AppBarLayout padding (GetRootWindowInsets) | ✅ PASS | +39 | Works but overly complex |
| 3 | DispatchApplyWindowInsets on content container | ❌ FAIL | — | Wrong target in view hierarchy |
| 4 | ViewTreeObserver.OnGlobalLayout + deferred RequestApplyInsets | ✅ PASS | +26 | Works but verbose |
| 5 | Post(() => RequestApplyInsets(nativeToolbar)) |
✅ PASS | +1 | Async deferral; no clear advantage over PR fix |
| PR | RequestApplyInsets(nativeToolbar) directly |
✅ PASS | +1 | Simplest, synchronous, consistent with codebase |
Selected Fix: PR's fix — same minimal size as Attempt 5, synchronous (simpler reasoning), and consistent with 4 other sites in the codebase.
Exhausted: No (API rate limits prevented 2 additional cross-pollination ideas: FitsSystemWindows and SetOnApplyWindowInsetsListener). The PR fix is clearly the best among tested candidates.
PR Finalize: Title & Description Review
Title: [Android] Fix NavigationBar overlapping StatusBar when NavigationBar visibility changes
- ✅ Has
[Android]platform prefix ⚠️ Minor: Could mention TabbedPage context for better searchability- Suggested improvement:
[Android] TabbedPage: Fix NavigationBar overlapping StatusBar with mixed HasNavigationBar values
Description quality: Good overall.
- ✅ NOTE block present at top
- ✅ Root cause documented
- ✅ Description of change accurate
- ✅ References to related code
⚠️ Missing "What NOT to Do" section (would help future agents avoidRequestLayout()/DispatchApplyWindowInsetsapproaches)
Code Review Findings
🟡 Suggestions
Missing AutomationId in HostApp (existing open review comment)
- File:
src/Controls/tests/TestCases.HostApp/Issues/Issue33340.cs:26 - Problem: Test relies on
Title = "Tab4"being discoverable as"Tab4"by Appium — theWaitForElementcall finds the tab by title. While this works in practice for TabbedPage tabs (title text is used as automation ID by the MAUI test infra), adding an explicitAutomationIdis more robust. - Severity: Minor — test works as-is, but explicitness improves maintainability.
HostApp initializes as TabbedPage subclass with bottom toolbar always set
- Reproduces the specific scenario well. No issues.
Test is screenshot-only (VerifyScreenshot)
- The test navigates to Tab4 and verifies visually. This is appropriate for a layout overlap issue, but a future improvement could add an element position assertion for more precise validation.
✅ Looks Good
- Single line fix in the right method (
UpdateIsVisible) — minimal, focused ViewCompat.RequestApplyInsetsis the correct API for triggering inset redispatch- Existing pattern: this call is already used in
ContentViewGroup.cs,LayoutViewGroup.cs,MauiScrollView.cs - Test covers exactly the bug scenario: TabbedPage with mixed HasNavigationBar, first visit to the 'true' tab
- Snapshots provided for all 4 platforms (android, ios, mac, windows)
- Appropriate
[Category(UITestCategories.TabbedPage)]attribute PlatformAffected.Androidcorrectly set
📋 Expand PR Finalization Review
Title: ✅ Good
Current: [Android] Fix NavigationBar overlapping StatusBar when NavigationBar visibility changes
Description: ✅ Good
Description needs updates. See details below.
✨ Suggested PR 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 from this PR and let us know in a comment if this change resolves your issue. Thank you!
Issue Details
On Android, the content area in a TabbedPage shows incorrect layout when tabs use mixed HasNavigationBar values (some true, some false). When switching to a tab where the NavigationBar is visible, the content area does not properly account for the toolbar height, resulting in content being obscured by the NavigationBar.
Regression PR: #27294
Root Cause
PR #27294 introduced a default OffscreenPageLimit value, which pre-creates tab fragments during initialization. When switching between tabs with different HasNavigationBar values, Android's insets system does not automatically recalculate layout measurements because they were cached during the pre-creation phase. While the toolbar height updates correctly via LayoutParameters, the content area continues using stale inset measurements.
Description of Change
Added a call to AndroidX.Core.View.ViewCompat.RequestApplyInsets(nativeToolbar) in ToolbarExtensions.UpdateIsVisible after updating LayoutParameters. This explicitly requests Android to re-dispatch window insets through the view hierarchy, triggering remeasurement of the content area when the toolbar visibility or height changes.
File changed:
src/Controls/src/Core/Platform/Android/Extensions/ToolbarExtensions. 1 line added toUpdateIsVisiblecs
References:
Tested the behavior in the following platforms
- Android
- Windows
- iOS
- Mac
Issues Fixed
Fixes #33340
Screenshots
| Before Issue Fix | After Issue Fix |
|---|---|
| (before screenshot) | (after screenshot) |
Code Review: ✅ Passed
Code PR #33359Review
Source Change
File: src/Controls/src/Core/Platform/Android/Extensions/ToolbarExtensions.cs
Change: +1 AndroidX.Core.View.ViewCompat.RequestApplyInsets(nativeToolbar) after nativeToolbar.LayoutParameters = lp;line
1. AutomationId Missing on TabbedPage Tabs (HostApp)
File: src/Controls/tests/TestCases.HostApp/Issues/Issue33340.cs
Problem: The UI test locates tabs using App.WaitForElement("Tab4") and App.Tap("Tab4"), but the NavigationPage instances in the HostApp have no AutomationId set. The test relies on the Title property ("Tab4") being discoverable by Appium, which is tab title accessibility mapping varies by platform and Appium driver.fragile
Note: This was already flagged in an existing review comment from
copilot-pull-request-reviewer(Jan 2, 2026).
Recommendation: Add AutomationId to each NavigationPage:
Children.Add(new NavigationPage(page4) { Title = "Tab4", AutomationId = "Tab4" });2. RequestApplyInsets Called on Every Visibility Update
File: src/Controls/src/Core/Platform/Android/Extensions/ToolbarExtensions.cs
Problem: ViewCompat.RequestApplyInsets(nativeToolbar) is now called unconditionally on every UpdateIsVisible even when the toolbar height hasn't changed (e.g., when the same visibility state is applied again). This triggers a full inset re-dispatch pass through the view hierarchy on every call.invocation
Impact: Low in most scenarios (toolbar visibility doesn't change frequently), but could add overhead in edge cases such as rapid page transitions or re-layout cycles.
Recommendation (optional): Guard the call to only when the height actually changed:
var previousHeight = lp.Height;
// ... existing height-setting logic ...
nativeToolbar.LayoutParameters = lp;
if (lp.Height != previousHeight)
AndroidX.Core.View.ViewCompat.RequestApplyInsets(nativeToolbar);This is an optional the current unconditional call is correct and safe.optimization
3. UI Test Only Verifies Snapshot, Not Layout Correctness
File: src/Controls/tests/TestCases.Shared.Tests/Tests/Issues/Issue33340.cs
Observation: The test taps Tab4 and calls VerifyScreenshot(). This is a visual regression test that confirms the final rendered state matches the baseline snapshot. It does not explicitly assert that no overlap occurs (e.g., by checking element positions).
Impact: If the fix regresses in a way that doesn't visually differ from the baseline (e.g., the overlap is subtle), the test may not catch it. However, VerifyScreenshot is the standard pattern for layout tests in this repo and is acceptable here.
Looks Good
- Fix is minimal and One line added exactly where the inset update is needed, in
UpdateIsVisibleafterLayoutParametersis set.targeted ViewCompat.RequestApplyInsetsis the correct This is the standard way to trigger inset re-dispatch in AndroidX and correctly causes the view hierarchy to remeasure with fresh insets.API- Test page correctly reproduces the 3 tabs without NavigationBar + 1 tab with NavigationBar, bottom toolbar placement, matches the reported reproduction steps.scenario
[Issue]attribute correctly scoped to AndroidPlatformAffected.Androidis appropriate sinceViewCompat.RequestApplyInsetsand theOffscreenPageLimitmechanism are Android-specific.only- No breaking The added call is purely additive; no existing behavior is modified.changes
Summary
| Severity | Count | Items |
|---|---|---|
| Positive |
The most actionable item is adding AutomationId to the NavigationPage instances in the HostApp (already noted in existing review comment). The source fix itself is correct.
…visibility changes (#33359) <!-- Please let the below note in for people that find this PR --> > [!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! ### Issue Details On Android, the content area in a TabbedPage shows incorrect layout when tabs use mixed HasNavigationBar values (some true, some false). When switching to a tab where the NavigationBar is visible, the content area does not properly account for the toolbar height, resulting in content being obscured by the NavigationBar. **Regression PR:** #27294 ### Root Cause PR #27294 introduced a default OffscreenPageLimit value, which pre-creates tab fragments during initialization. When switching between tabs with different HasNavigationBar values, Android's insets system does not automatically recalculate layout measurements because they were cached during the pre-creation phase. While the toolbar height updates correctly via LayoutParameters, the content area continues using stale inset measurements. ### Description of Change Added a call to AndroidX.Core.View.ViewCompat.RequestApplyInsets(nativeToolbar) in ToolbarExtensions.UpdateIsVisible after updating LayoutParameters. This explicitly requests Android to re-dispatch window insets through the view hierarchy, triggering remeasurement of the content area when the toolbar visibility or height changes. **References:** [Android/ContentViewGroup.cs#L149](https://github.com/dotnet/maui/blob/main/src/Core/src/Platform/Android/ContentViewGroup.cs#L149) [Android/LayoutViewGroup.cs#L166](https://github.com/dotnet/maui/blob/main/src/Core/src/Platform/Android/LayoutViewGroup.cs#L166) [Android/MauiScrollView.cs#L303](https://github.com/dotnet/maui/blob/main/src/Core/src/Platform/Android/MauiScrollView.cs#L303) ### Tested the behavior in the following platforms - [x] Android - [x] Windows - [x] iOS - [x] Mac ### Issues Fixed Fixes #33340 ### Screenshots | Before Issue Fix | After Issue Fix | |----------|----------| | <video width="300" height="600" src="https://github.com/user-attachments/assets/e15fe58b-a609-442c-911f-0e0f04ee8545"> | <video width="300" height="600" src="https://github.com/user-attachments/assets/e5da01a3-c0b8-4fc1-a443-efff1409dd82">) | --------- Co-authored-by: Shane Neuville <[email protected]> Co-authored-by: Jakub Florkowski <[email protected]>
…visibility changes (#33359) <!-- Please let the below note in for people that find this PR --> > [!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! ### Issue Details On Android, the content area in a TabbedPage shows incorrect layout when tabs use mixed HasNavigationBar values (some true, some false). When switching to a tab where the NavigationBar is visible, the content area does not properly account for the toolbar height, resulting in content being obscured by the NavigationBar. **Regression PR:** #27294 ### Root Cause PR #27294 introduced a default OffscreenPageLimit value, which pre-creates tab fragments during initialization. When switching between tabs with different HasNavigationBar values, Android's insets system does not automatically recalculate layout measurements because they were cached during the pre-creation phase. While the toolbar height updates correctly via LayoutParameters, the content area continues using stale inset measurements. ### Description of Change Added a call to AndroidX.Core.View.ViewCompat.RequestApplyInsets(nativeToolbar) in ToolbarExtensions.UpdateIsVisible after updating LayoutParameters. This explicitly requests Android to re-dispatch window insets through the view hierarchy, triggering remeasurement of the content area when the toolbar visibility or height changes. **References:** [Android/ContentViewGroup.cs#L149](https://github.com/dotnet/maui/blob/main/src/Core/src/Platform/Android/ContentViewGroup.cs#L149) [Android/LayoutViewGroup.cs#L166](https://github.com/dotnet/maui/blob/main/src/Core/src/Platform/Android/LayoutViewGroup.cs#L166) [Android/MauiScrollView.cs#L303](https://github.com/dotnet/maui/blob/main/src/Core/src/Platform/Android/MauiScrollView.cs#L303) ### Tested the behavior in the following platforms - [x] Android - [x] Windows - [x] iOS - [x] Mac ### Issues Fixed Fixes #33340 ### Screenshots | Before Issue Fix | After Issue Fix | |----------|----------| | <video width="300" height="600" src="https://github.com/user-attachments/assets/e15fe58b-a609-442c-911f-0e0f04ee8545"> | <video width="300" height="600" src="https://github.com/user-attachments/assets/e5da01a3-c0b8-4fc1-a443-efff1409dd82">) | --------- Co-authored-by: Shane Neuville <[email protected]> Co-authored-by: Jakub Florkowski <[email protected]>
…visibility changes (#33359) <!-- Please let the below note in for people that find this PR --> > [!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! ### Issue Details On Android, the content area in a TabbedPage shows incorrect layout when tabs use mixed HasNavigationBar values (some true, some false). When switching to a tab where the NavigationBar is visible, the content area does not properly account for the toolbar height, resulting in content being obscured by the NavigationBar. **Regression PR:** #27294 ### Root Cause PR #27294 introduced a default OffscreenPageLimit value, which pre-creates tab fragments during initialization. When switching between tabs with different HasNavigationBar values, Android's insets system does not automatically recalculate layout measurements because they were cached during the pre-creation phase. While the toolbar height updates correctly via LayoutParameters, the content area continues using stale inset measurements. ### Description of Change Added a call to AndroidX.Core.View.ViewCompat.RequestApplyInsets(nativeToolbar) in ToolbarExtensions.UpdateIsVisible after updating LayoutParameters. This explicitly requests Android to re-dispatch window insets through the view hierarchy, triggering remeasurement of the content area when the toolbar visibility or height changes. **References:** [Android/ContentViewGroup.cs#L149](https://github.com/dotnet/maui/blob/main/src/Core/src/Platform/Android/ContentViewGroup.cs#L149) [Android/LayoutViewGroup.cs#L166](https://github.com/dotnet/maui/blob/main/src/Core/src/Platform/Android/LayoutViewGroup.cs#L166) [Android/MauiScrollView.cs#L303](https://github.com/dotnet/maui/blob/main/src/Core/src/Platform/Android/MauiScrollView.cs#L303) ### Tested the behavior in the following platforms - [x] Android - [x] Windows - [x] iOS - [x] Mac ### Issues Fixed Fixes #33340 ### Screenshots | Before Issue Fix | After Issue Fix | |----------|----------| | <video width="300" height="600" src="https://github.com/user-attachments/assets/e15fe58b-a609-442c-911f-0e0f04ee8545"> | <video width="300" height="600" src="https://github.com/user-attachments/assets/e5da01a3-c0b8-4fc1-a443-efff1409dd82">) | --------- Co-authored-by: Shane Neuville <[email protected]> Co-authored-by: Jakub Florkowski <[email protected]>
…visibility changes (#33359) <!-- Please let the below note in for people that find this PR --> > [!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! ### Issue Details On Android, the content area in a TabbedPage shows incorrect layout when tabs use mixed HasNavigationBar values (some true, some false). When switching to a tab where the NavigationBar is visible, the content area does not properly account for the toolbar height, resulting in content being obscured by the NavigationBar. **Regression PR:** #27294 ### Root Cause PR #27294 introduced a default OffscreenPageLimit value, which pre-creates tab fragments during initialization. When switching between tabs with different HasNavigationBar values, Android's insets system does not automatically recalculate layout measurements because they were cached during the pre-creation phase. While the toolbar height updates correctly via LayoutParameters, the content area continues using stale inset measurements. ### Description of Change Added a call to AndroidX.Core.View.ViewCompat.RequestApplyInsets(nativeToolbar) in ToolbarExtensions.UpdateIsVisible after updating LayoutParameters. This explicitly requests Android to re-dispatch window insets through the view hierarchy, triggering remeasurement of the content area when the toolbar visibility or height changes. **References:** [Android/ContentViewGroup.cs#L149](https://github.com/dotnet/maui/blob/main/src/Core/src/Platform/Android/ContentViewGroup.cs#L149) [Android/LayoutViewGroup.cs#L166](https://github.com/dotnet/maui/blob/main/src/Core/src/Platform/Android/LayoutViewGroup.cs#L166) [Android/MauiScrollView.cs#L303](https://github.com/dotnet/maui/blob/main/src/Core/src/Platform/Android/MauiScrollView.cs#L303) ### Tested the behavior in the following platforms - [x] Android - [x] Windows - [x] iOS - [x] Mac ### Issues Fixed Fixes #33340 ### Screenshots | Before Issue Fix | After Issue Fix | |----------|----------| | <video width="300" height="600" src="https://github.com/user-attachments/assets/e15fe58b-a609-442c-911f-0e0f04ee8545"> | <video width="300" height="600" src="https://github.com/user-attachments/assets/e5da01a3-c0b8-4fc1-a443-efff1409dd82">) | --------- Co-authored-by: Shane Neuville <[email protected]> Co-authored-by: Jakub Florkowski <[email protected]>
…visibility changes (dotnet#33359) <!-- Please let the below note in for people that find this PR --> > [!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! ### Issue Details On Android, the content area in a TabbedPage shows incorrect layout when tabs use mixed HasNavigationBar values (some true, some false). When switching to a tab where the NavigationBar is visible, the content area does not properly account for the toolbar height, resulting in content being obscured by the NavigationBar. **Regression PR:** dotnet#27294 ### Root Cause PR dotnet#27294 introduced a default OffscreenPageLimit value, which pre-creates tab fragments during initialization. When switching between tabs with different HasNavigationBar values, Android's insets system does not automatically recalculate layout measurements because they were cached during the pre-creation phase. While the toolbar height updates correctly via LayoutParameters, the content area continues using stale inset measurements. ### Description of Change Added a call to AndroidX.Core.View.ViewCompat.RequestApplyInsets(nativeToolbar) in ToolbarExtensions.UpdateIsVisible after updating LayoutParameters. This explicitly requests Android to re-dispatch window insets through the view hierarchy, triggering remeasurement of the content area when the toolbar visibility or height changes. **References:** [Android/ContentViewGroup.cs#L149](https://github.com/dotnet/maui/blob/main/src/Core/src/Platform/Android/ContentViewGroup.cs#L149) [Android/LayoutViewGroup.cs#L166](https://github.com/dotnet/maui/blob/main/src/Core/src/Platform/Android/LayoutViewGroup.cs#L166) [Android/MauiScrollView.cs#L303](https://github.com/dotnet/maui/blob/main/src/Core/src/Platform/Android/MauiScrollView.cs#L303) ### Tested the behavior in the following platforms - [x] Android - [x] Windows - [x] iOS - [x] Mac ### Issues Fixed Fixes dotnet#33340 ### Screenshots | Before Issue Fix | After Issue Fix | |----------|----------| | <video width="300" height="600" src="https://github.com/user-attachments/assets/e15fe58b-a609-442c-911f-0e0f04ee8545"> | <video width="300" height="600" src="https://github.com/user-attachments/assets/e5da01a3-c0b8-4fc1-a443-efff1409dd82">) | --------- Co-authored-by: Shane Neuville <[email protected]> Co-authored-by: Jakub Florkowski <[email protected]>
…visibility changes (#33359) <!-- Please let the below note in for people that find this PR --> > [!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! ### Issue Details On Android, the content area in a TabbedPage shows incorrect layout when tabs use mixed HasNavigationBar values (some true, some false). When switching to a tab where the NavigationBar is visible, the content area does not properly account for the toolbar height, resulting in content being obscured by the NavigationBar. **Regression PR:** #27294 ### Root Cause PR #27294 introduced a default OffscreenPageLimit value, which pre-creates tab fragments during initialization. When switching between tabs with different HasNavigationBar values, Android's insets system does not automatically recalculate layout measurements because they were cached during the pre-creation phase. While the toolbar height updates correctly via LayoutParameters, the content area continues using stale inset measurements. ### Description of Change Added a call to AndroidX.Core.View.ViewCompat.RequestApplyInsets(nativeToolbar) in ToolbarExtensions.UpdateIsVisible after updating LayoutParameters. This explicitly requests Android to re-dispatch window insets through the view hierarchy, triggering remeasurement of the content area when the toolbar visibility or height changes. **References:** [Android/ContentViewGroup.cs#L149](https://github.com/dotnet/maui/blob/main/src/Core/src/Platform/Android/ContentViewGroup.cs#L149) [Android/LayoutViewGroup.cs#L166](https://github.com/dotnet/maui/blob/main/src/Core/src/Platform/Android/LayoutViewGroup.cs#L166) [Android/MauiScrollView.cs#L303](https://github.com/dotnet/maui/blob/main/src/Core/src/Platform/Android/MauiScrollView.cs#L303) ### Tested the behavior in the following platforms - [x] Android - [x] Windows - [x] iOS - [x] Mac ### Issues Fixed Fixes #33340 ### Screenshots | Before Issue Fix | After Issue Fix | |----------|----------| | <video width="300" height="600" src="https://github.com/user-attachments/assets/e15fe58b-a609-442c-911f-0e0f04ee8545"> | <video width="300" height="600" src="https://github.com/user-attachments/assets/e5da01a3-c0b8-4fc1-a443-efff1409dd82">) | --------- Co-authored-by: Shane Neuville <[email protected]> Co-authored-by: Jakub Florkowski <[email protected]>
## What's Coming .NET MAUI inflight/candidate introduces significant improvements across all platforms with focus on quality, performance, and developer experience. This release includes 46 commits with various improvements, bug fixes, and enhancements. ## Button - [Android] Implemented material3 support for Button by @Dhivya-SF4094 in #33173 <details> <summary>🔧 Fixes</summary> - [Implement Material3 support for Button](#33172) </details> ## CollectionView - [Android] Fix RemainingItemsThresholdReachedCommand not firing when CollectionView has Header and Footer both defined by @SuthiYuvaraj in #29618 <details> <summary>🔧 Fixes</summary> - [Android : RemainingItemsThresholdReachedCommand not firing when CollectionVew has Header and Footer both defined](#29588) </details> - [iOS/MacCatalyst] Fix CollectionView ScrollTo for horizontal layouts by @Shalini-Ashokan in #33853 <details> <summary>🔧 Fixes</summary> - [[iOS/MacCatalyst] CollectionView ScrollTo does not work with horizontal Layout](#33852) </details> - [iOS & Mac] Fixed IndicatorView Size doesnt update dynamically by @SubhikshaSf4851 in #31129 <details> <summary>🔧 Fixes</summary> - [[iOS, Catalyst] IndicatorView.IndicatorSize does not update dynamically at runtime](#31064) </details> - [Android] Fix for CollectionView Scrolled event is triggered on the initial app load. by @BagavathiPerumal in #33558 <details> <summary>🔧 Fixes</summary> - [[Android] CollectionView Scrolled event is triggered on the initial app load.](#33333) </details> - [iOS, Android] Fix for CollectionView IsEnabled=false allows touch interactions by @praveenkumarkarunanithi in #31403 <details> <summary>🔧 Fixes</summary> - [More issues with CollectionView IsEnabled, InputTransparent, Opacity via Styles and code behind](#19771) </details> - [iOS] Fix VerticalOffset Update When Modifying CollectionView.ItemsSource While Scrolled by @devanathan-vaithiyanathan in #34153 <details> <summary>🔧 Fixes</summary> - [[iOS]VerticalOffset Not Reset to Zero After Clearing ItemSource in CollectionView](#26798) </details> ## DateTimePicker - [Android] Fix DatePicker MinimumDate/MaximumDate not updating dynamically by @HarishwaranVijayakumar in #33687 <details> <summary>🔧 Fixes</summary> - [[regression/8.0.3] [Android] DatePicker control minimum date issue](#19256) - [[Android] DatePicker does not update MinimumDate / MaximumDate in the Popup when set in the viewmodel after first opening](#33583) </details> ## Drawing - Android drawable perf by @albyrock87 in #31567 ## Editor - [Android] Implemented material3 support for Editor by @SyedAbdulAzeemSF4852 in #33478 <details> <summary>🔧 Fixes</summary> - [Implement Material3 Support for Editor](#33476) </details> ## Entry - [iOS, Mac] Fix for CursorPosition not updating when typing into Entry control by @SyedAbdulAzeemSF4852 in #30505 <details> <summary>🔧 Fixes</summary> - [Entry control CursorPosition does not update on TextChanged event [iOS Maui 8.0.7] ](#20911) - [CursorPosition not calculated correctly on behaviors events for iOS devices](#32483) </details> ## Flyoutpage - [Android, Windows] Fix for FlyoutPage toolbar button not updating on orientation change by @praveenkumarkarunanithi in #31962 <details> <summary>🔧 Fixes</summary> - [Flyout page in Android does not show flyout button (burger) consistently](#24468) </details> - Fix for First Item in CollectionView Overlaps in FlyoutPage.Flyout on iOS by @praveenkumarkarunanithi in #29265 <details> <summary>🔧 Fixes</summary> - [[iOS] CollectionView not rendering first item correctly in FlyoutPage.Flyout](#29170) </details> ## Image - [Android] Fix excessive memory usage for stream and resource-based image loading by @Shalini-Ashokan in #33590 <details> <summary>🔧 Fixes</summary> - [[Android] Unexpected high Bitmap.ByteCount when loading image via ImageSource.FromResource() or ImageSource.FromStream() in .NET MAUI](#33239) </details> - [Android] Fix for Resize method returns an image that has already been disposed by @SyedAbdulAzeemSF4852 in #29964 <details> <summary>🔧 Fixes</summary> - [In GraphicsView, the Resize method returns an image that has already been disposed](#29961) - [IIMage.Resize bugged behaviour](#31103) </details> ## Label - Fixed Label Span font property inheritance when applied via Style by @SubhikshaSf4851 in #34110 <details> <summary>🔧 Fixes</summary> - [`Span` does not inherit text styling from `Label` if that styling is applied using `Style` ](#21326) </details> - [Android] Implemented material3 support for Label by @SyedAbdulAzeemSF4852 in #33599 <details> <summary>🔧 Fixes</summary> - [Implement Material3 Support for Label](#33598) </details> ## Map - [Android] Fix Circle Stroke color is incorrectly updated as Fill color. by @NirmalKumarYuvaraj in #33643 <details> <summary>🔧 Fixes</summary> - [[Android] Circle Stroke color is incorrectly updated as Fill color.](#33642) </details> ## Mediapicker - [iOS] Fix: invoke MediaPicker completion handler after DismissViewController by @yuriikyry4enko in #34250 <details> <summary>🔧 Fixes</summary> - [[iOS] Media Picker UIImagePickerController closing issue](#21996) </details> ## Navigation - Fix ContentPage memory leak on Android when using NavigationPage modally (fixes #33918) by @brunck in #34117 <details> <summary>🔧 Fixes</summary> - [[Android] Modal TabbedPage whose tabs are NavigationPage(ContentPage) is retained after PopModalAsync()](#33918) </details> ## Picker - [Android] Implement material3 support for TimePicker by @HarishwaranVijayakumar in #33646 <details> <summary>🔧 Fixes</summary> - [Implement Material3 support for TimePicker](#33645) </details> - [Android] Implemented Material3 support for Picker by @SyedAbdulAzeemSF4852 in #33668 <details> <summary>🔧 Fixes</summary> - [Implement Material3 support for Picker](#33665) </details> ## RadioButton - [Android] Implemented material3 support for RadioButton by @SyedAbdulAzeemSF4852 in #33468 <details> <summary>🔧 Fixes</summary> - [Implement Material3 Support for RadioButton](#33467) </details> ## Setup - Clarify MA003 error message by @jeremy-visionaid in #34067 <details> <summary>🔧 Fixes</summary> - [MA003 false positive with 9.0.21](#26599) </details> ## Shell - [Android] Fix TabBar FlowDirection not updating dynamically by @SubhikshaSf4851 in #33091 <details> <summary>🔧 Fixes</summary> - [[Android, iOS] FlowDirection RTL is not updated dynamically on Shell TabBar](#32993) </details> - [Android] Fix page not disposed on Shell replace navigation by @Vignesh-SF3580 in #33426 <details> <summary>🔧 Fixes</summary> - [[Android] [Shell] replace navigation leaks current page](#25134) </details> - [Android] Fixed Shell flyout does not disable scrolling when FlyoutVerticalScrollMode is set to Disabled by @NanthiniMahalingam in #32734 <details> <summary>🔧 Fixes</summary> - [[Android] Shell.FlyoutVerticalScrollMode="Disabled" does not disable scrolling](#32477) </details> ## Single Project - Fix: Throw a clear error when an SVG lacks dimensions instead of a NullReferenceException by @Shalini-Ashokan in #33194 <details> <summary>🔧 Fixes</summary> - [MAUI Fails To Convert Valid SVG Files Into PNG Files (Object reference not set to an instance of an object)](#32460) </details> ## SwipeView - [iOS] Fix SwipeView stays open on iOS after updating content by @devanathan-vaithiyanathan in #31248 <details> <summary>🔧 Fixes</summary> - [[iOS] - Swipeview with collectionview issue](#19541) </details> ## TabbedPage - [Windows] Fixed IsEnabled Property not works on Tabs by @NirmalKumarYuvaraj in #26728 <details> <summary>🔧 Fixes</summary> - [ShellContent IsEnabledProperty does not work](#5161) - [[Windows] Shell Tab IsEnabled Not Working](#32996) </details> - [Android] Fix NavigationBar overlapping StatusBar when NavigationBar visibility changes by @Vignesh-SF3580 in #33359 <details> <summary>🔧 Fixes</summary> - [[Android] NavigationBar overlaps with StatusBar when mixing HasNavigationBar=true/false in TabbedPage on Android 15 (API 35)](#33340) </details> ## Templates - Fix for unable to open task using keyboard navigation on windows platform by @SuthiYuvaraj in #33647 <details> <summary>🔧 Fixes</summary> - [Unable to open task using keyboard: A11y_.NET maui_User can get all the insights of Dashboard_Keyboard](#30787) </details> ## TitleView - Fix for NavigationPage.TitleView does not expand with host window in iPadOS 26+ by @SuthiYuvaraj in #33088 ## Toolbar - [iOS] Fix toolbar items ignoring BarTextColor on iOS/MacCatalyst 26+ by @Shalini-Ashokan in #34036 <details> <summary>🔧 Fixes</summary> - [[iOS 26] ToolbarItem color with custom BarTextColor not working](#33970) </details> - [Android] Fix for ToolbarItem retaining the icon from the previous page on Android when using NavigationPage. by @BagavathiPerumal in #32311 <details> <summary>🔧 Fixes</summary> - [Toolbaritem keeps the icon of the previous page on Android, using NavigationPage (not shell)](#31727) </details> ## WebView - [Android] Fix WebView in a grid expands beyond it's cell by @devanathan-vaithiyanathan in #32145 <details> <summary>🔧 Fixes</summary> - [Android - WebView in a grid expands beyond it's cell](#32030) </details> ## Xaml - ContentPresenter: Propagate binding context to children with explicit TemplateBinding by @HarishwaranVijayakumar in #30880 <details> <summary>🔧 Fixes</summary> - [Binding context in ContentPresenter](#23797) </details> <details> <summary>🔧 Infrastructure (1)</summary> - [Revert] ContentPresenter: Propagate binding context to children with explicit TemplateBinding by @Ahamed-Ali in #34332 </details> <details> <summary>🧪 Testing (6)</summary> - [Testing] Feature Matrix UITest Cases for Shell Flyout Page by @NafeelaNazhir in #32525 - [Testing] Feature Matrix UITest Cases for Brushes by @LogishaSelvarajSF4525 in #31833 - [Testing] Feature Matrix UITest Cases for BindableLayout by @LogishaSelvarajSF4525 in #33108 - [Android] Add UI tests for Material 3 CheckBox by @HarishwaranVijayakumar in #34126 <details> <summary>🔧 Fixes</summary> - [[Android] Add UI tests for Material 3 CheckBox](#34125) </details> - [Testing] Feature Matrix UITest Cases for Shell Tabbed Page by @NafeelaNazhir in #33159 - [Testing] Fixed Test case failure in PR 34294 - [03/2/2026] Candidate - 1 by @TamilarasanSF4853 in #34334 </details> <details> <summary>📦 Other (2)</summary> - Bumps Syncfusion.Maui.Toolkit dependency to version 1.0.9 by @PaulAndersonS in #34178 - Fix crash when closing Windows based app when using TitleBar by @MFinkBK in #34032 <details> <summary>🔧 Fixes</summary> - [Unhandled exception "Value does not fall within the expected range" when closing Windows app](#32194) </details> </details> **Full Changelog**: main...inflight/candidate
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 from this PR and let us know in a comment if this change resolves your issue. Thank you!
Issue Details
On Android, the content area in a TabbedPage shows incorrect layout when tabs use mixed HasNavigationBar values (some true, some false). When switching to a tab where the NavigationBar is visible, the content area does not properly account for the toolbar height, resulting in content being obscured by the NavigationBar.
Regression PR: #27294
Root Cause
PR #27294 introduced a default OffscreenPageLimit value, which pre-creates tab fragments during initialization. When switching between tabs with different HasNavigationBar values, Android's insets system does not automatically recalculate layout measurements because they were cached during the pre-creation phase. While the toolbar height updates correctly via LayoutParameters, the content area continues using stale inset measurements.
Description of Change
Added a call to AndroidX.Core.View.ViewCompat.RequestApplyInsets(nativeToolbar) in ToolbarExtensions.UpdateIsVisible after updating LayoutParameters. This explicitly requests Android to re-dispatch window insets through the view hierarchy, triggering remeasurement of the content area when the toolbar visibility or height changes.
References:
Android/ContentViewGroup.cs#L149
Android/LayoutViewGroup.cs#L166
Android/MauiScrollView.cs#L303
Tested the behavior in the following platforms
Issues Fixed
Fixes #33340
Screenshots
BeforeFix33340.mov
AfterFix33340.mov