[Shell] Add FlyoutIcon (#5567) fixes #4766 fixes #4767 fixes #4845 fixes #5219

* [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:
Rui Marinho 2019-03-27 17:05:21 +00:00 коммит произвёл GitHub
Родитель eab93e53d1
Коммит db7e702ecf
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: 4AEE18F83AFDEB23
12 изменённых файлов: 252 добавлений и 50 удалений

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

@ -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);