зеркало из https://github.com/DeGsoft/maui-linux.git
985 строки
28 KiB
C#
985 строки
28 KiB
C#
using System;
|
|
using System.Collections.Generic;
|
|
using System.ComponentModel;
|
|
using System.Diagnostics;
|
|
using System.Drawing;
|
|
using System.Linq;
|
|
using System.Threading;
|
|
using System.Threading.Tasks;
|
|
using Xamarin.Forms.Internals;
|
|
using Xamarin.Forms.PlatformConfiguration.iOSSpecific;
|
|
#if __UNIFIED__
|
|
using UIKit;
|
|
using CoreGraphics;
|
|
#else
|
|
using MonoTouch.UIKit;
|
|
using MonoTouch.CoreGraphics;
|
|
#endif
|
|
#if __UNIFIED__
|
|
using RectangleF = CoreGraphics.CGRect;
|
|
using SizeF = CoreGraphics.CGSize;
|
|
using PointF = CoreGraphics.CGPoint;
|
|
|
|
#else
|
|
using nfloat = System.Single;
|
|
using nint = System.Int32;
|
|
using nuint = System.UInt32;
|
|
#endif
|
|
|
|
namespace Xamarin.Forms.Platform.iOS
|
|
{
|
|
public class NavigationRenderer : UINavigationController, IVisualElementRenderer, IEffectControlProvider
|
|
{
|
|
internal const string UpdateToolbarButtons = "Xamarin.UpdateToolbarButtons";
|
|
bool _appeared;
|
|
bool _ignorePopCall;
|
|
bool _loaded;
|
|
MasterDetailPage _parentMasterDetailPage;
|
|
Size _queuedSize;
|
|
UIViewController[] _removeControllers;
|
|
UIToolbar _secondaryToolbar;
|
|
VisualElementTracker _tracker;
|
|
|
|
public NavigationRenderer()
|
|
{
|
|
MessagingCenter.Subscribe<IVisualElementRenderer>(this, UpdateToolbarButtons, sender =>
|
|
{
|
|
if (!ViewControllers.Any())
|
|
return;
|
|
var parentingViewController = (ParentingViewController)ViewControllers.Last();
|
|
UpdateLeftBarButtonItem(parentingViewController);
|
|
});
|
|
|
|
|
|
}
|
|
|
|
Page Current { get; set; }
|
|
|
|
IPageController PageController => Element as IPageController;
|
|
|
|
public VisualElement Element { get; private set; }
|
|
|
|
public event EventHandler<VisualElementChangedEventArgs> ElementChanged;
|
|
|
|
public SizeRequest GetDesiredSize(double widthConstraint, double heightConstraint)
|
|
{
|
|
return NativeView.GetSizeRequest(widthConstraint, heightConstraint);
|
|
}
|
|
|
|
public UIView NativeView
|
|
{
|
|
get { return View; }
|
|
}
|
|
|
|
public void SetElement(VisualElement element)
|
|
{
|
|
var oldElement = Element;
|
|
Element = (NavigationPage)element;
|
|
OnElementChanged(new VisualElementChangedEventArgs(oldElement, element));
|
|
|
|
if (element != null)
|
|
element.SendViewInitialized(NativeView);
|
|
|
|
EffectUtilities.RegisterEffectControlProvider(this, oldElement, element);
|
|
}
|
|
|
|
public void SetElementSize(Size size)
|
|
{
|
|
if (_loaded)
|
|
Element.Layout(new Rectangle(Element.X, Element.Y, size.Width, size.Height));
|
|
else
|
|
_queuedSize = size;
|
|
}
|
|
|
|
public UIViewController ViewController
|
|
{
|
|
get { return this; }
|
|
}
|
|
|
|
public override void DidRotate(UIInterfaceOrientation fromInterfaceOrientation)
|
|
{
|
|
base.DidRotate(fromInterfaceOrientation);
|
|
|
|
View.SetNeedsLayout();
|
|
|
|
var parentingViewController = (ParentingViewController)ViewControllers.Last();
|
|
UpdateLeftBarButtonItem(parentingViewController);
|
|
}
|
|
|
|
public Task<bool> PopToRootAsync(Page page, bool animated = true)
|
|
{
|
|
return OnPopToRoot(page, animated);
|
|
}
|
|
|
|
public Task<bool> PopViewAsync(Page page, bool animated = true)
|
|
{
|
|
return OnPopViewAsync(page, animated);
|
|
}
|
|
|
|
public Task<bool> PushPageAsync(Page page, bool animated = true)
|
|
{
|
|
return OnPushAsync(page, animated);
|
|
}
|
|
|
|
public override void ViewDidAppear(bool animated)
|
|
{
|
|
if (!_appeared)
|
|
{
|
|
_appeared = true;
|
|
PageController?.SendAppearing();
|
|
}
|
|
|
|
base.ViewDidAppear(animated);
|
|
|
|
View.SetNeedsLayout();
|
|
}
|
|
|
|
public override void ViewDidDisappear(bool animated)
|
|
{
|
|
base.ViewDidDisappear(animated);
|
|
|
|
if (!_appeared || Element == null)
|
|
return;
|
|
|
|
_appeared = false;
|
|
PageController.SendDisappearing();
|
|
}
|
|
|
|
public override void ViewDidLayoutSubviews()
|
|
{
|
|
base.ViewDidLayoutSubviews();
|
|
UpdateToolBarVisible();
|
|
|
|
var navBarFrame = NavigationBar.Frame;
|
|
|
|
var toolbar = _secondaryToolbar;
|
|
// Use 0 if the NavBar is hidden or will be hidden
|
|
var toolbarY = NavigationBarHidden || !NavigationPage.GetHasNavigationBar(Current) ? 0 : navBarFrame.Bottom;
|
|
toolbar.Frame = new RectangleF(0, toolbarY, View.Frame.Width, toolbar.Frame.Height);
|
|
|
|
double trueBottom = toolbar.Hidden ? toolbarY : toolbar.Frame.Bottom;
|
|
var modelSize = _queuedSize.IsZero ? Element.Bounds.Size : _queuedSize;
|
|
PageController.ContainerArea =
|
|
new Rectangle(0, toolbar.Hidden ? 0 : toolbar.Frame.Height, modelSize.Width, modelSize.Height - trueBottom);
|
|
|
|
if (!_queuedSize.IsZero)
|
|
{
|
|
Element.Layout(new Rectangle(Element.X, Element.Y, _queuedSize.Width, _queuedSize.Height));
|
|
_queuedSize = Size.Zero;
|
|
}
|
|
|
|
_loaded = true;
|
|
|
|
foreach (var view in View.Subviews)
|
|
{
|
|
if (view == NavigationBar || view == _secondaryToolbar)
|
|
continue;
|
|
view.Frame = View.Bounds;
|
|
}
|
|
}
|
|
|
|
public override void ViewDidLoad()
|
|
{
|
|
base.ViewDidLoad();
|
|
|
|
if (Forms.IsiOS7OrNewer)
|
|
{
|
|
|
|
UpdateTranslucent();
|
|
}
|
|
else
|
|
WantsFullScreenLayout = false;
|
|
|
|
_secondaryToolbar = new SecondaryToolbar { Frame = new RectangleF(0, 0, 320, 44) };
|
|
View.Add(_secondaryToolbar);
|
|
_secondaryToolbar.Hidden = true;
|
|
|
|
FindParentMasterDetail();
|
|
|
|
var navPage = (NavigationPage)Element;
|
|
|
|
if (navPage.CurrentPage == null)
|
|
{
|
|
throw new InvalidOperationException(
|
|
"NavigationPage must have a root Page before being used. Either call PushAsync with a valid Page, or pass a Page to the constructor before usage.");
|
|
}
|
|
|
|
var navController = ((INavigationPageController)navPage);
|
|
|
|
navController.PushRequested += OnPushRequested;
|
|
navController.PopRequested += OnPopRequested;
|
|
navController.PopToRootRequested += OnPopToRootRequested;
|
|
navController.RemovePageRequested += OnRemovedPageRequested;
|
|
navController.InsertPageBeforeRequested += OnInsertPageBeforeRequested;
|
|
|
|
UpdateTint();
|
|
UpdateBarBackgroundColor();
|
|
UpdateBarTextColor();
|
|
|
|
// If there is already stuff on the stack we need to push it
|
|
((INavigationPageController)navPage).StackCopy.Reverse().ForEach(async p => await PushPageAsync(p, false));
|
|
|
|
_tracker = new VisualElementTracker(this);
|
|
|
|
Element.PropertyChanged += HandlePropertyChanged;
|
|
|
|
UpdateToolBarVisible();
|
|
UpdateBackgroundColor();
|
|
Current = navPage.CurrentPage;
|
|
}
|
|
|
|
protected override void Dispose(bool disposing)
|
|
{
|
|
if (disposing)
|
|
{
|
|
MessagingCenter.Unsubscribe<IVisualElementRenderer>(this, UpdateToolbarButtons);
|
|
|
|
foreach (var childViewController in ViewControllers)
|
|
childViewController.Dispose();
|
|
|
|
if (_tracker != null)
|
|
_tracker.Dispose();
|
|
|
|
_secondaryToolbar.RemoveFromSuperview();
|
|
_secondaryToolbar.Dispose();
|
|
_secondaryToolbar = null;
|
|
|
|
_parentMasterDetailPage = null;
|
|
Current = null; // unhooks events
|
|
|
|
var navPage = (NavigationPage)Element;
|
|
navPage.PropertyChanged -= HandlePropertyChanged;
|
|
|
|
var navController = ((INavigationPageController)navPage);
|
|
navController.PushRequested -= OnPushRequested;
|
|
navController.PopRequested -= OnPopRequested;
|
|
navController.PopToRootRequested -= OnPopToRootRequested;
|
|
navController.RemovePageRequested -= OnRemovedPageRequested;
|
|
navController.InsertPageBeforeRequested -= OnInsertPageBeforeRequested;
|
|
}
|
|
|
|
base.Dispose(disposing);
|
|
if (_appeared)
|
|
{
|
|
PageController.SendDisappearing();
|
|
|
|
_appeared = false;
|
|
}
|
|
}
|
|
|
|
protected virtual void OnElementChanged(VisualElementChangedEventArgs e)
|
|
{
|
|
var changed = ElementChanged;
|
|
if (changed != null)
|
|
changed(this, e);
|
|
}
|
|
|
|
protected virtual async Task<bool> OnPopToRoot(Page page, bool animated)
|
|
{
|
|
_ignorePopCall = true;
|
|
var renderer = Platform.GetRenderer(page);
|
|
if (renderer == null || renderer.ViewController == null)
|
|
return false;
|
|
|
|
var task = GetAppearedOrDisappearedTask(page);
|
|
|
|
PopToRootViewController(animated);
|
|
|
|
_ignorePopCall = false;
|
|
var success = !await task;
|
|
|
|
UpdateToolBarVisible();
|
|
return success;
|
|
}
|
|
|
|
protected virtual async Task<bool> OnPopViewAsync(Page page, bool animated)
|
|
{
|
|
if (_ignorePopCall)
|
|
return true;
|
|
|
|
var renderer = Platform.GetRenderer(page);
|
|
if (renderer == null || renderer.ViewController == null)
|
|
return false;
|
|
|
|
var actuallyRemoved = false;
|
|
|
|
if (page != ((ParentingViewController)TopViewController).Child)
|
|
throw new NotSupportedException("Popped page does not appear on top of current navigation stack, please file a bug.");
|
|
|
|
var task = GetAppearedOrDisappearedTask(page);
|
|
|
|
UIViewController poppedViewController;
|
|
#if __UNIFIED__
|
|
poppedViewController = base.PopViewController(animated);
|
|
#else
|
|
poppedViewController = base.PopViewControllerAnimated (animated);
|
|
#endif
|
|
|
|
if (poppedViewController == null)
|
|
{
|
|
// this happens only when the user does something REALLY dumb like pop right after putting the page as visible.
|
|
poppedViewController = TopViewController;
|
|
var newControllers = ViewControllers.Remove(poppedViewController);
|
|
ViewControllers = newControllers;
|
|
actuallyRemoved = true;
|
|
}
|
|
else
|
|
actuallyRemoved = !await task;
|
|
|
|
poppedViewController.Dispose();
|
|
|
|
UpdateToolBarVisible();
|
|
return actuallyRemoved;
|
|
}
|
|
|
|
protected virtual async Task<bool> OnPushAsync(Page page, bool animated)
|
|
{
|
|
var pack = CreateViewControllerForPage(page);
|
|
var task = GetAppearedOrDisappearedTask(page);
|
|
|
|
PushViewController(pack, animated);
|
|
|
|
var shown = await task;
|
|
UpdateToolBarVisible();
|
|
return shown;
|
|
}
|
|
|
|
ParentingViewController CreateViewControllerForPage(Page page)
|
|
{
|
|
if (Platform.GetRenderer(page) == null)
|
|
Platform.SetRenderer(page, Platform.CreateRenderer(page));
|
|
|
|
// must pack into container so padding can work
|
|
// otherwise the view controller is forced to 0,0
|
|
var pack = new ParentingViewController(this) { Child = page };
|
|
if (!string.IsNullOrWhiteSpace(page.Title))
|
|
pack.NavigationItem.Title = page.Title;
|
|
|
|
// First page and we have a master detail to contend with
|
|
UpdateLeftBarButtonItem(pack);
|
|
|
|
//var pack = Platform.GetRenderer (view).ViewController;
|
|
|
|
var titleIcon = NavigationPage.GetTitleIcon(page);
|
|
if (!string.IsNullOrEmpty(titleIcon))
|
|
{
|
|
try
|
|
{
|
|
//UIImage ctor throws on file not found if MonoTouch.ObjCRuntime.Class.ThrowOnInitFailure is true;
|
|
pack.NavigationItem.TitleView = new UIImageView(new UIImage(titleIcon));
|
|
}
|
|
catch
|
|
{
|
|
}
|
|
}
|
|
|
|
var titleText = NavigationPage.GetBackButtonTitle(page);
|
|
if (titleText != null)
|
|
{
|
|
pack.NavigationItem.BackBarButtonItem =
|
|
new UIBarButtonItem(titleText, UIBarButtonItemStyle.Plain, async (o, e) => await PopViewAsync(page));
|
|
}
|
|
|
|
var pageRenderer = Platform.GetRenderer(page);
|
|
pack.View.AddSubview(pageRenderer.ViewController.View);
|
|
pack.AddChildViewController(pageRenderer.ViewController);
|
|
pageRenderer.ViewController.DidMoveToParentViewController(pack);
|
|
|
|
return pack;
|
|
}
|
|
|
|
void FindParentMasterDetail()
|
|
{
|
|
var parentPages = ((Page)Element).GetParentPages();
|
|
var masterDetail = parentPages.OfType<MasterDetailPage>().FirstOrDefault();
|
|
|
|
if (masterDetail != null && parentPages.Append((Page)Element).Contains(masterDetail.Detail))
|
|
_parentMasterDetailPage = masterDetail;
|
|
}
|
|
|
|
Task<bool> GetAppearedOrDisappearedTask(Page page)
|
|
{
|
|
var tcs = new TaskCompletionSource<bool>();
|
|
|
|
var parentViewController = Platform.GetRenderer(page).ViewController.ParentViewController as ParentingViewController;
|
|
if (parentViewController == null)
|
|
throw new NotSupportedException("ParentingViewController parent could not be found. Please file a bug.");
|
|
|
|
EventHandler appearing = null, disappearing = null;
|
|
appearing = (s, e) =>
|
|
{
|
|
parentViewController.Appearing -= appearing;
|
|
parentViewController.Disappearing -= disappearing;
|
|
|
|
Device.BeginInvokeOnMainThread(() => { tcs.SetResult(true); });
|
|
};
|
|
|
|
disappearing = (s, e) =>
|
|
{
|
|
parentViewController.Appearing -= appearing;
|
|
parentViewController.Disappearing -= disappearing;
|
|
|
|
Device.BeginInvokeOnMainThread(() => { tcs.SetResult(false); });
|
|
};
|
|
|
|
parentViewController.Appearing += appearing;
|
|
parentViewController.Disappearing += disappearing;
|
|
|
|
return tcs.Task;
|
|
}
|
|
|
|
void HandlePropertyChanged(object sender, PropertyChangedEventArgs e)
|
|
{
|
|
#pragma warning disable 0618 //retaining legacy call to obsolete code
|
|
if (e.PropertyName == NavigationPage.TintProperty.PropertyName)
|
|
#pragma warning restore 0618
|
|
UpdateTint();
|
|
if (e.PropertyName == NavigationPage.BarBackgroundColorProperty.PropertyName)
|
|
UpdateBarBackgroundColor();
|
|
else if (e.PropertyName == NavigationPage.BarTextColorProperty.PropertyName)
|
|
UpdateBarTextColor();
|
|
else if (e.PropertyName == VisualElement.BackgroundColorProperty.PropertyName)
|
|
UpdateBackgroundColor();
|
|
else if (e.PropertyName == NavigationPage.CurrentPageProperty.PropertyName)
|
|
Current = ((NavigationPage)Element).CurrentPage;
|
|
else if (e.PropertyName == PlatformConfiguration.iOSSpecific.NavigationPage.IsNavigationBarTranslucentProperty.PropertyName)
|
|
UpdateTranslucent();
|
|
}
|
|
|
|
void UpdateTranslucent()
|
|
{
|
|
if (!Forms.IsiOS7OrNewer)
|
|
{
|
|
return;
|
|
}
|
|
|
|
NavigationBar.Translucent = ((NavigationPage)Element).OnThisPlatform().IsNavigationBarTranslucent();
|
|
}
|
|
|
|
void InsertPageBefore(Page page, Page before)
|
|
{
|
|
if (before == null)
|
|
throw new ArgumentNullException("before");
|
|
if (page == null)
|
|
throw new ArgumentNullException("page");
|
|
|
|
var pageContainer = CreateViewControllerForPage(page);
|
|
var target = Platform.GetRenderer(before).ViewController.ParentViewController;
|
|
ViewControllers = ViewControllers.Insert(ViewControllers.IndexOf(target), pageContainer);
|
|
}
|
|
|
|
void OnInsertPageBeforeRequested(object sender, NavigationRequestedEventArgs e)
|
|
{
|
|
InsertPageBefore(e.Page, e.BeforePage);
|
|
}
|
|
|
|
void OnPopRequested(object sender, NavigationRequestedEventArgs e)
|
|
{
|
|
e.Task = PopViewAsync(e.Page, e.Animated);
|
|
}
|
|
|
|
void OnPopToRootRequested(object sender, NavigationRequestedEventArgs e)
|
|
{
|
|
e.Task = PopToRootAsync(e.Page, e.Animated);
|
|
}
|
|
|
|
void OnPushRequested(object sender, NavigationRequestedEventArgs e)
|
|
{
|
|
e.Task = PushPageAsync(e.Page, e.Animated);
|
|
}
|
|
|
|
void OnRemovedPageRequested(object sender, NavigationRequestedEventArgs e)
|
|
{
|
|
RemovePage(e.Page);
|
|
}
|
|
|
|
void RemovePage(Page page)
|
|
{
|
|
if (page == null)
|
|
throw new ArgumentNullException("page");
|
|
if (page == Current)
|
|
throw new NotSupportedException(); // should never happen as NavPage protects against this
|
|
|
|
var target = Platform.GetRenderer(page).ViewController.ParentViewController;
|
|
|
|
// So the ViewControllers property is not very property like on iOS. Assigning to it doesn't cause it to be
|
|
// immediately reflected into the property. The change will not be reflected until there has been sufficient time
|
|
// to process it (it ends up on the event queue). So to resolve this issue we keep our own stack until we
|
|
// know iOS has processed it, and make sure any updates use that.
|
|
|
|
// In the future we may want to make RemovePageAsync and deprecate RemovePage to handle cases where Push/Pop is called
|
|
// during a remove cycle.
|
|
var parentingVC = target as ParentingViewController;
|
|
if (parentingVC != null)
|
|
parentingVC.IgnorePageBeingRemoved = true;
|
|
|
|
if (_removeControllers == null)
|
|
{
|
|
_removeControllers = ViewControllers.Remove(target);
|
|
ViewControllers = _removeControllers;
|
|
Device.BeginInvokeOnMainThread(() => { _removeControllers = null; });
|
|
}
|
|
else
|
|
{
|
|
_removeControllers = _removeControllers.Remove(target);
|
|
ViewControllers = _removeControllers;
|
|
}
|
|
var parentingViewController = ViewControllers.Last() as ParentingViewController;
|
|
UpdateLeftBarButtonItem(parentingViewController, page);
|
|
}
|
|
|
|
void UpdateBackgroundColor()
|
|
{
|
|
var color = Element.BackgroundColor == Color.Default ? Color.White : Element.BackgroundColor;
|
|
View.BackgroundColor = color.ToUIColor();
|
|
}
|
|
|
|
void UpdateBarBackgroundColor()
|
|
{
|
|
var barBackgroundColor = ((NavigationPage)Element).BarBackgroundColor;
|
|
// Set navigation bar background color
|
|
if (Forms.IsiOS7OrNewer)
|
|
{
|
|
NavigationBar.BarTintColor = barBackgroundColor == Color.Default
|
|
? UINavigationBar.Appearance.BarTintColor
|
|
: barBackgroundColor.ToUIColor();
|
|
}
|
|
else
|
|
{
|
|
NavigationBar.TintColor = barBackgroundColor == Color.Default
|
|
? UINavigationBar.Appearance.TintColor
|
|
: barBackgroundColor.ToUIColor();
|
|
}
|
|
}
|
|
|
|
void UpdateBarTextColor()
|
|
{
|
|
var barTextColor = ((NavigationPage)Element).BarTextColor;
|
|
|
|
var globalAttributes = UINavigationBar.Appearance.GetTitleTextAttributes();
|
|
|
|
if (barTextColor == Color.Default)
|
|
{
|
|
if (NavigationBar.TitleTextAttributes != null)
|
|
{
|
|
var attributes = new UIStringAttributes();
|
|
attributes.ForegroundColor = globalAttributes.TextColor;
|
|
attributes.Font = globalAttributes.Font;
|
|
NavigationBar.TitleTextAttributes = attributes;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
var titleAttributes = new UIStringAttributes();
|
|
titleAttributes.Font = globalAttributes.Font;
|
|
// TODO: the ternary if statement here will always return false because of the encapsulating if statement.
|
|
// What was the intention?
|
|
titleAttributes.ForegroundColor = barTextColor == Color.Default
|
|
? titleAttributes.ForegroundColor ?? UINavigationBar.Appearance.TintColor
|
|
: barTextColor.ToUIColor();
|
|
NavigationBar.TitleTextAttributes = titleAttributes;
|
|
}
|
|
|
|
// set Tint color (i. e. Back Button arrow and Text)
|
|
if (Forms.IsiOS7OrNewer)
|
|
{
|
|
NavigationBar.TintColor = barTextColor == Color.Default
|
|
? UINavigationBar.Appearance.TintColor
|
|
: barTextColor.ToUIColor();
|
|
}
|
|
|
|
if (barTextColor.Luminosity > 0.5)
|
|
{
|
|
// Use light text color for status bar
|
|
UIApplication.SharedApplication.StatusBarStyle = UIStatusBarStyle.LightContent;
|
|
}
|
|
else
|
|
{
|
|
// Use dark text color for status bar
|
|
UIApplication.SharedApplication.StatusBarStyle = UIStatusBarStyle.Default;
|
|
}
|
|
}
|
|
|
|
void UpdateLeftBarButtonItem(ParentingViewController containerController, Page pageBeingRemoved = null)
|
|
{
|
|
if (containerController == null)
|
|
return;
|
|
var currentChild = containerController.Child;
|
|
var firstPage = ((INavigationPageController)Element).StackCopy.LastOrDefault();
|
|
if ((firstPage != pageBeingRemoved && currentChild != firstPage && NavigationPage.GetHasBackButton(currentChild)) || _parentMasterDetailPage == null)
|
|
return;
|
|
|
|
if (!_parentMasterDetailPage.ShouldShowToolbarButton())
|
|
{
|
|
containerController.NavigationItem.LeftBarButtonItem = null;
|
|
return;
|
|
}
|
|
|
|
var shouldUseIcon = _parentMasterDetailPage.Master.Icon != null;
|
|
if (shouldUseIcon)
|
|
{
|
|
try
|
|
{
|
|
containerController.NavigationItem.LeftBarButtonItem =
|
|
new UIBarButtonItem(new UIImage(_parentMasterDetailPage.Master.Icon), UIBarButtonItemStyle.Plain,
|
|
(o, e) => _parentMasterDetailPage.IsPresented = !_parentMasterDetailPage.IsPresented);
|
|
}
|
|
catch (Exception)
|
|
{
|
|
// Throws Exception otherwise would catch more specific exception type
|
|
shouldUseIcon = false;
|
|
}
|
|
}
|
|
|
|
if (!shouldUseIcon)
|
|
{
|
|
containerController.NavigationItem.LeftBarButtonItem = new UIBarButtonItem(_parentMasterDetailPage.Master.Title,
|
|
UIBarButtonItemStyle.Plain,
|
|
(o, e) => _parentMasterDetailPage.IsPresented = !_parentMasterDetailPage.IsPresented);
|
|
}
|
|
}
|
|
|
|
void UpdateTint()
|
|
{
|
|
#pragma warning disable 0618 //retaining legacy call to obsolete code
|
|
var tintColor = ((NavigationPage)Element).Tint;
|
|
#pragma warning restore 0618
|
|
if (Forms.IsiOS7OrNewer)
|
|
{
|
|
NavigationBar.BarTintColor = tintColor == Color.Default
|
|
? UINavigationBar.Appearance.BarTintColor
|
|
: tintColor.ToUIColor();
|
|
if (tintColor == Color.Default)
|
|
NavigationBar.TintColor = UINavigationBar.Appearance.TintColor;
|
|
else
|
|
NavigationBar.TintColor = tintColor.Luminosity > 0.5 ? UIColor.Black : UIColor.White;
|
|
}
|
|
else
|
|
NavigationBar.TintColor = tintColor == Color.Default ? null : tintColor.ToUIColor();
|
|
}
|
|
|
|
void UpdateToolBarVisible()
|
|
{
|
|
if (_secondaryToolbar == null)
|
|
return;
|
|
if (TopViewController != null && TopViewController.ToolbarItems != null && TopViewController.ToolbarItems.Any())
|
|
{
|
|
_secondaryToolbar.Hidden = false;
|
|
_secondaryToolbar.Items = TopViewController.ToolbarItems;
|
|
}
|
|
else
|
|
{
|
|
_secondaryToolbar.Hidden = true;
|
|
//secondaryToolbar.Items = null;
|
|
}
|
|
}
|
|
|
|
class SecondaryToolbar : UIToolbar
|
|
{
|
|
readonly List<UIView> _lines = new List<UIView>();
|
|
|
|
public SecondaryToolbar()
|
|
{
|
|
TintColor = UIColor.White;
|
|
}
|
|
|
|
public override UIBarButtonItem[] Items
|
|
{
|
|
get { return base.Items; }
|
|
set
|
|
{
|
|
base.Items = value;
|
|
SetupLines();
|
|
}
|
|
}
|
|
|
|
public override void LayoutSubviews()
|
|
{
|
|
base.LayoutSubviews();
|
|
if (Items == null || Items.Length == 0)
|
|
return;
|
|
nfloat padding = 11f;
|
|
var itemWidth = (Bounds.Width - padding) / Items.Length - padding;
|
|
var x = padding;
|
|
var itemH = Bounds.Height - 10;
|
|
foreach (var item in Items)
|
|
{
|
|
var frame = new RectangleF(x, 5, itemWidth, itemH);
|
|
item.CustomView.Frame = frame;
|
|
x += itemWidth + padding;
|
|
}
|
|
x = itemWidth + padding * 1.5f;
|
|
var y = Bounds.GetMidY();
|
|
foreach (var l in _lines)
|
|
{
|
|
l.Center = new PointF(x, y);
|
|
x += itemWidth + padding;
|
|
}
|
|
}
|
|
|
|
void SetupLines()
|
|
{
|
|
_lines.ForEach(l => l.RemoveFromSuperview());
|
|
_lines.Clear();
|
|
if (Items == null)
|
|
return;
|
|
for (var i = 1; i < Items.Length; i++)
|
|
{
|
|
var l = new UIView(new RectangleF(0, 0, 1, 24)) { BackgroundColor = new UIColor(0, 0, 0, 0.2f) };
|
|
AddSubview(l);
|
|
_lines.Add(l);
|
|
}
|
|
}
|
|
}
|
|
|
|
class ParentingViewController : UIViewController
|
|
{
|
|
readonly WeakReference<NavigationRenderer> _navigation;
|
|
|
|
Page _child;
|
|
ToolbarTracker _tracker = new ToolbarTracker();
|
|
|
|
public ParentingViewController(NavigationRenderer navigation)
|
|
{
|
|
if (Forms.IsiOS7OrNewer)
|
|
AutomaticallyAdjustsScrollViewInsets = false;
|
|
|
|
_navigation = new WeakReference<NavigationRenderer>(navigation);
|
|
}
|
|
|
|
public Page Child
|
|
{
|
|
get { return _child; }
|
|
set
|
|
{
|
|
if (_child == value)
|
|
return;
|
|
|
|
if (_child != null)
|
|
_child.PropertyChanged -= HandleChildPropertyChanged;
|
|
|
|
_child = value;
|
|
|
|
if (_child != null)
|
|
_child.PropertyChanged += HandleChildPropertyChanged;
|
|
|
|
UpdateHasBackButton();
|
|
}
|
|
}
|
|
|
|
public bool IgnorePageBeingRemoved
|
|
{
|
|
get;
|
|
set;
|
|
}
|
|
|
|
public event EventHandler Appearing;
|
|
|
|
public override void DidRotate(UIInterfaceOrientation fromInterfaceOrientation)
|
|
{
|
|
base.DidRotate(fromInterfaceOrientation);
|
|
|
|
View.SetNeedsLayout();
|
|
}
|
|
|
|
public event EventHandler Disappearing;
|
|
|
|
public override void ViewDidAppear(bool animated)
|
|
{
|
|
base.ViewDidAppear(animated);
|
|
|
|
var handler = Appearing;
|
|
if (handler != null)
|
|
handler(this, EventArgs.Empty);
|
|
}
|
|
|
|
public override void ViewDidDisappear(bool animated)
|
|
{
|
|
base.ViewDidDisappear(animated);
|
|
|
|
var handler = Disappearing;
|
|
if (handler != null)
|
|
handler(this, EventArgs.Empty);
|
|
}
|
|
|
|
public override void ViewDidLayoutSubviews()
|
|
{
|
|
IVisualElementRenderer childRenderer;
|
|
if (Child != null && (childRenderer = Platform.GetRenderer(Child)) != null)
|
|
childRenderer.NativeView.Frame = Child.Bounds.ToRectangleF();
|
|
base.ViewDidLayoutSubviews();
|
|
}
|
|
|
|
public override void ViewDidLoad()
|
|
{
|
|
base.ViewDidLoad();
|
|
|
|
_tracker.Target = Child;
|
|
_tracker.AdditionalTargets = Child.GetParentPages();
|
|
_tracker.CollectionChanged += TrackerOnCollectionChanged;
|
|
|
|
UpdateToolbarItems();
|
|
}
|
|
|
|
public override void ViewWillAppear(bool animated)
|
|
{
|
|
UpdateNavigationBarVisibility(animated);
|
|
EdgesForExtendedLayout = UIRectEdge.None;
|
|
base.ViewWillAppear(animated);
|
|
}
|
|
|
|
public override async void DidMoveToParentViewController(UIViewController parent)
|
|
{
|
|
//If Parent of our child is already null we removed this using our API
|
|
//If we still have parent and we are removing our render we need to update our navigation
|
|
if (parent == null && !IgnorePageBeingRemoved)
|
|
{
|
|
NavigationRenderer n;
|
|
if (_navigation.TryGetTarget(out n))
|
|
{
|
|
var navController = n.Element as INavigationPageController;
|
|
await navController?.PopAsyncInner(true, true);
|
|
}
|
|
|
|
}
|
|
base.DidMoveToParentViewController(parent);
|
|
|
|
}
|
|
|
|
protected override void Dispose(bool disposing)
|
|
{
|
|
if (disposing)
|
|
{
|
|
((IPageController)Child).SendDisappearing();
|
|
Child = null;
|
|
_tracker.Target = null;
|
|
_tracker.CollectionChanged -= TrackerOnCollectionChanged;
|
|
_tracker = null;
|
|
|
|
if (NavigationItem.RightBarButtonItems != null)
|
|
{
|
|
for (var i = 0; i < NavigationItem.RightBarButtonItems.Length; i++)
|
|
NavigationItem.RightBarButtonItems[i].Dispose();
|
|
}
|
|
|
|
if (ToolbarItems != null)
|
|
{
|
|
for (var i = 0; i < ToolbarItems.Length; i++)
|
|
ToolbarItems[i].Dispose();
|
|
}
|
|
}
|
|
base.Dispose(disposing);
|
|
}
|
|
|
|
void HandleChildPropertyChanged(object sender, PropertyChangedEventArgs e)
|
|
{
|
|
if (e.PropertyName == NavigationPage.HasNavigationBarProperty.PropertyName)
|
|
UpdateNavigationBarVisibility(true);
|
|
else if (e.PropertyName == Page.TitleProperty.PropertyName)
|
|
NavigationItem.Title = Child.Title;
|
|
else if (e.PropertyName == NavigationPage.HasBackButtonProperty.PropertyName)
|
|
UpdateHasBackButton();
|
|
}
|
|
|
|
void TrackerOnCollectionChanged(object sender, EventArgs eventArgs)
|
|
{
|
|
UpdateToolbarItems();
|
|
}
|
|
|
|
void UpdateHasBackButton()
|
|
{
|
|
if (Child == null)
|
|
return;
|
|
|
|
NavigationItem.HidesBackButton = !NavigationPage.GetHasBackButton(Child);
|
|
}
|
|
|
|
void UpdateNavigationBarVisibility(bool animated)
|
|
{
|
|
var current = Child;
|
|
|
|
if (current == null || NavigationController == null)
|
|
return;
|
|
|
|
var hasNavBar = NavigationPage.GetHasNavigationBar(current);
|
|
|
|
if (NavigationController.NavigationBarHidden == hasNavBar)
|
|
NavigationController.SetNavigationBarHidden(!hasNavBar, animated);
|
|
}
|
|
|
|
void UpdateToolbarItems()
|
|
{
|
|
if (NavigationItem.RightBarButtonItems != null)
|
|
{
|
|
for (var i = 0; i < NavigationItem.RightBarButtonItems.Length; i++)
|
|
NavigationItem.RightBarButtonItems[i].Dispose();
|
|
}
|
|
if (ToolbarItems != null)
|
|
{
|
|
for (var i = 0; i < ToolbarItems.Length; i++)
|
|
ToolbarItems[i].Dispose();
|
|
}
|
|
|
|
List<UIBarButtonItem> primaries = null;
|
|
List<UIBarButtonItem> secondaries = null;
|
|
foreach (var item in _tracker.ToolbarItems)
|
|
{
|
|
if (item.Order == ToolbarItemOrder.Secondary)
|
|
(secondaries = secondaries ?? new List<UIBarButtonItem>()).Add(item.ToUIBarButtonItem(true));
|
|
else
|
|
(primaries = primaries ?? new List<UIBarButtonItem>()).Add(item.ToUIBarButtonItem());
|
|
}
|
|
|
|
if (primaries != null)
|
|
primaries.Reverse();
|
|
NavigationItem.SetRightBarButtonItems(primaries == null ? new UIBarButtonItem[0] : primaries.ToArray(), false);
|
|
ToolbarItems = secondaries == null ? new UIBarButtonItem[0] : secondaries.ToArray();
|
|
|
|
NavigationRenderer n;
|
|
if (_navigation.TryGetTarget(out n))
|
|
n.UpdateToolBarVisible();
|
|
}
|
|
|
|
public override UIInterfaceOrientationMask GetSupportedInterfaceOrientations()
|
|
{
|
|
IVisualElementRenderer childRenderer;
|
|
if (Child != null && (childRenderer = Platform.GetRenderer(Child)) != null)
|
|
return childRenderer.ViewController.GetSupportedInterfaceOrientations();
|
|
return base.GetSupportedInterfaceOrientations();
|
|
}
|
|
|
|
public override UIInterfaceOrientation PreferredInterfaceOrientationForPresentation()
|
|
{
|
|
IVisualElementRenderer childRenderer;
|
|
if (Child != null && (childRenderer = Platform.GetRenderer(Child)) != null)
|
|
return childRenderer.ViewController.PreferredInterfaceOrientationForPresentation();
|
|
return base.PreferredInterfaceOrientationForPresentation();
|
|
}
|
|
|
|
public override bool ShouldAutorotate()
|
|
{
|
|
IVisualElementRenderer childRenderer;
|
|
if (Child != null && (childRenderer = Platform.GetRenderer(Child)) != null)
|
|
return childRenderer.ViewController.ShouldAutorotate();
|
|
return base.ShouldAutorotate();
|
|
}
|
|
|
|
public override bool ShouldAutorotateToInterfaceOrientation(UIInterfaceOrientation toInterfaceOrientation)
|
|
{
|
|
IVisualElementRenderer childRenderer;
|
|
if (Child != null && (childRenderer = Platform.GetRenderer(Child)) != null)
|
|
return childRenderer.ViewController.ShouldAutorotateToInterfaceOrientation(toInterfaceOrientation);
|
|
return base.ShouldAutorotateToInterfaceOrientation(toInterfaceOrientation);
|
|
}
|
|
|
|
public override bool ShouldAutomaticallyForwardRotationMethods => true;
|
|
}
|
|
|
|
void IEffectControlProvider.RegisterEffect(Effect effect)
|
|
{
|
|
var platformEffect = effect as PlatformEffect;
|
|
if (platformEffect != null)
|
|
platformEffect.Container = View;
|
|
}
|
|
}
|
|
} |