Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -209,6 +209,49 @@ public async Task RotationConsistent()
var platformRotation = await InvokeOnMainThreadAsync(() => handler.PlatformView.Rotation);
Assert.Equal(expected, platformRotation);
}

[Fact]
[Description("BottomNavigationView should extend to screen bottom in Edge-to-Edge mode (Issue 33344)")]
public async Task BottomNavigationViewExtendsToScreenBottom()
{
SetupBuilder();

var tabbedPage = new TabbedPage
{
Children =
{
new ContentPage() { Title = "Page1" },
new ContentPage() { Title = "Page2" }
},
BarBackgroundColor = Colors.Orange
};

Microsoft.Maui.Controls.PlatformConfiguration.AndroidSpecific.TabbedPage
.SetToolbarPlacement(tabbedPage, Microsoft.Maui.Controls.PlatformConfiguration.AndroidSpecific.ToolbarPlacement.Bottom);

await CreateHandlerAndAddToWindow<TabbedViewHandler>(tabbedPage, async handler =>
{
var bottomNavView = GetBottomNavigationView(handler);
Assert.NotNull(bottomNavView);

// Wait for layout to complete
await AssertEventually(() => bottomNavView.Height > 0);

var location = new int[2];
bottomNavView.GetLocationOnScreen(location);
var bottomNavBottom = location[1] + bottomNavView.Height;

var decorView = MauiContext.Context.GetActivity()?.Window?.DecorView;
Assert.NotNull(decorView);

decorView.GetLocationOnScreen(location);
var screenHeight = location[1] + decorView.Height;

Assert.True(Math.Abs(screenHeight - bottomNavBottom) < 2,
$"BottomNavigationView should extend to screen bottom. Expected bottom at {screenHeight}px, but was at {bottomNavBottom}px (gap of {screenHeight - bottomNavBottom}px)");
});
}

BottomNavigationView GetBottomNavigationView(IPlatformViewHandler tabViewHandler)
{
var layout = tabViewHandler.PlatformView.FindParent((view) => view is CoordinatorLayout)
Expand Down
39 changes: 16 additions & 23 deletions src/Core/src/Platform/Android/MauiWindowInsetListener.cs
Original file line number Diff line number Diff line change
Expand Up @@ -264,37 +264,30 @@ public MauiWindowInsetListener() : base(DispatchModeStop)
}
}

// Handle bottom navigation
var hasBottomNav = v.FindViewById(Resource.Id.navigationlayout_bottomtabs)?.MeasuredHeight > 0;
var bottomTabContainer = v.FindViewById<ViewGroup>(Resource.Id.navigationlayout_bottomtabs);
var hasBottomNav = bottomTabContainer?.MeasuredHeight > 0;
var contentView = v.FindViewById(Resource.Id.navigationlayout_content);

if (hasBottomNav)
{
var bottomInset = Math.Max(systemBars?.Bottom ?? 0, displayCutout?.Bottom ?? 0);
v.SetPadding(0, 0, 0, bottomInset);

// Only pad the bottom of contentView to prevent content from sliding under the
// BottomNavigationView + system navigation bar. Left/right are intentionally
// excluded: landscape cutout padding on the content area is handled by
// SafeAreaExtensions which applies per-view overlap logic.
contentView?.SetPadding(0, 0, 0, bottomInset);
}
else
{
v.SetPadding(0, 0, 0, 0);
// Reset contentView padding when bottom navigation is removed dynamically
contentView?.SetPadding(0, 0, 0, 0);
}

// Create new insets with consumed values
var newSystemBars = Insets.Of(
systemBars?.Left ?? 0,
appBarHasContent ? 0 : systemBars?.Top ?? 0,
systemBars?.Right ?? 0,
hasBottomNav ? 0 : systemBars?.Bottom ?? 0
) ?? Insets.None;

var newDisplayCutout = Insets.Of(
displayCutout?.Left ?? 0,
appBarHasContent ? 0 : displayCutout?.Top ?? 0,
displayCutout?.Right ?? 0,
hasBottomNav ? 0 : displayCutout?.Bottom ?? 0
) ?? Insets.None;

return new WindowInsetsCompat.Builder(insets)
?.SetInsets(WindowInsetsCompat.Type.SystemBars(), newSystemBars)
?.SetInsets(WindowInsetsCompat.Type.DisplayCutout(), newDisplayCutout)
?.Build() ?? insets;
// Pass insets through unconsumed so child views receive them intact.
// Bottom: BottomNavigationView needs the nav bar inset to extend its background in Edge-to-Edge mode (Issue #33344).
// Top: SafeAreaExtensions handles per-view overlap, avoiding double-padding.
return insets;
}

public void TrackView(AView view)
Expand Down
Loading