Skip to content

Commit

Permalink
fix(contentdialog): [Android] Fix botom of full-size ContentDialog cu…
Browse files Browse the repository at this point in the history
…t off

Add an internal adjusted visible bounds which trims the status bar from the height. This allows the ContentDialog to be arranged with the correct available height.

There's a case for adjusting the public-facing VisibleBounds property, but it's not clear what the exact adjustment would be and it's potentially a breaking change, and isn't required for the present case.
  • Loading branch information
davidjohnoliver committed Oct 23, 2020
1 parent 22e0227 commit 6c0ede3
Show file tree
Hide file tree
Showing 4 changed files with 69 additions and 39 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ protected override Size ArrangeOverride(Size finalSize)

private Rect CalculateDialogPlacement(Size desiredSize)
{
var visibleBounds = ApplicationView.GetForCurrentView().VisibleBounds;
var visibleBounds = ApplicationView.GetForCurrentView().TrueVisibleBounds;

// Make sure the desiredSize fits in visibleBounds
if (desiredSize.Width > visibleBounds.Width)
Expand Down
88 changes: 50 additions & 38 deletions src/Uno.UI/UI/Xaml/Window.Android.cs
Original file line number Diff line number Diff line change
Expand Up @@ -95,49 +95,63 @@ internal void RaiseNativeSizeChanged()

var newBounds = ViewHelper.PhysicalToLogicalPixels(new Rect(0, 0, fullScreenMetrics.WidthPixels, fullScreenMetrics.HeightPixels));

var statusBarSizeExcluded = GetLogicalStatusBarSizeExcluded();
var navigationBarSizeExcluded = GetLogicalNavigationBarSizeExcluded();
var statusBarSize = GetLogicalStatusBarSize();

var statusBarSizeExcluded = IsStatusBarTranslucent() ?
// The real metrics excluded the StatusBar only if it is plain.
// We want to subtract it if it is translucent. Otherwise, it will be like we subtract it twice.
statusBarSize :
0;
var navigationBarSizeExcluded = GetLogicalNavigationBarSizeExcluded();

// Actually, we need to check visibility of nav bar and status bar since the insets don't
UpdateInsetsWithVisibilities();

var topHeightExcluded = Math.Max(Insets.Top, statusBarSizeExcluded);

var orientation = DisplayInformation.GetForCurrentView().CurrentOrientation;
var newVisibleBounds = new Rect();

switch (orientation)
Rect CalculateVisibleBounds(double excludedStatusBarHeight)
{
// StatusBar on top, NavigationBar on right
case DisplayOrientations.Landscape:
newVisibleBounds = new Rect(
x: newBounds.X + Insets.Left,
y: newBounds.Y + topHeightExcluded,
width: newBounds.Width - (Insets.Left + Math.Max(Insets.Right, navigationBarSizeExcluded)),
height: newBounds.Height - topHeightExcluded - Insets.Bottom
);
break;
// StatusBar on top, NavigationBar on left
case DisplayOrientations.LandscapeFlipped:
newVisibleBounds = new Rect(
x: newBounds.X + Math.Max(Insets.Left, navigationBarSizeExcluded),
y: newBounds.Y + topHeightExcluded,
width: newBounds.Width - (Math.Max(Insets.Left, navigationBarSizeExcluded) + Insets.Right),
height: newBounds.Height - topHeightExcluded - Insets.Bottom
);
break;
// StatusBar on top, NavigationBar on bottom
default:
newVisibleBounds = new Rect(
x: newBounds.X + Insets.Left,
y: newBounds.Y + topHeightExcluded,
width: newBounds.Width - (Insets.Left + Insets.Right),
height: newBounds.Height - topHeightExcluded - Math.Max(Insets.Bottom, navigationBarSizeExcluded)
);
break;
var topHeightExcluded = Math.Max(Insets.Top, excludedStatusBarHeight);
var newVisibleBounds = new Rect();

switch (orientation)
{
// StatusBar on top, NavigationBar on right
case DisplayOrientations.Landscape:
newVisibleBounds = new Rect(
x: newBounds.X + Insets.Left,
y: newBounds.Y + topHeightExcluded,
width: newBounds.Width - (Insets.Left + Math.Max(Insets.Right, navigationBarSizeExcluded)),
height: newBounds.Height - topHeightExcluded - Insets.Bottom
);
break;
// StatusBar on top, NavigationBar on left
case DisplayOrientations.LandscapeFlipped:
newVisibleBounds = new Rect(
x: newBounds.X + Math.Max(Insets.Left, navigationBarSizeExcluded),
y: newBounds.Y + topHeightExcluded,
width: newBounds.Width - (Math.Max(Insets.Left, navigationBarSizeExcluded) + Insets.Right),
height: newBounds.Height - topHeightExcluded - Insets.Bottom
);
break;
// StatusBar on top, NavigationBar on bottom
default:
newVisibleBounds = new Rect(
x: newBounds.X + Insets.Left,
y: newBounds.Y + topHeightExcluded,
width: newBounds.Width - (Insets.Left + Insets.Right),
height: newBounds.Height - topHeightExcluded - Math.Max(Insets.Bottom, navigationBarSizeExcluded)
);
break;
}

return newVisibleBounds;
}

ApplicationView.GetForCurrentView()?.SetVisibleBounds(newVisibleBounds);
var visibleBounds = CalculateVisibleBounds(statusBarSizeExcluded);
var trueVisibleBounds = CalculateVisibleBounds(statusBarSize);
ApplicationView.GetForCurrentView()?.SetVisibleBounds(visibleBounds);
ApplicationView.GetForCurrentView()?.SetTrueVisibleBounds(trueVisibleBounds);

if (Bounds != newBounds)
{
Expand Down Expand Up @@ -194,13 +208,11 @@ internal void UpdateInsetsWithVisibilities()
Insets = newInsets;
}

private double GetLogicalStatusBarSizeExcluded()
private double GetLogicalStatusBarSize()
{
var logicalStatusBarHeight = 0d;

// The real metrics excluded the StatusBar only if it is plain.
// We want to subtract it if it is translucent. Otherwise, it will be like we subtract it twice.
if (IsStatusBarVisible() && IsStatusBarTranslucent())
if (IsStatusBarVisible())
{
var resourceId = Android.Content.Res.Resources.System.GetIdentifier("status_bar_height", "dimen", "android");
if (resourceId > 0)
Expand Down
4 changes: 4 additions & 0 deletions src/Uno.UWP/UI/ViewManagement/ApplicationView.Android.cs
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,10 @@ public string Title
}
}

private Rect _trueVisibleBounds;

internal void SetTrueVisibleBounds(Rect trueVisibleBounds) => _trueVisibleBounds = trueVisibleBounds;

public bool TryEnterFullScreenMode()
{
CoreDispatcher.CheckThreadAccess();
Expand Down
14 changes: 14 additions & 0 deletions src/Uno.UWP/UI/ViewManagement/ApplicationView.cs
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,20 @@ public bool SetDesiredBoundsMode(global::Windows.UI.ViewManagement.ApplicationVi

public Foundation.Rect VisibleBounds { get; private set; }

/// <summary>
/// All other platforms: equivalent to <see cref="VisibleBounds"/>.
///
/// Android: returns the visible bounds taking the status bar into account. The status bar is not removed from <see cref="VisibleBounds"/>
/// on Android when it's opaque, on the grounds that the root managed view is already arranged below the status bar in y-direction by
/// default (unlike iOS), but in some cases the correct total height is needed, hence this property.
/// </summary>
internal Rect TrueVisibleBounds =>
#if __ANDROID__
_trueVisibleBounds;
#else
VisibleBounds;
#endif

public event global::Windows.Foundation.TypedEventHandler<global::Windows.UI.ViewManagement.ApplicationView, object> VisibleBoundsChanged;

[global::Uno.NotImplemented]
Expand Down

0 comments on commit 6c0ede3

Please sign in to comment.