* [Controls] Add repo for shell issue * [iOS] Allow specify SetPaddingInsets on the ShellContent * [iOS,Shell] Fix issue when disposing ToolbarItems of old page * [Controls] Add demo repo for #5466 * [Shell,Core] Fix navigating to a registered route * [Shell,Core] Add better exception messages for wrong or non existing content fixes #5081 * [Core,Shell,iOS,Android] Add FlyoutIcon property * [Controls] Make shell sample work on Android * [Controls,Android] Add ImageSource support to FlyoutIcon * [Android]Allow to set text on the back button * [Android] Create default text back button * [Controls] Add example to push with back button behavior * [Android] Fix back button tint color * [Android] Cleanup and refactor UpdateDrawerArrow * Update Xamarin.Forms.Platform.Android/Renderers/ShellToolbarTracker.cs Co-Authored-By: rmarinho <me@ruimarinho.net> * [iOS,Shell] Fix go back (Pop) when proving BackButtonBehavior * [iOS] Check the ParentViewController since we were push to it * [Android,iOS,Shell] Remove extra code implement feedback * removed old code * minor cleanup
This commit is contained in:
Родитель
eab93e53d1
Коммит
db7e702ecf
|
@ -12,11 +12,30 @@ namespace Xamarin.Forms.Controls.XamStore
|
|||
[XamlCompilation(XamlCompilationOptions.Compile)]
|
||||
public partial class StoreShell : Shell
|
||||
{
|
||||
public StoreShell ()
|
||||
public StoreShell()
|
||||
{
|
||||
InitializeComponent ();
|
||||
|
||||
CurrentItem = _storeItem;
|
||||
InitializeComponent();
|
||||
var fontFamily = "";
|
||||
switch (Device.RuntimePlatform)
|
||||
{
|
||||
case Device.iOS:
|
||||
fontFamily = "Ionicons";
|
||||
break;
|
||||
case Device.UWP:
|
||||
fontFamily = "Assets/Fonts/ionicons.ttf#ionicons";
|
||||
break;
|
||||
case Device.Android:
|
||||
default:
|
||||
fontFamily = "fonts/ionicons.ttf#";
|
||||
break;
|
||||
}
|
||||
FlyoutIcon = new FontImageSource
|
||||
{
|
||||
Glyph = "\uf2fb",
|
||||
FontFamily = fontFamily,
|
||||
Size = 20
|
||||
};
|
||||
CurrentItem = _storeItem;
|
||||
Routing.RegisterRoute("demo", typeof(DemoShellPage));
|
||||
Routing.RegisterRoute("demo/demo", typeof(DemoShellPage));
|
||||
}
|
||||
|
|
|
@ -35,7 +35,7 @@
|
|||
StyleClass="MainTab"
|
||||
HorizontalOptions="FillAndExpand"
|
||||
VerticalOptions="Fill"
|
||||
Image="button_bookmark.png"
|
||||
Image="icon_bookmark.png"
|
||||
Command="{Binding ToggleCommand}"
|
||||
CommandParameter="bookmarked">
|
||||
<Button.Triggers>
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
using System;
|
||||
using System;
|
||||
using System.ComponentModel;
|
||||
using System.Globalization;
|
||||
using System.Linq;
|
||||
|
|
|
@ -20,7 +20,7 @@ namespace Xamarin.Forms.Controls.XamStore
|
|||
public BasePage(string title, Color tint)
|
||||
{
|
||||
Title = title;
|
||||
|
||||
Shell.SetShellForegroundColor(this, tint);
|
||||
var grid = new Grid()
|
||||
{
|
||||
Padding = 20,
|
||||
|
@ -220,6 +220,19 @@ namespace Xamarin.Forms.Controls.XamStore
|
|||
async () => await Shell.CurrentShell.GoToAsync("demo", true)),
|
||||
1, 15);
|
||||
|
||||
grid.Children.Add(MakeButton("Go Back with Text",
|
||||
async () => {
|
||||
var page = (Page)Activator.CreateInstance(GetType());
|
||||
Shell.SetShellForegroundColor(page, Color.Pink);
|
||||
Shell.SetBackButtonBehavior(page, new BackButtonBehavior()
|
||||
{
|
||||
//IconOverride = "calculator.png",
|
||||
|
||||
TextOverride = "back"
|
||||
});
|
||||
await Navigation.PushAsync(page);
|
||||
}),2, 15);
|
||||
|
||||
grid.Children.Add(new Label {
|
||||
Text = "Navigate to",
|
||||
VerticalOptions = LayoutOptions.CenterAndExpand
|
||||
|
|
|
@ -21,6 +21,8 @@ namespace Xamarin.Forms
|
|||
|
||||
View FlyoutHeader { get; }
|
||||
|
||||
ImageSource FlyoutIcon { get; }
|
||||
|
||||
void AddAppearanceObserver(IAppearanceObserver observer, Element pivot);
|
||||
|
||||
void AddFlyoutBehaviorObserver(IFlyoutBehaviorObserver observer);
|
||||
|
|
|
@ -566,6 +566,9 @@ namespace Xamarin.Forms
|
|||
public static readonly BindableProperty MenuItemTemplateProperty =
|
||||
BindableProperty.Create(nameof(MenuItemTemplate), typeof(DataTemplate), typeof(Shell), null, BindingMode.OneTime);
|
||||
|
||||
public static readonly BindableProperty FlyoutIconProperty =
|
||||
BindableProperty.Create(nameof(FlyoutIcon), typeof(ImageSource), typeof(Shell), null);
|
||||
|
||||
ShellNavigatedEventArgs _accumulatedEvent;
|
||||
bool _accumulateNavigatedEvents;
|
||||
View _flyoutHeaderView;
|
||||
|
@ -587,6 +590,13 @@ namespace Xamarin.Forms
|
|||
public event EventHandler<ShellNavigatedEventArgs> Navigated;
|
||||
public event EventHandler<ShellNavigatingEventArgs> Navigating;
|
||||
|
||||
|
||||
public ImageSource FlyoutIcon
|
||||
{
|
||||
get => (ImageSource)GetValue(FlyoutIconProperty);
|
||||
set => SetValue(FlyoutIconProperty, value);
|
||||
}
|
||||
|
||||
public ShellItem CurrentItem {
|
||||
get => (ShellItem)GetValue(CurrentItemProperty);
|
||||
set => SetValue(CurrentItemProperty, value);
|
||||
|
|
|
@ -66,6 +66,25 @@ namespace Xamarin.Forms
|
|||
}
|
||||
}
|
||||
|
||||
public static float GetFontSizeNormal(Context context)
|
||||
{
|
||||
float size = 50;
|
||||
if (!IsLollipopOrNewer)
|
||||
return size;
|
||||
|
||||
// Android 5.0+
|
||||
//this doesn't seem to work
|
||||
using (var value = new TypedValue())
|
||||
{
|
||||
if (context.Theme.ResolveAttribute(Resource.Attribute.TextSize, value, true))
|
||||
{
|
||||
size = value.Data;
|
||||
}
|
||||
}
|
||||
|
||||
return size;
|
||||
}
|
||||
|
||||
public static Color GetColorButtonNormal(Context context)
|
||||
{
|
||||
if (!_ColorButtonNormalSet)
|
||||
|
|
|
@ -9,6 +9,7 @@ using Android.Views;
|
|||
using System;
|
||||
using System.Collections.Specialized;
|
||||
using System.ComponentModel;
|
||||
using System.Threading.Tasks;
|
||||
using ActionBarDrawerToggle = Android.Support.V7.App.ActionBarDrawerToggle;
|
||||
using AView = Android.Views.View;
|
||||
using LP = Android.Views.ViewGroup.LayoutParams;
|
||||
|
@ -130,7 +131,7 @@ namespace Xamarin.Forms.Platform.Android
|
|||
{
|
||||
UpdateTitleView(_shellContext.AndroidContext, _toolbar, null);
|
||||
|
||||
_drawerToggle.Dispose();
|
||||
_drawerToggle?.Dispose();
|
||||
if (_searchView != null)
|
||||
{
|
||||
_searchView.View.RemoveFromParent();
|
||||
|
@ -235,10 +236,85 @@ namespace Xamarin.Forms.Platform.Android
|
|||
var backButtonHandler = Shell.GetBackButtonBehavior(page);
|
||||
toolbar.SetNavigationOnClickListener(this);
|
||||
|
||||
var activity = (FormsAppCompatActivity)context;
|
||||
|
||||
if (backButtonHandler != null)
|
||||
{
|
||||
using (var icon = await context.GetFormsDrawable(backButtonHandler.IconOverride))
|
||||
using (var mutatedIcon = icon.GetConstantState().NewDrawable().Mutate())
|
||||
await UpdateDrawerArrowFromBackButtonBehavior(context, toolbar, drawerLayout, backButtonHandler, activity);
|
||||
}
|
||||
else
|
||||
{
|
||||
await UpdateDrawerArrow(context, toolbar, drawerLayout, activity);
|
||||
}
|
||||
}
|
||||
|
||||
protected virtual async Task UpdateDrawerArrow(Context context, Toolbar toolbar, DrawerLayout drawerLayout, FormsAppCompatActivity activity)
|
||||
{
|
||||
if (_drawerToggle == null)
|
||||
{
|
||||
_drawerToggle = new ActionBarDrawerToggle((Activity)context, drawerLayout, toolbar,
|
||||
R.String.Ok, R.String.Ok)
|
||||
{
|
||||
ToolbarNavigationClickListener = this,
|
||||
};
|
||||
|
||||
await UpdateDrawerArrowFromFlyoutIcon(context, _drawerToggle);
|
||||
|
||||
_drawerToggle.DrawerSlideAnimationEnabled = false;
|
||||
drawerLayout.AddDrawerListener(_drawerToggle);
|
||||
}
|
||||
|
||||
if (CanNavigateBack)
|
||||
{
|
||||
_drawerToggle.DrawerIndicatorEnabled = false;
|
||||
using (var icon = new DrawerArrowDrawable(activity.SupportActionBar.ThemedContext))
|
||||
{
|
||||
icon.SetColorFilter(TintColor.ToAndroid(Color.White), PorterDuff.Mode.SrcAtop);
|
||||
icon.Progress = 1;
|
||||
toolbar.NavigationIcon = icon;
|
||||
}
|
||||
}
|
||||
else if (_flyoutBehavior == FlyoutBehavior.Flyout)
|
||||
{
|
||||
toolbar.NavigationIcon = null;
|
||||
var drawable = _drawerToggle.DrawerArrowDrawable;
|
||||
drawable.SetColorFilter(TintColor.ToAndroid(Color.White), PorterDuff.Mode.SrcAtop);
|
||||
_drawerToggle.DrawerIndicatorEnabled = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
_drawerToggle.DrawerIndicatorEnabled = false;
|
||||
}
|
||||
_drawerToggle.SyncState();
|
||||
}
|
||||
|
||||
protected virtual async Task UpdateDrawerArrowFromBackButtonBehavior(Context context, Toolbar toolbar, DrawerLayout drawerLayout, BackButtonBehavior backButtonHandler, FormsAppCompatActivity activity)
|
||||
{
|
||||
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.GetFormsDrawable(image);
|
||||
|
||||
if (text != null)
|
||||
icon = new FlyoutIconDrawerDrawable(context, TintColor, icon, text);
|
||||
|
||||
if (CanNavigateBack && icon == null)
|
||||
{
|
||||
icon = new DrawerArrowDrawable(activity.SupportActionBar.ThemedContext);
|
||||
(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;
|
||||
|
@ -246,40 +322,27 @@ namespace Xamarin.Forms.Platform.Android
|
|||
}
|
||||
else
|
||||
{
|
||||
var activity = (FormsAppCompatActivity)context;
|
||||
if (_drawerToggle == null)
|
||||
{
|
||||
_drawerToggle = new ActionBarDrawerToggle((Activity)context, drawerLayout, toolbar,
|
||||
R.String.Ok, R.String.Ok)
|
||||
{
|
||||
ToolbarNavigationClickListener = this,
|
||||
};
|
||||
_drawerToggle.DrawerSlideAnimationEnabled = false;
|
||||
drawerLayout.AddDrawerListener(_drawerToggle);
|
||||
}
|
||||
toolbar.NavigationIcon = icon;
|
||||
}
|
||||
}
|
||||
|
||||
if (CanNavigateBack)
|
||||
protected virtual async Task UpdateDrawerArrowFromFlyoutIcon(Context context, ActionBarDrawerToggle actionBarDrawerToggle)
|
||||
{
|
||||
Element item = Page;
|
||||
ImageSource icon = null;
|
||||
while (!Application.IsApplicationOrNull(item))
|
||||
{
|
||||
if (item is IShellController shell)
|
||||
{
|
||||
_drawerToggle.DrawerIndicatorEnabled = false;
|
||||
using (var icon = new DrawerArrowDrawable(activity.SupportActionBar.ThemedContext))
|
||||
icon = shell.FlyoutIcon;
|
||||
if (icon != null)
|
||||
{
|
||||
icon.SetColorFilter(TintColor.ToAndroid(Color.White), PorterDuff.Mode.SrcAtop);
|
||||
icon.Progress = 1;
|
||||
toolbar.NavigationIcon = icon;
|
||||
var drawable = await context.GetFormsDrawable(icon);
|
||||
actionBarDrawerToggle.DrawerArrowDrawable = new FlyoutIconDrawerDrawable(context, TintColor, drawable, null);
|
||||
}
|
||||
return;
|
||||
}
|
||||
else if (_flyoutBehavior == FlyoutBehavior.Flyout)
|
||||
{
|
||||
toolbar.NavigationIcon = null;
|
||||
using (var drawable = _drawerToggle.DrawerArrowDrawable)
|
||||
drawable.SetColorFilter(TintColor.ToAndroid(Color.White), PorterDuff.Mode.SrcAtop);
|
||||
_drawerToggle.DrawerIndicatorEnabled = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
_drawerToggle.DrawerIndicatorEnabled = false;
|
||||
}
|
||||
_drawerToggle.SyncState();
|
||||
item = item?.Parent;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -452,5 +515,51 @@ namespace Xamarin.Forms.Platform.Android
|
|||
{
|
||||
UpdateToolbarItems(_toolbar, Page);
|
||||
}
|
||||
|
||||
class FlyoutIconDrawerDrawable : DrawerArrowDrawable
|
||||
{
|
||||
Drawable _iconBitmap;
|
||||
string _text;
|
||||
Color _defaultColor;
|
||||
float _defaultSize;
|
||||
|
||||
Color _pressedBackgroundColor => _defaultColor.AddLuminosity(-.12);//<item name="highlight_alpha_material_light" format="float" type="dimen">0.12</item>
|
||||
|
||||
protected override void Dispose(bool disposing)
|
||||
{
|
||||
base.Dispose(disposing);
|
||||
if (disposing && _iconBitmap != null)
|
||||
{
|
||||
_iconBitmap.Dispose();
|
||||
}
|
||||
}
|
||||
|
||||
public FlyoutIconDrawerDrawable(Context context, Color defaultColor, Drawable icon, string text) : base(context)
|
||||
{
|
||||
_defaultColor = defaultColor;
|
||||
_defaultSize = Forms.GetFontSizeNormal(context);
|
||||
_iconBitmap = icon;
|
||||
_text = text;
|
||||
}
|
||||
|
||||
public override void Draw(Canvas canvas)
|
||||
{
|
||||
bool pressed = false;
|
||||
if (_iconBitmap != null)
|
||||
{
|
||||
_iconBitmap.SetBounds(Bounds.Left, Bounds.Top, Bounds.Right, Bounds.Bottom);
|
||||
_iconBitmap.Draw(canvas);
|
||||
}
|
||||
else if (!string.IsNullOrEmpty(_text))
|
||||
{
|
||||
var paint = new Paint { AntiAlias = true };
|
||||
paint.TextSize = _defaultSize;
|
||||
paint.Color = pressed ? _pressedBackgroundColor.ToAndroid() : _defaultColor.ToAndroid();
|
||||
paint.SetStyle(Paint.Style.Fill);
|
||||
var y = (Bounds.Height() + paint.TextSize) / 2;
|
||||
canvas.DrawText(_text, 0, y, paint);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -4,6 +4,7 @@ using System.Collections.Generic;
|
|||
using System.Collections.Specialized;
|
||||
using System.ComponentModel;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows.Input;
|
||||
using UIKit;
|
||||
|
||||
namespace Xamarin.Forms.Platform.iOS
|
||||
|
@ -198,24 +199,24 @@ namespace Xamarin.Forms.Platform.iOS
|
|||
var commandParameter = behavior.CommandParameter;
|
||||
var image = behavior.IconOverride;
|
||||
var enabled = behavior.IsEnabled;
|
||||
|
||||
if (image == null)
|
||||
{
|
||||
var text = BackButtonBehavior.TextOverride;
|
||||
NavigationItem.LeftBarButtonItem =
|
||||
new UIBarButtonItem(text, UIBarButtonItemStyle.Plain, (s, e) => command?.Execute(commandParameter)) { Enabled = enabled };
|
||||
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) => command?.Execute(commandParameter)) { Enabled = enabled };
|
||||
new UIBarButtonItem(icon, UIBarButtonItemStyle.Plain, (s, e) => LeftBarButtonItemHandler(ViewController, command, commandParameter, IsRootPage)) { Enabled = enabled };
|
||||
}
|
||||
}
|
||||
else if (IsRootPage && _flyoutBehavior == FlyoutBehavior.Flyout)
|
||||
{
|
||||
ImageSource image = "3bar.png";
|
||||
var icon = await image.GetNativeImageAsync();
|
||||
NavigationItem.LeftBarButtonItem = new UIBarButtonItem(icon, UIBarButtonItemStyle.Plain, OnMenuButtonPressed);
|
||||
|
||||
await SetDrawerArrowDrawableFromFlyoutIcon();
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -223,6 +224,35 @@ namespace Xamarin.Forms.Platform.iOS
|
|||
}
|
||||
}
|
||||
|
||||
static void LeftBarButtonItemHandler(UIViewController controller, ICommand command, object commandParameter, bool isRootPage)
|
||||
{
|
||||
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;
|
||||
}
|
||||
if (image == null)
|
||||
image = "3bar.png";
|
||||
var icon = await image.GetNativeImageAsync();
|
||||
NavigationItem.LeftBarButtonItem = new UIBarButtonItem(icon, UIBarButtonItemStyle.Plain, OnMenuButtonPressed);
|
||||
}
|
||||
|
||||
void OnMenuButtonPressed(object sender, EventArgs e)
|
||||
{
|
||||
_context.Shell.SetValueFromRenderer(Shell.FlyoutIsPresentedProperty, true);
|
||||
|
|
Загрузка…
Ссылка в новой задаче