[Shell] Fix back button behavior so that it only applies the property you've set opposed to replacing the entire thing (#6762)

* Fix backbutton behavior to only apply what you've set opposed to replacing everything

* - move GetPropertyIfSet to Core.Internals

* - make GetPropertyIfSet public.
fixes #5744
This commit is contained in:
Shane Neuville 2019-08-16 15:22:14 -06:00 коммит произвёл Samantha Houts
Родитель 659fa4faac
Коммит 9311b5f489
6 изменённых файлов: 484 добавлений и 177 удалений

Просмотреть файл

@ -0,0 +1,203 @@
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Text;
using Xamarin.Forms.CustomAttributes;
using Xamarin.Forms.Internals;
using System.Linq;
using Xamarin.Forms.PlatformConfiguration;
using Xamarin.Forms.PlatformConfiguration.iOSSpecific;
using System.Threading;
using System.ComponentModel;
#if UITEST
using Xamarin.UITest;
using NUnit.Framework;
using Xamarin.Forms.Core.UITests;
#endif
namespace Xamarin.Forms.Controls.Issues
{
[Preserve(AllMembers = true)]
[Issue(IssueTracker.None, 0, "Shell Back Button Behavior Test",
PlatformAffected.All)]
#if UITEST
[NUnit.Framework.Category(UITestCategories.Shell)]
#endif
public class ShellBackButtonBehavior : TestShell
{
const string EntryCommandParameter = "EntryCommandParameter";
const string ToggleBehaviorId = "ToggleBehaviorId";
const string ToggleCommandId = "ToggleCommandId";
const string ToggleCommandCanExecuteId = "ToggleCommandCanExecuteId";
const string ToggleIconId = "ToggleIconId";
const string ToggleIsEnabledId = "ToggleIsEnabledId";
const string ToggleTextId = "ToggleTextId";
const string CommandResultId = "CommandResult";
const string PushPageId = "PushPageId";
protected override void Init()
{
AddContentPage(new BackButtonPage());
}
public class BackButtonPage : ContentPage
{
BackButtonBehavior behavior = new BackButtonBehavior();
Entry _commandParameter;
Label _commandResult = new Label() { AutomationId = CommandResultId };
public BackButtonPage()
{
_commandParameter = new Entry()
{
Placeholder = "Command Parameter",
AutomationId = EntryCommandParameter
};
_commandParameter.TextChanged += (_, __) =>
{
if (String.IsNullOrWhiteSpace(_commandParameter.Text))
behavior.ClearValue(BackButtonBehavior.CommandParameterProperty);
else
behavior.CommandParameter = _commandParameter.Text;
};
StackLayout layout = new StackLayout();
layout.Children.Add(new Label()
{
Text = "Test setting different Back Button Behavior properties"
});
layout.Children.Add(new Button()
{
Text = "Toggle Behavior",
Command = new Command(ToggleBehavior),
AutomationId = ToggleBehaviorId
});
layout.Children.Add(new Button()
{
Text = "Toggle Command",
Command = new Command(ToggleCommand),
AutomationId = ToggleCommandId
});
layout.Children.Add(new Button()
{
Text = "Toggle Command Can Execute",
Command = new Command(ToggleCommandIsEnabled),
AutomationId = ToggleCommandCanExecuteId
});
layout.Children.Add(_commandParameter);
layout.Children.Add(_commandResult);
layout.Children.Add(new Button()
{
Text = "Toggle Text",
Command = new Command(ToggleBackButtonText),
AutomationId = ToggleTextId
});
layout.Children.Add(new Button()
{
Text = "Toggle Icon",
Command = new Command(ToggleIcon),
AutomationId = ToggleIconId
});
layout.Children.Add(new Button()
{
Text = "Toggle Is Enabled",
Command = new Command(ToggleIsEnabled),
AutomationId = ToggleIsEnabledId
});
layout.Children.Add(new Button()
{
Text = "Push Page",
Command = new Command(PushPage),
AutomationId = PushPageId
});
Content = layout;
ToggleBehavior();
}
async void PushPage(object obj)
{
await Navigation.PushAsync(new BackButtonPage());
}
public void ToggleBehavior()
{
if (this.IsSet(Shell.BackButtonBehaviorProperty))
this.ClearValue(Shell.BackButtonBehaviorProperty);
else
this.SetValue(Shell.BackButtonBehaviorProperty, behavior);
}
public void ToggleCommand()
{
if (behavior.Command == null)
behavior.Command = new Command<string>(result =>
{
_commandResult.Text = result;
}, (_) => canExecute);
else
behavior.ClearValue(BackButtonBehavior.CommandProperty);
}
bool canExecute = true;
public void ToggleCommandIsEnabled()
{
canExecute = !canExecute;
if (behavior.Command is Command command)
command.ChangeCanExecute();
}
public void ToggleBackButtonText()
{
if (!String.IsNullOrWhiteSpace(behavior.TextOverride))
behavior.ClearValue(BackButtonBehavior.TextOverrideProperty);
else
behavior.TextOverride = "Text";
}
public void ToggleIcon()
{
if (behavior.IsSet(BackButtonBehavior.IconOverrideProperty))
behavior.ClearValue(BackButtonBehavior.IconOverrideProperty);
else
behavior.IconOverride = "coffee.png";
}
public void ToggleIsEnabled()
{
behavior.IsEnabled = !behavior.IsEnabled;
}
}
#if UITEST && (__IOS__ || __ANDROID__)
[Test]
public void CommandTest()
{
RunningApp.Tap(ToggleCommandId);
RunningApp.EnterText(EntryCommandParameter, "parameter");
ShowFlyout();
var commandResult = RunningApp.WaitForElement(CommandResultId)[0].ReadText();
Assert.AreEqual(commandResult, "parameter");
RunningApp.EnterText(EntryCommandParameter, "canexecutetest");
RunningApp.Tap(ToggleCommandCanExecuteId);
commandResult = RunningApp.WaitForElement(CommandResultId)[0].ReadText();
Assert.AreEqual(commandResult, "parameter");
}
#endif
}
}

Просмотреть файл

@ -637,8 +637,33 @@ namespace Xamarin.Forms.Controls
Items.Add(item);
return page;
}
public ShellItem AddContentPage(ContentPage contentPage)
{
ContentPage page = new ContentPage();
ShellItem item = new ShellItem()
{
Items =
{
new ShellSection()
{
Items =
{
new ShellContent()
{
Content = contentPage
}
}
}
}
};
Items.Add(item);
return item;
}
#if UITEST
[SetUp]
public void Setup()

Просмотреть файл

@ -24,6 +24,7 @@
<Compile Include="$(MSBuildThisFileDirectory)Issue7061.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Issue7111.cs" />
<Compile Include="$(MSBuildThisFileDirectory)ShellGestures.cs" />
<Compile Include="$(MSBuildThisFileDirectory)ShellBackButtonBehavior.cs" />
<Compile Include="$(MSBuildThisFileDirectory)ShellInsets.cs" />
<Compile Include="$(MSBuildThisFileDirectory)CollectionViewGrouping.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Issue5412.cs" />

Просмотреть файл

@ -56,5 +56,16 @@ namespace Xamarin.Forms
Binding binding = Binding.Create(sourceProperty, mode, converter, stringFormat: stringFormat);
self.SetBinding(targetProperty, binding);
}
public static T GetPropertyIfSet<T>(this BindableObject bindableObject, BindableProperty bindableProperty, T returnIfNotSet)
{
if (bindableObject == null)
return returnIfNotSet;
if (bindableObject.IsSet(bindableProperty))
return (T)bindableObject.GetValue(bindableProperty);
return returnIfNotSet;
}
}
}

Просмотреть файл

@ -10,11 +10,13 @@ using System;
using System.Collections.Specialized;
using System.ComponentModel;
using System.Threading.Tasks;
using System.Windows.Input;
using ActionBarDrawerToggle = Android.Support.V7.App.ActionBarDrawerToggle;
using AView = Android.Views.View;
using LP = Android.Views.ViewGroup.LayoutParams;
using R = Android.Resource;
using Toolbar = Android.Support.V7.Widget.Toolbar;
using ADrawableCompat = Android.Support.V4.Graphics.Drawable.DrawableCompat;
namespace Xamarin.Forms.Platform.Android
{
@ -47,7 +49,6 @@ namespace Xamarin.Forms.Platform.Android
//assume the default
Color _tintColor = Color.Default;
Toolbar _toolbar;
string _defaultNavigationContentDescription;
public ShellToolbarTracker(IShellContext shellContext, Toolbar toolbar, DrawerLayout drawerLayout)
{
@ -55,6 +56,7 @@ namespace Xamarin.Forms.Platform.Android
_toolbar = toolbar ?? throw new ArgumentNullException(nameof(toolbar));
_drawerLayout = drawerLayout ?? throw new ArgumentNullException(nameof(drawerLayout));
_toolbar.SetNavigationOnClickListener(this);
((IShellController)_shellContext.Shell).AddFlyoutBehaviorObserver(this);
}
@ -114,45 +116,55 @@ namespace Xamarin.Forms.Platform.Android
void AView.IOnClickListener.OnClick(AView v)
{
var backButtonHandler = Shell.GetBackButtonBehavior(Page);
if (backButtonHandler?.Command != null)
backButtonHandler.Command.Execute(backButtonHandler.CommandParameter);
else if (CanNavigateBack)
OnNavigateBack();
else
_shellContext.Shell.FlyoutIsPresented = !_shellContext.Shell.FlyoutIsPresented;
var isEnabled = backButtonHandler.GetPropertyIfSet(BackButtonBehavior.IsEnabledProperty, true);
if (isEnabled)
{
if (backButtonHandler?.Command != null)
backButtonHandler.Command.Execute(backButtonHandler.CommandParameter);
else if (CanNavigateBack)
OnNavigateBack();
else
_shellContext.Shell.FlyoutIsPresented = !_shellContext.Shell.FlyoutIsPresented;
}
v.Dispose();
}
protected override void Dispose(bool disposing)
{
if (!_disposed)
if (_disposed)
return;
if (disposing)
{
if (disposing)
UpdateTitleView(_shellContext.AndroidContext, _toolbar, null);
_drawerToggle?.Dispose();
if (_searchView != null)
{
UpdateTitleView(_shellContext.AndroidContext, _toolbar, null);
_drawerToggle?.Dispose();
if (_searchView != null)
{
_searchView.View.RemoveFromParent();
_searchView.View.ViewAttachedToWindow -= OnSearchViewAttachedToWindow;
_searchView.SearchConfirmed -= OnSearchConfirmed;
_searchView.Dispose();
}
((IShellController)_shellContext.Shell).RemoveFlyoutBehaviorObserver(this);
_searchView.View.RemoveFromParent();
_searchView.View.ViewAttachedToWindow -= OnSearchViewAttachedToWindow;
_searchView.SearchConfirmed -= OnSearchConfirmed;
_searchView.Dispose();
}
SearchHandler = null;
_shellContext = null;
_drawerToggle = null;
_searchView = null;
Page = null;
_toolbar = null;
_drawerLayout = null;
_disposed = true;
((IShellController)_shellContext.Shell).RemoveFlyoutBehaviorObserver(this);
if (_backButtonBehavior != null)
_backButtonBehavior.PropertyChanged -= OnBackButtonBehaviorChanged;
}
_backButtonBehavior = null;
SearchHandler = null;
_shellContext = null;
_drawerToggle = null;
_searchView = null;
Page = null;
_toolbar = null;
_drawerLayout = null;
_disposed = true;
base.Dispose(disposing);
}
protected virtual IShellSearchView GetSearchView(Context context)
@ -169,6 +181,9 @@ namespace Xamarin.Forms.Platform.Android
{
if (oldPage != null)
{
if (_backButtonBehavior != null)
_backButtonBehavior.PropertyChanged -= OnBackButtonBehaviorChanged;
oldPage.PropertyChanged -= OnPagePropertyChanged;
((INotifyCollectionChanged)oldPage.ToolbarItems).CollectionChanged -= OnPageToolbarItemsChanged;
}
@ -176,6 +191,11 @@ namespace Xamarin.Forms.Platform.Android
if (newPage != null)
{
newPage.PropertyChanged += OnPagePropertyChanged;
_backButtonBehavior = Shell.GetBackButtonBehavior(newPage);
if (_backButtonBehavior != null)
_backButtonBehavior.PropertyChanged += OnBackButtonBehaviorChanged;
((INotifyCollectionChanged)newPage.ToolbarItems).CollectionChanged += OnPageToolbarItemsChanged;
UpdatePageTitle(_toolbar, newPage);
@ -186,6 +206,7 @@ namespace Xamarin.Forms.Platform.Android
}
}
BackButtonBehavior _backButtonBehavior = null;
protected virtual void OnPagePropertyChanged(object sender, PropertyChangedEventArgs e)
{
if (e.PropertyName == Page.TitleProperty.PropertyName)
@ -195,11 +216,52 @@ namespace Xamarin.Forms.Platform.Android
else if (e.PropertyName == Shell.NavBarIsVisibleProperty.PropertyName)
UpdateNavBarVisible(_toolbar, Page);
else if (e.PropertyName == Shell.BackButtonBehaviorProperty.PropertyName)
{
var backButtonHandler = Shell.GetBackButtonBehavior(Page);
if (_backButtonBehavior != null)
_backButtonBehavior.PropertyChanged -= OnBackButtonBehaviorChanged;
UpdateLeftBarButtonItem();
_backButtonBehavior = backButtonHandler;
if (_backButtonBehavior != null)
_backButtonBehavior.PropertyChanged += OnBackButtonBehaviorChanged;
}
else if (e.PropertyName == Shell.TitleViewProperty.PropertyName)
UpdateTitleView();
}
void OnBackButtonBehaviorChanged(object sender, PropertyChangedEventArgs e)
{
if(e.PropertyName == BackButtonBehavior.IsEnabledProperty.PropertyName)
{
UpdateBackButtonBehaviorIsEnabled();
_drawerToggle.SyncState();
}
UpdateLeftBarButtonItem();
}
void UpdateBackButtonBehaviorIsEnabled()
{
if (_drawerLayout == null || _drawerToggle == null)
return;
bool isEnabled = _backButtonBehavior?.IsEnabled ?? true;
if (isEnabled)
{
_drawerLayout.SetDrawerLockMode(DrawerLayout.LockModeUnlocked);
_drawerToggle.OnDrawerStateChanged(DrawerLayout.LockModeUnlocked);
}
else
{
_drawerLayout.SetDrawerLockMode(DrawerLayout.LockModeLockedClosed);
_drawerToggle.OnDrawerStateChanged(DrawerLayout.LockModeLockedClosed);
}
}
protected virtual void OnPageToolbarItemsChanged(object sender, NotifyCollectionChangedEventArgs e)
{
UpdateToolbarItems();
@ -233,26 +295,10 @@ namespace Xamarin.Forms.Platform.Android
}
protected virtual async void UpdateLeftBarButtonItem(Context context, Toolbar toolbar, DrawerLayout drawerLayout, Page page)
{
var backButtonHandler = Shell.GetBackButtonBehavior(page);
toolbar.SetNavigationOnClickListener(this);
if (backButtonHandler != null)
{
await UpdateDrawerArrowFromBackButtonBehavior(context, toolbar, drawerLayout, backButtonHandler);
}
else
{
await UpdateDrawerArrow(context, toolbar, drawerLayout);
}
}
protected virtual async Task UpdateDrawerArrow(Context context, Toolbar toolbar, DrawerLayout drawerLayout)
{
if (_drawerToggle == null && !context.IsDesignerContext())
{
_drawerToggle = new ActionBarDrawerToggle(context.GetActivity(), drawerLayout, toolbar, R.String.Ok, R.String.Ok)
{
ToolbarNavigationClickListener = this,
};
@ -263,104 +309,99 @@ namespace Xamarin.Forms.Platform.Android
drawerLayout.AddDrawerListener(_drawerToggle);
}
if (CanNavigateBack)
var backButtonHandler = Shell.GetBackButtonBehavior(page);
var image = backButtonHandler.GetPropertyIfSet<ImageSource>(BackButtonBehavior.IconOverrideProperty, null);
var text = backButtonHandler.GetPropertyIfSet(BackButtonBehavior.TextOverrideProperty, String.Empty);
var command = backButtonHandler.GetPropertyIfSet<ICommand>(BackButtonBehavior.CommandProperty, null);
if (image == null)
{
_drawerToggle.DrawerIndicatorEnabled = false;
using (var icon = new DrawerArrowDrawable(context.GetThemedContext()))
Element item = page;
while (!Application.IsApplicationOrNull(item))
{
icon.SetColorFilter(TintColor.ToAndroid(Color.White), PorterDuff.Mode.SrcAtop);
icon.Progress = 1;
toolbar.NavigationIcon = icon;
if (item is IShellController shell)
{
image = shell.FlyoutIcon;
break;
}
item = item?.Parent;
}
}
else if (_flyoutBehavior == FlyoutBehavior.Flyout)
DrawerArrowDrawable icon = null;
var tintColor = Color.White;
if (TintColor != Color.Default)
tintColor = TintColor;
if (image != null)
{
toolbar.NavigationIcon = null;
var drawable = _drawerToggle.DrawerArrowDrawable;
drawable.SetColorFilter(TintColor.ToAndroid(Color.White), PorterDuff.Mode.SrcAtop);
_drawerToggle.DrawerIndicatorEnabled = true;
var customIcon = await context.GetFormsDrawableAsync(image);
if(customIcon != null)
icon = new FlyoutIconDrawerDrawable(context, tintColor, customIcon, text);
}
else
if (!String.IsNullOrWhiteSpace(text) && icon == null)
icon = new FlyoutIconDrawerDrawable(context, tintColor, icon, text);
if(icon == null)
{
icon = new DrawerArrowDrawable(context.GetThemedContext());
ADrawableCompat.SetTint(icon, tintColor.ToAndroid());
ADrawableCompat.SetTintMode(icon, PorterDuff.Mode.SrcAtop);
}
icon.Progress = (CanNavigateBack) ? 1 : 0;
if (command != null || CanNavigateBack)
{
_drawerToggle.DrawerIndicatorEnabled = false;
toolbar.NavigationIcon = icon;
}
else
{
toolbar.NavigationIcon = null;
_drawerToggle.DrawerIndicatorEnabled = true;
_drawerToggle.DrawerArrowDrawable = icon;
}
UpdateBackButtonBehaviorIsEnabled();
_drawerToggle.SyncState();
//this needs to be set after SyncState
UpdateToolbarIconAccessibilityText(toolbar, _shellContext.Shell);
}
protected virtual Task UpdateDrawerArrow(Context context, Toolbar toolbar, DrawerLayout drawerLayout)
{
return Task.CompletedTask;
}
protected virtual void UpdateToolbarIconAccessibilityText(Toolbar toolbar, Shell shell)
{
//if AutomationId was specified the user wants to use UITests and interact with FlyoutIcon
if (!string.IsNullOrEmpty(shell.FlyoutIcon?.AutomationId))
{
if (_defaultNavigationContentDescription == null)
_defaultNavigationContentDescription = toolbar.NavigationContentDescription;
toolbar.NavigationContentDescription = shell.FlyoutIcon.AutomationId;
}
else
else if(toolbar.SetNavigationContentDescription(_shellContext.Shell.FlyoutIcon) == null)
{
toolbar.SetNavigationContentDescription(_shellContext.Shell.FlyoutIcon, _defaultNavigationContentDescription);
toolbar.SetNavigationContentDescription(R.String.Ok);
}
}
protected virtual async Task UpdateDrawerArrowFromBackButtonBehavior(Context context, Toolbar toolbar, DrawerLayout drawerLayout, BackButtonBehavior backButtonHandler)
protected virtual Task UpdateDrawerArrowFromBackButtonBehavior(Context context, Toolbar toolbar, DrawerLayout drawerLayout, BackButtonBehavior backButtonHandler)
{
var behavior = backButtonHandler;
var command = behavior.Command;
var commandParameter = behavior.CommandParameter;
var image = behavior.IconOverride;
var text = behavior.TextOverride;
var enabled = behavior.IsEnabled;
Drawable icon = null;
if (image != null)
icon = await context.GetFormsDrawableAsync(image);
if (text != null)
icon = new FlyoutIconDrawerDrawable(context, TintColor, icon, text);
if (CanNavigateBack && icon == null)
{
icon = new DrawerArrowDrawable(context.GetThemedContext());
(icon as DrawerArrowDrawable).Progress = 1;
}
var iconState = icon.GetConstantState();
if (iconState != null)
{
using (var mutatedIcon = iconState.NewDrawable().Mutate())
{
mutatedIcon.SetColorFilter(TintColor.ToAndroid(Color.White), PorterDuff.Mode.SrcAtop);
toolbar.NavigationIcon = mutatedIcon;
}
}
else
{
toolbar.NavigationIcon = icon;
}
return Task.CompletedTask;
}
protected virtual async Task UpdateDrawerArrowFromFlyoutIcon(Context context, ActionBarDrawerToggle actionBarDrawerToggle)
protected virtual Task UpdateDrawerArrowFromFlyoutIcon(Context context, ActionBarDrawerToggle actionBarDrawerToggle)
{
Element item = Page;
ImageSource icon = null;
while (!Application.IsApplicationOrNull(item))
{
if (item is IShellController shell)
{
icon = shell.FlyoutIcon;
if (icon != null)
{
var drawable = await context.GetFormsDrawableAsync(icon);
actionBarDrawerToggle.DrawerArrowDrawable = new FlyoutIconDrawerDrawable(context, TintColor, drawable, null);
}
return;
}
item = item?.Parent;
}
return Task.CompletedTask;
}
protected virtual void UpdateMenuItemIcon(Context context, IMenuItem menuItem, ToolbarItem toolBarItem)
@ -564,6 +605,9 @@ namespace Xamarin.Forms.Platform.Android
bool pressed = false;
if (_iconBitmap != null)
{
ADrawableCompat.SetTint(_iconBitmap, _defaultColor.ToAndroid());
ADrawableCompat.SetTintMode(_iconBitmap, PorterDuff.Mode.SrcAtop);
_iconBitmap.SetBounds(Bounds.Left, Bounds.Top, Bounds.Right, Bounds.Bottom);
_iconBitmap.Draw(canvas);
}

Просмотреть файл

@ -75,8 +75,18 @@ namespace Xamarin.Forms.Platform.iOS
protected virtual async void OnBackButtonBehaviorPropertyChanged(object sender, PropertyChangedEventArgs e)
{
if (e.PropertyName == BackButtonBehavior.CommandParameterProperty.PropertyName)
if (e.PropertyName == BackButtonBehavior.CommandProperty.PropertyName)
return;
else if (e.PropertyName == BackButtonBehavior.CommandParameterProperty.PropertyName)
return;
else if (e.PropertyName == BackButtonBehavior.IsEnabledProperty.PropertyName)
{
if (NavigationItem?.LeftBarButtonItem != null)
NavigationItem.LeftBarButtonItem.Enabled = BackButtonBehavior.IsEnabled;
return;
}
await UpdateToolbarItems().ConfigureAwait(false);
}
@ -199,79 +209,78 @@ namespace Xamarin.Forms.Platform.iOS
items.Reverse();
NavigationItem.SetRightBarButtonItems(items.ToArray(), false);
if (BackButtonBehavior != null)
{
var behavior = BackButtonBehavior;
var command = behavior.Command;
var commandParameter = behavior.CommandParameter;
var image = behavior.IconOverride;
var enabled = behavior.IsEnabled;
var behavior = BackButtonBehavior;
if (image == null)
{
var text = BackButtonBehavior.TextOverride;
NavigationItem.LeftBarButtonItem =
new UIBarButtonItem(text, UIBarButtonItemStyle.Plain, (s, e) => LeftBarButtonItemHandler(ViewController, command, commandParameter, IsRootPage)) { Enabled = enabled };
}
else
{
var icon = await image.GetNativeImageAsync();
NavigationItem.LeftBarButtonItem =
new UIBarButtonItem(icon, UIBarButtonItemStyle.Plain, (s, e) => LeftBarButtonItemHandler(ViewController, command, commandParameter, IsRootPage)) { Enabled = enabled };
}
}
else if (IsRootPage && _flyoutBehavior == FlyoutBehavior.Flyout)
{
var image = behavior.GetPropertyIfSet<ImageSource>(BackButtonBehavior.IconOverrideProperty, null);
var enabled = behavior.GetPropertyIfSet(BackButtonBehavior.IsEnabledProperty, true);
var text = behavior.GetPropertyIfSet(BackButtonBehavior.TextOverrideProperty, String.Empty);
UIImage icon = null;
await SetDrawerArrowDrawableFromFlyoutIcon();
}
else
if (image == null && String.IsNullOrWhiteSpace(text) && (!IsRootPage || _flyoutBehavior != FlyoutBehavior.Flyout))
{
NavigationItem.LeftBarButtonItem = null;
}
else
{
if (String.IsNullOrWhiteSpace(text) && image == null)
{
Element item = Page;
while (!Application.IsApplicationOrNull(item))
{
if (item is IShellController shell)
{
image = shell.FlyoutIcon;
item = null;
}
item = item?.Parent;
}
}
if (image != null)
icon = await image.GetNativeImageAsync();
else if (String.IsNullOrWhiteSpace(text))
icon = DrawHamburger();
if (icon == null)
{
NavigationItem.LeftBarButtonItem =
new UIBarButtonItem(text, UIBarButtonItemStyle.Plain, (s, e) => LeftBarButtonItemHandler(ViewController, IsRootPage)) { Enabled = enabled };
}
else
{
NavigationItem.LeftBarButtonItem =
new UIBarButtonItem(icon, UIBarButtonItemStyle.Plain, (s, e) => LeftBarButtonItemHandler(ViewController, IsRootPage)) { Enabled = enabled };
}
if (String.IsNullOrWhiteSpace(image?.AutomationId))
NavigationItem.LeftBarButtonItem.AccessibilityIdentifier = "OK";
else
NavigationItem.LeftBarButtonItem.AccessibilityIdentifier = image.AutomationId;
if (image != null)
{
NavigationItem.LeftBarButtonItem.SetAccessibilityHint(image);
NavigationItem.LeftBarButtonItem.SetAccessibilityLabel(image);
}
}
}
static void LeftBarButtonItemHandler(UIViewController controller, ICommand command, object commandParameter, bool isRootPage)
void LeftBarButtonItemHandler(UIViewController controller, bool isRootPage)
{
var behavior = BackButtonBehavior;
var command = behavior.GetPropertyIfSet(BackButtonBehavior.CommandProperty, new Command(() => OnMenuButtonPressed(this, EventArgs.Empty)));
var commandParameter = behavior.GetPropertyIfSet<object>(BackButtonBehavior.CommandParameterProperty, null);
if (command == null && !isRootPage && controller?.ParentViewController is UINavigationController navigationController)
{
navigationController.PopViewController(true);
return;
}
command?.Execute(commandParameter);
}
async Task SetDrawerArrowDrawableFromFlyoutIcon()
{
Element item = Page;
ImageSource image = null;
while (!Application.IsApplicationOrNull(item))
{
if (item is IShellController shell)
{
image = shell.FlyoutIcon;
item = null;
}
item = item?.Parent;
}
UIImage icon = null;
if (image != null)
icon = await image.GetNativeImageAsync();
else
icon = DrawHamburger();
var barButtonItem = new UIBarButtonItem(icon, UIBarButtonItemStyle.Plain, OnMenuButtonPressed);
barButtonItem.AccessibilityIdentifier = "OK";
NavigationItem.LeftBarButtonItem = barButtonItem;
if (image == null)
return;
NavigationItem.LeftBarButtonItem.AccessibilityIdentifier = image.AutomationId;
NavigationItem.LeftBarButtonItem.SetAccessibilityHint(image);
NavigationItem.LeftBarButtonItem.SetAccessibilityLabel(image);
}
UIImage DrawHamburger()
{
@ -323,19 +332,29 @@ namespace Xamarin.Forms.Platform.iOS
return;
if (BackButtonBehavior != null)
{
BackButtonBehavior.PropertyChanged -= OnBackButtonBehaviorPropertyChanged;
}
BackButtonBehavior = value;
if (BackButtonBehavior != null)
{
BackButtonBehavior.PropertyChanged += OnBackButtonBehaviorPropertyChanged;
}
await UpdateToolbarItems().ConfigureAwait(false);
}
void OnBackButtonCommandCanExecuteChanged(object sender, EventArgs e)
{
if (NavigationItem?.LeftBarButtonItem == null)
return;
bool isEnabled = BackButtonBehavior.GetPropertyIfSet<bool>(BackButtonBehavior.IsEnabledProperty, true);
if (isEnabled && sender is ICommand command)
isEnabled = command.CanExecute(BackButtonBehavior?.CommandParameter);
NavigationItem.LeftBarButtonItem.Enabled = isEnabled;
}
public class TitleViewContainer : UIContainerView
{
public TitleViewContainer(View view) : base(view)
@ -588,11 +607,15 @@ namespace Xamarin.Forms.Platform.iOS
Page.PropertyChanged -= OnPagePropertyChanged;
((INotifyCollectionChanged)Page.ToolbarItems).CollectionChanged -= OnToolbarItemsChanged;
((IShellController)_context.Shell).RemoveFlyoutBehaviorObserver(this);
if (BackButtonBehavior != null)
BackButtonBehavior.PropertyChanged -= OnBackButtonBehaviorPropertyChanged;
}
SearchHandler = null;
Page = null;
SetBackButtonBehavior(null);
BackButtonBehavior = null;
_rendererRef = null;
NavigationItem = null;
_searchHandlerAppearanceTracker = null;