Skip to content

Commit

Permalink
Fix TitleView swapping behavior on Android/WinUI (#6195)
Browse files Browse the repository at this point in the history
* Fix TitleView swapping behavior on Android/WinUI

* - fix tests
  • Loading branch information
PureWeen authored Apr 18, 2022
1 parent 9ac65b0 commit 9a38741
Show file tree
Hide file tree
Showing 13 changed files with 253 additions and 53 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -198,6 +198,8 @@ protected override void Dispose(bool disposing)
_drawerLayout.RemoveDrawerListener(_drawerToggle);
_drawerToggle?.Dispose();

_toolbar?.Handler?.DisconnectHandler();
_toolbar = null;
_platformToolbar.RemoveAllViews();
}

Expand Down
83 changes: 58 additions & 25 deletions src/Controls/src/Core/HandlerImpl/Toolbar/Toolbar.Android.cs
Original file line number Diff line number Diff line change
Expand Up @@ -9,13 +9,14 @@
using Google.Android.Material.AppBar;
using Microsoft.Maui.Controls.Platform;
using Microsoft.Maui.Handlers;
using LP = Android.Views.ViewGroup.LayoutParams;

namespace Microsoft.Maui.Controls
{
public partial class Toolbar
{
IViewHandler? _nativeTitleViewHandler;
Container? _nativeTitleView;
IViewHandler? _platformTitleViewHandler;
Container? _platformTitleView;
List<IMenuItem> _currentMenuItems = new List<IMenuItem>();
List<ToolbarItem> _currentToolbarItems = new List<ToolbarItem>();

Expand All @@ -24,6 +25,17 @@ public partial class Toolbar

MaterialToolbar PlatformView => Handler?.PlatformView as MaterialToolbar ?? throw new InvalidOperationException("Native View not set");

partial void OnHandlerChanging(IElementHandler oldHandler, IElementHandler newHandler)
{
if (newHandler == null)
{
if (_platformTitleView != null)
_platformTitleView.Child = null;

_platformTitleViewHandler?.DisconnectHandler();
}
}

void OnToolbarItemPropertyChanged(object? sender, PropertyChangedEventArgs e)
{
var toolbarItems = ToolbarItems;
Expand Down Expand Up @@ -57,39 +69,45 @@ void UpdateTitleView()
_ = MauiContext.Context ?? throw new ArgumentNullException(nameof(MauiContext.Context));

VisualElement titleView = TitleView;
if (_nativeTitleViewHandler != null)
if (_platformTitleViewHandler != null)
{
var reflectableType = _nativeTitleViewHandler as System.Reflection.IReflectableType;
var rendererType = reflectableType != null ? reflectableType.GetTypeInfo().AsType() : _nativeTitleViewHandler.GetType();
if (titleView == null || Internals.Registrar.Registered.GetHandlerTypeForObject(titleView) != rendererType)
Type? rendererType = null;

if (titleView != null)
rendererType = MauiContext.Handlers.GetHandlerType(titleView.GetType());

if (titleView == null || titleView.Handler?.GetType() != rendererType)
{
if (_nativeTitleView != null)
_nativeTitleView.Child = null;
if (_platformTitleView != null)
_platformTitleView.Child = null;

if (_nativeTitleViewHandler?.VirtualView != null)
_nativeTitleViewHandler.VirtualView.Handler = null;
if (_platformTitleViewHandler?.VirtualView != null)
_platformTitleViewHandler.VirtualView.Handler = null;

_nativeTitleViewHandler = null;
_platformTitleViewHandler = null;
}
}

if (titleView == null)
return;

if (_nativeTitleViewHandler != null)
_nativeTitleViewHandler.SetVirtualView(titleView);
if (_platformTitleViewHandler != null)
_platformTitleViewHandler.SetVirtualView(titleView);
else
{
titleView.ToPlatform(MauiContext);
_nativeTitleViewHandler = titleView.Handler;
_platformTitleViewHandler = titleView.Handler;

if (_nativeTitleView == null)
if (_platformTitleView == null)
{
_nativeTitleView = new Container(MauiContext.Context);
PlatformView.AddView(_nativeTitleView);
var context = MauiContext.Context!;
_platformTitleView = new Container(context);
var layoutParams = new MaterialToolbar.LayoutParams(LP.MatchParent, LP.MatchParent);
_platformTitleView.LayoutParameters = layoutParams;
PlatformView.AddView(_platformTitleView);
}

_nativeTitleView.Child = (IPlatformViewHandler?)_nativeTitleViewHandler;
_platformTitleView.Child = (IPlatformViewHandler?)_platformTitleViewHandler;
}
}

Expand Down Expand Up @@ -155,13 +173,18 @@ public IPlatformViewHandler? Child
{
set
{
if (_child != null)
RemoveView(_child.PlatformView);
_child?.DisconnectHandler();
RemoveAllViews();

_child = value;

if (value != null)
AddView(value.PlatformView);
if (_child != null)
{
var platformView = _child.ToPlatform();
platformView.RemoveFromParent();
if (platformView != null)
AddView(platformView);
}
}
}

Expand All @@ -170,7 +193,8 @@ protected override void OnLayout(bool changed, int l, int t, int r, int b)
if (_child?.PlatformView == null)
return;

_child.PlatformView.Layout(l, t, r, b);
var destination = Context!.ToCrossPlatformRectInReferenceFrame(l, t, r, b);
_child?.VirtualView?.Arrange(destination);
}

protected override void OnMeasure(int widthMeasureSpec, int heightMeasureSpec)
Expand All @@ -181,8 +205,17 @@ protected override void OnMeasure(int widthMeasureSpec, int heightMeasureSpec)
return;
}

_child.PlatformView.Measure(widthMeasureSpec, heightMeasureSpec);
SetMeasuredDimension(_child.PlatformView.MeasuredWidth, _child.PlatformView.MeasuredHeight);
var width = widthMeasureSpec.GetSize();
var height = heightMeasureSpec.GetSize();

if (width * height == 0)
{
SetMeasuredDimension(0, 0);
return;
}

_child?.VirtualView?.Measure(widthMeasureSpec.ToDouble(Context!), heightMeasureSpec.ToDouble(Context!));
SetMeasuredDimension(width, height);
}
}
}
Expand Down
3 changes: 2 additions & 1 deletion src/Controls/src/Core/NavigationPageToolbar.cs
Original file line number Diff line number Diff line change
Expand Up @@ -230,7 +230,8 @@ void OnPropertyChanged(object sender, System.ComponentModel.PropertyChangedEvent

Color GetBarTextColor() => _currentNavigationPage?.BarTextColor;
Color GetIconColor() => (_currentPage != null) ? NavigationPage.GetIconColor(_currentPage) : null;
string GetTitle() => _currentPage?.Title;
string GetTitle() => GetTitleView() != null ? String.Empty : _currentPage?.Title;

VisualElement GetTitleView()
{
if (_currentNavigationPage == null)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,71 +11,80 @@ namespace Microsoft.Maui.Controls.Platform
{
internal static class ToolbarExtensions
{
public static void UpdateIsVisible(this MauiToolbar nativeToolbar, Toolbar toolbar)
public static void UpdateIsVisible(this MauiToolbar platformToolbar, Toolbar toolbar)
{
nativeToolbar.Visibility = (toolbar.IsVisible) ? UI.Xaml.Visibility.Visible : UI.Xaml.Visibility.Collapsed;
platformToolbar.Visibility = (toolbar.IsVisible) ? UI.Xaml.Visibility.Visible : UI.Xaml.Visibility.Collapsed;
}

public static void UpdateTitleIcon(this MauiToolbar nativeToolbar, Toolbar toolbar)
public static void UpdateTitleIcon(this MauiToolbar platformToolbar, Toolbar toolbar)
{
_ = toolbar?.Handler?.MauiContext ?? throw new ArgumentNullException(nameof(toolbar.Handler.MauiContext));
toolbar.TitleIcon.LoadImage(toolbar.Handler.MauiContext, (result) =>
{
if (result != null)
{
nativeToolbar.TitleIconImageSource = result.Value;
platformToolbar.TitleIconImageSource = result.Value;
toolbar.Handler.UpdateValue(nameof(Toolbar.IconColor));
}
else
nativeToolbar.TitleIconImageSource = null;
platformToolbar.TitleIconImageSource = null;
});
}

public static void UpdateBackButton(this MauiToolbar nativeToolbar, Toolbar toolbar)
public static void UpdateBackButton(this MauiToolbar platformToolbar, Toolbar toolbar)
{
nativeToolbar.IsBackEnabled =
platformToolbar.IsBackEnabled =
toolbar.BackButtonEnabled && toolbar.BackButtonVisible;

nativeToolbar
platformToolbar
.IsBackButtonVisible = (toolbar.BackButtonVisible) ? NavigationViewBackButtonVisible.Visible : NavigationViewBackButtonVisible.Collapsed;

toolbar.Handler?.UpdateValue(nameof(Toolbar.BarBackground));
}

public static void UpdateBarBackground(this MauiToolbar nativeToolbar, Toolbar toolbar)
public static void UpdateBarBackground(this MauiToolbar platformToolbar, Toolbar toolbar)
{
nativeToolbar.Background = toolbar.BarBackground?.ToBrush();
platformToolbar.Background = toolbar.BarBackground?.ToBrush();
}

public static void UpdateTitleView(this MauiToolbar nativeToolbar, Toolbar toolbar)
public static void UpdateTitleView(this MauiToolbar platformToolbar, Toolbar toolbar)
{
_ = toolbar.Handler?.MauiContext ?? throw new ArgumentNullException(nameof(toolbar.Handler.MauiContext));

nativeToolbar.TitleView = toolbar.TitleView?.ToPlatform(toolbar.Handler.MauiContext);
platformToolbar.TitleView = toolbar.TitleView?.ToPlatform(toolbar.Handler.MauiContext);

if (toolbar.TitleView is IView view)
{
platformToolbar.TitleViewMargin = view.Margin.ToPlatform();
}
else
{
platformToolbar.TitleViewMargin = new UI.Xaml.Thickness(0);
}
}

public static void UpdateIconColor(this MauiToolbar nativeToolbar, Toolbar toolbar)
public static void UpdateIconColor(this MauiToolbar platformToolbar, Toolbar toolbar)
{
// This property wasn't wired up in Controls
}

public static void UpdateTitle(this MauiToolbar nativeToolbar, Toolbar toolbar)
public static void UpdateTitle(this MauiToolbar platformToolbar, Toolbar toolbar)
{
nativeToolbar.Title = toolbar.Title;
platformToolbar.Title = toolbar.Title;
}

public static void UpdateBarTextColor(this MauiToolbar nativeToolbar, Toolbar toolbar)
public static void UpdateBarTextColor(this MauiToolbar platformToolbar, Toolbar toolbar)
{
if (toolbar.BarTextColor != null)
nativeToolbar.TitleColor = toolbar.BarTextColor.ToPlatform();
platformToolbar.TitleColor = toolbar.BarTextColor.ToPlatform();
}

public static void UpdateToolbarDynamicOverflowEnabled(this MauiToolbar nativeToolbar, Toolbar toolbar)
public static void UpdateToolbarDynamicOverflowEnabled(this MauiToolbar platformToolbar, Toolbar toolbar)
{
if (nativeToolbar.CommandBar == null)
if (platformToolbar.CommandBar == null)
return;

nativeToolbar.CommandBar.IsDynamicOverflowEnabled = toolbar.DynamicOverflowEnabled;
platformToolbar.CommandBar.IsDynamicOverflowEnabled = toolbar.DynamicOverflowEnabled;
}
}
}
15 changes: 10 additions & 5 deletions src/Controls/src/Core/ShellToolbar.cs
Original file line number Diff line number Diff line change
Expand Up @@ -94,10 +94,6 @@ internal void ApplyChanges()

UpdateTitle();

TitleView = _shell.GetEffectiveValue<VisualElement>(
Shell.TitleViewProperty,
Shell.GetTitleView(_shell));

if (_currentPage != null &&
_currentPage.IsSet(Shell.NavBarIsVisibleProperty))
{
Expand Down Expand Up @@ -169,8 +165,17 @@ void OnCurrentPagePropertyChanged(object sender, System.ComponentModel.PropertyC

internal void UpdateTitle()
{
Page currentPage = _shell.GetCurrentShellPage() as Page;
TitleView = _shell.GetEffectiveValue<VisualElement>(
Shell.TitleViewProperty,
Shell.GetTitleView(_shell));

if (TitleView != null)
{
Title = String.Empty;
return;
}

Page currentPage = _shell.GetCurrentShellPage() as Page;
if (currentPage?.IsSet(Page.TitleProperty) == true)
{
Title = currentPage.Title ?? String.Empty;
Expand Down
16 changes: 14 additions & 2 deletions src/Controls/src/Core/Toolbar.cs
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,8 @@ public partial class Toolbar : Maui.IToolbar, INotifyPropertyChanged
bool _backButtonVisible;
bool _backButtonEnabled = true;
bool _drawerToggleVisible;
Maui.IElement _parent;
IElementHandler _handler;

public Toolbar(Maui.IElement parent)
{
Expand All @@ -43,10 +45,20 @@ public Toolbar(Maui.IElement parent)
public bool BackButtonEnabled { get => _backButtonEnabled; set => SetProperty(ref _backButtonEnabled, value); }
public virtual bool DrawerToggleVisible { get => _drawerToggleVisible; set => SetProperty(ref _drawerToggleVisible, value); }
public bool IsVisible { get => _isVisible; set => SetProperty(ref _isVisible, value); }
public IElementHandler Handler { get; set; }
public IElementHandler Handler
{
get => _handler;
set
{
if (_handler == value)
return;

Maui.IElement _parent;
OnHandlerChanging(_handler, value);
_handler = value;
}
}

partial void OnHandlerChanging(IElementHandler oldHandler, IElementHandler newHandler);
public event PropertyChangedEventHandler PropertyChanged;

public Maui.IElement Parent => _parent;
Expand Down
21 changes: 21 additions & 0 deletions src/Controls/tests/Core.UnitTests/ShellToolbarTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -188,5 +188,26 @@ public void BackButtonBehaviorBindingContextPropagationWithExistingBindingContex

Assert.AreEqual(page.BindingContext, backButtonBehavior.BindingContext);
}

[Test]
public async Task TitleAndTitleViewAreMutuallyExclusive()
{
var contentPage = new ContentPage() { Title = "Test Title" };
var titleView = new VerticalStackLayout();

TestShell testShell = new TestShell(contentPage);
var window = new Window()
{
Page = testShell
};

var toolbar = testShell.Toolbar;
Assert.AreEqual("Test Title", toolbar.Title);
Shell.SetTitleView(contentPage, titleView);
Assert.IsEmpty(toolbar.Title);
Assert.AreEqual(titleView, toolbar.TitleView);
Shell.SetTitleView(contentPage, null);
Assert.AreEqual("Test Title", toolbar.Title);
}
}
}
19 changes: 19 additions & 0 deletions src/Controls/tests/Core.UnitTests/ToolbarTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,25 @@ public void ToolbarClearsWhenNavigationPageRemoved()
Assert.IsNull(toolbarElement.Toolbar);
}

[Test]
public async Task TitleAndTitleViewAreMutuallyExclusive()
{
var window = new Window();
IToolbarElement toolbarElement = window;
var contentPage = new ContentPage() { Title = "Test Title" };
var navigationPage = new NavigationPage(contentPage);
window.Page = navigationPage;

var titleView = new VerticalStackLayout();
var toolbar = (Toolbar)toolbarElement.Toolbar;
Assert.AreEqual("Test Title", toolbar.Title);
NavigationPage.SetTitleView(contentPage, titleView);
Assert.IsEmpty(toolbar.Title);
Assert.AreEqual(titleView, toolbar.TitleView);
NavigationPage.SetTitleView(contentPage, null);
Assert.AreEqual("Test Title", toolbar.Title);
}

[Test]
public async Task InsertPageBeforeRootPageShowsBackButton()
{
Expand Down
Loading

0 comments on commit 9a38741

Please sign in to comment.