diff --git a/Xamarin.Forms.Controls/CoreGallery.cs b/Xamarin.Forms.Controls/CoreGallery.cs index d01820d7f..df0452889 100644 --- a/Xamarin.Forms.Controls/CoreGallery.cs +++ b/Xamarin.Forms.Controls/CoreGallery.cs @@ -387,7 +387,7 @@ namespace Xamarin.Forms.Controls if (navigationBehavior == NavigationBehavior.PushAsync && rootPage.GetType () == typeof (CoreNavigationPage)) { _pages.Insert (0, new GalleryPageFactory(() => new NavigationBarGallery((NavigationPage)rootPage), "NavigationBar Gallery - Legacy")); - _pages.Insert(1, new GalleryPageFactory(() => new TitleView(), "TitleView")); + _pages.Insert(1, new GalleryPageFactory(() => new TitleView(true), "TitleView")); } var template = new DataTemplate(typeof(TextCell)); diff --git a/Xamarin.Forms.Controls/GalleryPages/TitleView.xaml b/Xamarin.Forms.Controls/GalleryPages/TitleView.xaml index 792bc5fe3..4226b8887 100644 --- a/Xamarin.Forms.Controls/GalleryPages/TitleView.xaml +++ b/Xamarin.Forms.Controls/GalleryPages/TitleView.xaml @@ -1,19 +1,29 @@ - + - + - - - + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/Xamarin.Forms.Controls/GalleryPages/TitleView.xaml.cs b/Xamarin.Forms.Controls/GalleryPages/TitleView.xaml.cs index 44369cf0d..13811fad6 100644 --- a/Xamarin.Forms.Controls/GalleryPages/TitleView.xaml.cs +++ b/Xamarin.Forms.Controls/GalleryPages/TitleView.xaml.cs @@ -5,6 +5,8 @@ using System.Text; using System.Threading.Tasks; using Xamarin.Forms; +using Xamarin.Forms.PlatformConfiguration; +using Xamarin.Forms.PlatformConfiguration.iOSSpecific; using Xamarin.Forms.Xaml; namespace Xamarin.Forms.Controls.GalleryPages @@ -12,9 +14,216 @@ namespace Xamarin.Forms.Controls.GalleryPages [XamlCompilation(XamlCompilationOptions.Compile)] public partial class TitleView : ContentPage { - public TitleView () + public TitleView(bool initialLoad) { - InitializeComponent (); + InitializeComponent(); + + if (initialLoad) + { + Device.BeginInvokeOnMainThread(() => masterDetailsPage_Clicked(this, EventArgs.Empty)); + } + } + + NavigationPage CreateNavigationPage() + { + return new NavigationPage(new TitleView(false) { Title = "Nav Title" }); + } + + public Page GetPage() + { + return new MasterDetailPage() + { + Detail = CreateNavigationPage(), + Master = new ContentPage() { Title = "Master" } + }; + } + + void masterDetailsPage_Clicked(object sender, EventArgs e) + { + App.Current.MainPage = + new MasterDetailPage() + { + Detail = CreateNavigationPage(), + Master = new ContentPage() { Title = "Master" }, + }; + + } + + void toggleBackButtonText_Clicked(object sender, EventArgs e) + { + var page = Navigation.NavigationStack.First(); + var titleText = NavigationPage.GetBackButtonTitle(page); + + if (titleText == null) + titleText = "Custom Text"; + else if (titleText == "Custom Text") + titleText = ""; + else + titleText = null; + + NavigationPage.SetBackButtonTitle(page, titleText); + changeTitleView_Clicked(this, EventArgs.Empty); + + string result = (titleText == null) ? "" : titleText; + btnToggleBackButtonTitle.Text = $"Toggle Back Button Title Text: {result}"; + } + + void tabbedPage_Clicked(object sender, EventArgs e) + { + + var page = new ContentPage() { Title = "other title page" }; + NavigationPage.SetTitleView(page, createGrid()); + + App.Current.MainPage = + new TabbedPage() + { + Children = + { + CreateNavigationPage(), + new ContentPage(){ Title = "no title Page"}, + new NavigationPage(page), + } + }; + } + + void navigationPage_Clicked(object sender, EventArgs e) + { + App.Current.MainPage = CreateNavigationPage(); + } + + void nextPage_Clicked(object sender, EventArgs e) + { + ContentPage page = null; + page = new ContentPage() + { + Title = "second page", + Content = new StackLayout() + { + Children = + { + new Button() + { + Text = "Toggle Back Button", + Command = new Command(()=> + { + NavigationPage.SetHasBackButton(page, !NavigationPage.GetHasBackButton(page)); + }) + }, + new Button() + { + Text = "Toggle Title View", + Command = new Command(()=> + { + changeTitleView_Clicked(page, EventArgs.Empty); + }) + } + } + } + }; + + NavigationPage.SetTitleView(page, createGrid()); + Navigation.PushAsync(page); + } + + View createSearchBarView() + { + return new SearchBar { BackgroundColor = Color.Cornsilk, HorizontalOptions = LayoutOptions.FillAndExpand, Margin = new Thickness(10, 0) }; + } + + View createGrid() + { + var grid = new Grid + { + BackgroundColor = Color.LightGray + }; + + grid.RowDefinitions.Add(new RowDefinition()); + grid.RowDefinitions.Add(new RowDefinition()); + grid.ColumnDefinitions.Add(new ColumnDefinition()); + grid.ColumnDefinitions.Add(new ColumnDefinition() { Width = GridLength.Star }); + + var label = new Label { Text = "hello", HorizontalOptions = LayoutOptions.Start, BackgroundColor = Color.Yellow }; + var label2 = new Label { Text = "hello 2", HorizontalOptions = LayoutOptions.Start, BackgroundColor = Color.Yellow }; + grid.Children.Add(label); + grid.Children.Add(label2); + Grid.SetRow(label2, 1); + + var label3 = new Label { Text = "right aligned", HorizontalTextAlignment = TextAlignment.End }; + Grid.SetColumn(label3, 1); + grid.Children.Add(label3); + return grid; + } + + + void titleIcon_Clicked(object sender, EventArgs e) + { + var titleIcon = NavigationPage.GetTitleIcon(this); + + if (titleIcon == null) + NavigationPage.SetTitleIcon(this, "coffee.png"); + else + NavigationPage.SetTitleIcon(this, null); + + } + + void masterDetailsPageIcon_Clicked(object sender, EventArgs e) + { + if (App.Current.MainPage is MasterDetailPage mdp) + { + if (String.IsNullOrWhiteSpace(mdp.Master.Icon)) + mdp.Master.Icon = "menuIcon"; + else + mdp.Master.Icon = null; + } + } + + void toggleLargeTitles_Clicked(object sender, EventArgs e) + { + var navPage = (NavigationPage)Navigation.NavigationStack.Last().Parent; + navPage.On().SetPrefersLargeTitles(!navPage.On().PrefersLargeTitles()); + } + + void backToGallery_Clicked(object sender, EventArgs e) + { + (App.Current as App).Reset(); + } + + void toggleToolBarItem_Clicked(object sender, EventArgs e) + { + var page = Navigation.NavigationStack.Last(); + var items = page.ToolbarItems.Where(x => x.Order == ToolbarItemOrder.Primary).ToList(); + + if (items.Any()) + foreach (var item in items) + page.ToolbarItems.Remove(item); + else + page.ToolbarItems.Add(new ToolbarItem() { Text = "Save", Order = ToolbarItemOrder.Primary }); + } + + void toggleSecondaryToolBarItem_Clicked(object sender, EventArgs e) + { + var page = Navigation.NavigationStack.Last(); + var items = page.ToolbarItems.Where(x => x.Order == ToolbarItemOrder.Secondary).ToList(); + + if (items.Any()) + foreach (var item in items) + page.ToolbarItems.Remove(item); + else + page.ToolbarItems.Add(new ToolbarItem() { Text = "Save", Order = ToolbarItemOrder.Secondary }); + } + + + void changeTitleView_Clicked(object sender, EventArgs e) + { + var currentView = NavigationPage.GetTitleView(Navigation.NavigationStack.Last()); + + if (currentView is Grid) + NavigationPage.SetTitleView(Navigation.NavigationStack.Last(), createSearchBarView()); + else if (currentView is SearchBar) + NavigationPage.SetTitleView(Navigation.NavigationStack.Last(), null); + else + NavigationPage.SetTitleView(Navigation.NavigationStack.Last(), createGrid()); + } } } \ No newline at end of file diff --git a/Xamarin.Forms.Platform.iOS/Renderers/NavigationRenderer.cs b/Xamarin.Forms.Platform.iOS/Renderers/NavigationRenderer.cs index 56219f27f..7aadee791 100644 --- a/Xamarin.Forms.Platform.iOS/Renderers/NavigationRenderer.cs +++ b/Xamarin.Forms.Platform.iOS/Renderers/NavigationRenderer.cs @@ -33,14 +33,14 @@ namespace Xamarin.Forms.Platform.iOS UIImage _defaultNavBarShadowImage; UIImage _defaultNavBarBackImage; - public NavigationRenderer() + public NavigationRenderer() : base(typeof(FormsNavigationBar), null) { MessagingCenter.Subscribe(this, UpdateToolbarButtons, sender => { if (!ViewControllers.Any()) return; var parentingViewController = (ParentingViewController)ViewControllers.Last(); - UpdateLeftBarButtonItem(parentingViewController); + parentingViewController?.UpdateLeftBarButtonItem(); }); } @@ -97,7 +97,7 @@ namespace Xamarin.Forms.Platform.iOS View.SetNeedsLayout(); var parentingViewController = (ParentingViewController)ViewControllers.Last(); - UpdateLeftBarButtonItem(parentingViewController); + parentingViewController?.UpdateLeftBarButtonItem(); } public Task PopToRootAsync(Page page, bool animated = true) @@ -180,7 +180,7 @@ namespace Xamarin.Forms.Platform.iOS double trueBottom = toolbar.Hidden ? toolbarY : toolbar.Frame.Bottom; var modelSize = _queuedSize.IsZero ? Element.Bounds.Size : _queuedSize; - PageController.ContainerArea = + PageController.ContainerArea = new Rectangle(0, toolbar.Hidden ? 0 : toolbar.Frame.Height, modelSize.Width, modelSize.Height - trueBottom); if (!_queuedSize.IsZero) @@ -356,7 +356,7 @@ namespace Xamarin.Forms.Platform.iOS // otherwise the view controller is forced to 0,0 var pack = new ParentingViewController(this) { Child = page }; - UpdateTitleArea(pack, page); + pack.UpdateTitleArea(page); var pageRenderer = Platform.GetRenderer(page); pack.View.AddSubview(pageRenderer.ViewController.View); @@ -450,7 +450,7 @@ namespace Xamarin.Forms.Platform.iOS else if (e.PropertyName == NavigationPage.BackButtonTitleProperty.PropertyName) { var pack = (ParentingViewController)TopViewController; - UpdateTitleArea(pack, pack.Child); + pack?.UpdateTitleArea(pack.Child); } else if (e.PropertyName == HideNavigationBarSeparatorProperty.PropertyName) { @@ -462,7 +462,7 @@ namespace Xamarin.Forms.Platform.iOS { //if the last time we did ViewDidLayoutSubviews we had other value for _hasNavigationBar //we will need to relayout. This is because Current is updated async of the layout happening - if(_hasNavigationBar != NavigationPage.GetHasNavigationBar(newCurrentPage)) + if (_hasNavigationBar != NavigationPage.GetHasNavigationBar(newCurrentPage)) ViewDidLayoutSubviews(); } @@ -480,7 +480,7 @@ namespace Xamarin.Forms.Platform.iOS NavigationBar.ShadowImage = _defaultNavBarShadowImage; if (!Forms.IsiOS11OrNewer) - { + { // For iOS 10 and lower, you need to set the background image. // If you set this for iOS11, you'll remove the background color. if (_defaultNavBarBackImage == null) @@ -507,118 +507,6 @@ namespace Xamarin.Forms.Platform.iOS NavigationBar.PrefersLargeTitles = NavPage.OnThisPlatform().PrefersLargeTitles(); } - void UpdateTitleArea(ParentingViewController pack, Page page) - { - if (pack == null || page == null) - return; - - if (!string.IsNullOrWhiteSpace(page.Title)) - pack.NavigationItem.Title = page.Title; - - // First page and we have a master detail to contend with - UpdateLeftBarButtonItem(pack); - - var titleText = NavigationPage.GetBackButtonTitle(page); - if (titleText != null) - { - // adding a custom event handler to UIBarButtonItem for navigating back seems to be ignored. - pack.NavigationItem.BackBarButtonItem = new UIBarButtonItem { Title = titleText, Style = UIBarButtonItemStyle.Plain }; - } - - FileImageSource titleIcon = NavigationPage.GetTitleIcon(page); - VisualElement titleView = NavigationPage.GetTitleView(page); - - ClearTitleViewContainer(pack); - - bool needContainer = titleView != null || titleIcon != null; - - if (needContainer) - { - Container titleViewContainer = new Container(); - - pack.NavigationItem.TitleView = titleViewContainer; - - UpdateTitleImage(titleViewContainer, titleIcon); - UpdateTitleView(titleViewContainer, titleView); - - // Need to call this for iOS10 to properly frame the renderer - TopViewController?.NavigationItem?.TitleView?.SizeToFit(); - TopViewController?.NavigationItem?.TitleView?.LayoutSubviews(); - } - } - - async void UpdateTitleImage(Container titleViewContainer, FileImageSource titleIcon) - { - if (titleViewContainer == null) - return; - - if (string.IsNullOrWhiteSpace(titleIcon)) - { - titleViewContainer.Icon = null; - } - else - { - var source = Internals.Registrar.Registered.GetHandlerForObject(titleIcon); - var image = await source.LoadImageAsync(titleIcon); - - try - { - titleViewContainer.Icon = new UIImageView(image) { }; - } - catch - { - //UIImage ctor throws on file not found if MonoTouch.ObjCRuntime.Class.ThrowOnInitFailure is true; - } - } - } - - void ClearTitleViewContainer(UIViewController pack) - { - if (pack == null) - return; - - if (pack.NavigationItem.TitleView != null && pack.NavigationItem.TitleView is Container titleViewContainer) - { - titleViewContainer.Dispose(); - titleViewContainer = null; - pack.NavigationItem.TitleView = null; - } - } - - void UpdateTitleView(Container titleViewContainer, VisualElement titleView) - { - if (titleViewContainer == null) - return; - - var titleViewRenderer = titleViewContainer.Child; - - if (titleView != null) - { - if (titleViewRenderer != null) - { - var rendererType = titleViewRenderer is System.Reflection.IReflectableType reflectableType - ? reflectableType.GetTypeInfo().AsType() - : titleViewRenderer.GetType(); - - if (titleView != null && rendererType == Internals.Registrar.Registered.GetHandlerTypeForObject(titleView)) - { - if (titleViewContainer != null) - titleViewContainer.Child = null; - titleViewRenderer.SetElement(titleView); - return; - } - titleViewContainer?.DisposeChild(); - } - - titleViewRenderer = Platform.CreateRenderer(titleView); - titleViewContainer.Child = titleViewRenderer; - } - else if (titleViewRenderer != null) - { - titleViewContainer?.DisposeChild(); - } - } - void UpdateTranslucent() { NavigationBar.Translucent = NavPage.OnThisPlatform().IsNavigationBarTranslucent(); @@ -695,7 +583,7 @@ namespace Xamarin.Forms.Platform.iOS ViewControllers = _removeControllers; } var parentingViewController = ViewControllers.Last() as ParentingViewController; - UpdateLeftBarButtonItem(parentingViewController, page); + parentingViewController?.UpdateLeftBarButtonItem(page); } void RemoveViewControllers(bool animated) @@ -794,17 +682,6 @@ namespace Xamarin.Forms.Platform.iOS } } - void UpdateLeftBarButtonItem(ParentingViewController containerController, Page pageBeingRemoved = null) - { - if (containerController == null) - return; - var currentChild = containerController.Child; - var firstPage = NavPage.Pages.FirstOrDefault(); - if ((firstPage != pageBeingRemoved && currentChild != firstPage && NavigationPage.GetHasBackButton(currentChild)) || _parentMasterDetailPage == null) - return; - - SetMasterLeftBarButton(containerController, _parentMasterDetailPage); - } void UpdateTint() { @@ -1103,10 +980,117 @@ namespace Xamarin.Forms.Platform.iOS UpdateLargeTitles(); else if (e.PropertyName == NavigationPage.TitleIconProperty.PropertyName || e.PropertyName == NavigationPage.TitleViewProperty.PropertyName) + UpdateTitleArea(Child); + } + + + internal void UpdateLeftBarButtonItem(Page pageBeingRemoved = null) + { + NavigationRenderer n; + if (!_navigation.TryGetTarget(out n)) + return; + + var currentChild = this.Child; + var firstPage = n.NavPage.Pages.FirstOrDefault(); + + + if (n._parentMasterDetailPage == null) + return; + + if (firstPage != pageBeingRemoved && currentChild != firstPage && NavigationPage.GetHasBackButton(currentChild)) + { + NavigationItem.LeftBarButtonItem = null; + return; + } + + SetMasterLeftBarButton(this, n._parentMasterDetailPage); + } + + + public bool NeedsTitleViewContainer(Page page) => NavigationPage.GetTitleIcon(page) != null || NavigationPage.GetTitleView(page) != null; + + internal void UpdateBackButtonTitle(Page page) => UpdateBackButtonTitle(page.Title, NavigationPage.GetBackButtonTitle(page)); + + internal void UpdateBackButtonTitle(string title, string backButtonTitle) + { + if (!string.IsNullOrWhiteSpace(title)) + NavigationItem.Title = title; + + if (backButtonTitle != null) + // adding a custom event handler to UIBarButtonItem for navigating back seems to be ignored. + NavigationItem.BackBarButtonItem = new UIBarButtonItem { Title = backButtonTitle, Style = UIBarButtonItemStyle.Plain }; + else + NavigationItem.BackBarButtonItem = null; + } + + internal void UpdateTitleArea(Page page) + { + if (page == null) + return; + + FileImageSource titleIcon = NavigationPage.GetTitleIcon(page); + View titleView = NavigationPage.GetTitleView(page); + bool needContainer = titleView != null || titleIcon != null; + + string backButtonText = NavigationPage.GetBackButtonTitle(page); + bool isBackButtonTextSet = page.IsSet(NavigationPage.BackButtonTitleProperty); + + // on iOS 10 if the user hasn't set the back button text + // we set it to an empty string so it's consistent with iOS 11 + if (!Forms.IsiOS11OrNewer && !isBackButtonTextSet) + backButtonText = ""; + + // First page and we have a master detail to contend with + UpdateLeftBarButtonItem(); + UpdateBackButtonTitle(page.Title, backButtonText); + + //var hadTitleView = NavigationItem.TitleView != null; + ClearTitleViewContainer(); + if (needContainer) { NavigationRenderer n; - if (_navigation.TryGetTarget(out n)) - n.UpdateTitleArea(this, Child); + if (!_navigation.TryGetTarget(out n)) + return; + + Container titleViewContainer = new Container(titleView, n.NavigationBar); + + UpdateTitleImage(titleViewContainer, titleIcon); + NavigationItem.TitleView = titleViewContainer; + } + } + + async void UpdateTitleImage(Container titleViewContainer, FileImageSource titleIcon) + { + if (titleViewContainer == null) + return; + + if (string.IsNullOrWhiteSpace(titleIcon)) + { + titleViewContainer.Icon = null; + } + else + { + var source = Internals.Registrar.Registered.GetHandlerForObject(titleIcon); + var image = await source.LoadImageAsync(titleIcon); + + try + { + titleViewContainer.Icon = new UIImageView(image) { }; + } + catch + { + //UIImage ctor throws on file not found if MonoTouch.ObjCRuntime.Class.ThrowOnInitFailure is true; + } + } + } + + void ClearTitleViewContainer() + { + if (NavigationItem.TitleView != null && NavigationItem.TitleView is Container titleViewContainer) + { + titleViewContainer.Dispose(); + titleViewContainer = null; + NavigationItem.TitleView = null; } } @@ -1123,10 +1107,17 @@ namespace Xamarin.Forms.Platform.iOS void UpdateHasBackButton() { - if (Child == null) + if (Child == null || NavigationItem.HidesBackButton == !NavigationPage.GetHasBackButton(Child)) return; NavigationItem.HidesBackButton = !NavigationPage.GetHasBackButton(Child); + + NavigationRenderer n; + if (!_navigation.TryGetTarget(out n)) + return; + + if (!Forms.IsiOS11OrNewer || n._parentMasterDetailPage != null) + UpdateTitleArea(Child); } void UpdateNavigationBarVisibility(bool animated) @@ -1257,25 +1248,136 @@ namespace Xamarin.Forms.Platform.iOS VisualElementRenderer.RegisterEffect(effect, View); } + internal class FormsNavigationBar : UINavigationBar + { + public FormsNavigationBar() : base() + { + } + + public FormsNavigationBar(Foundation.NSCoder coder) : base(coder) + { + } + + protected FormsNavigationBar(Foundation.NSObjectFlag t) : base(t) + { + } + + protected internal FormsNavigationBar(IntPtr handle) : base(handle) + { + } + + public FormsNavigationBar(RectangleF frame) : base(frame) + { + } + + public RectangleF BackButtonFrameSize { get; private set; } + public UILabel NavBarLabel { get; private set; } + + public override void LayoutSubviews() + { + if (!Forms.IsiOS11OrNewer) + { + for (int i = 0; i < this.Subviews.Length; i++) + { + if (Subviews[i] is UIView view) + { + if (view.Class.Name == "_UINavigationBarBackIndicatorView") + { + if (view.Alpha == 0) + BackButtonFrameSize = CGRect.Empty; + else + BackButtonFrameSize = view.Frame; + + break; + } + else if(view.Class.Name == "UINavigationItemButtonView") + { + if (view.Subviews.Length == 0) + NavBarLabel = null; + else if (view.Subviews[0] is UILabel titleLabel) + NavBarLabel = titleLabel; + } + } + } + } + + base.LayoutSubviews(); + } + } + class Container : UIView { + View _view; + FormsNavigationBar _bar; IVisualElementRenderer _child; UIImageView _icon; - nfloat IconHeight => _icon?.Frame.Height ?? 0; + public Container(View view, UINavigationBar bar) : base(bar.Bounds) + { + if (Forms.IsiOS11OrNewer) + { + TranslatesAutoresizingMaskIntoConstraints = false; + } + else + { + TranslatesAutoresizingMaskIntoConstraints = true; + AutoresizingMask = UIViewAutoresizing.FlexibleHeight | UIViewAutoresizing.FlexibleWidth; + } + _bar = bar as FormsNavigationBar; + if (view != null) + { + _view = view; + _child = Platform.CreateRenderer(view); + Platform.SetRenderer(view, _child); + AddSubview(_child.NativeView); + } + + ClipsToBounds = true; + } + + public override CGSize IntrinsicContentSize => UILayoutFittingExpandedSize; + + nfloat IconHeight => _icon?.Frame.Height ?? 0; nfloat IconWidth => _icon?.Frame.Width ?? 0; - protected override void Dispose(bool disposing) + // Navigation bar will not stretch past these values. Prevent content clipping. + // iOS11 does this for us automatically, but apparently iOS10 doesn't. + nfloat ToolbarHeight { - if (disposing) + get { - DisposeChild(); + if (Superview?.Bounds.Height > 0) + return Superview.Bounds.Height; - _icon?.Dispose(); - _icon = null; + return (Device.Idiom == TargetIdiom.Phone && Device.Info.CurrentOrientation.IsLandscape()) ? 32 : 44; + } + } + + public override CGRect Frame + { + get => base.Frame; + set + { + if (Superview != null) + { + if (!Forms.IsiOS11OrNewer) + { + value.Y = Superview.Bounds.Y; + + if (_bar != null && String.IsNullOrWhiteSpace(_bar.NavBarLabel?.Text) && _bar.BackButtonFrameSize != RectangleF.Empty) + { + var xSpace = _bar.BackButtonFrameSize.Width + (_bar.BackButtonFrameSize.X * 2); + value.Width = (value.X - xSpace) + value.Width; + value.X = xSpace; + } + }; + + value.Height = ToolbarHeight; + } + + base.Frame = value; } - base.Dispose(disposing); } public UIImageView Icon @@ -1292,65 +1394,53 @@ namespace Xamarin.Forms.Platform.iOS } } - public IVisualElementRenderer Child - { - get { return _child; } - set - { - if (_child != null) - DisposeChild(); - - _child = value; - - if (value != null) - AddSubview(value.NativeView); - } - } - public override SizeF SizeThatFits(SizeF size) { - IVisualElementRenderer renderer = _child; - - if (renderer == null || renderer.Element == null || renderer.Element.Parent == null) - return new SizeF(IconWidth, IconHeight); - - var result = renderer.Element.Measure(double.PositiveInfinity, double.PositiveInfinity, MeasureFlags.IncludeMargins); - - return new SizeF(result.Request.Width + IconWidth, Math.Max(IconHeight, result.Request.Height)); + return new SizeF(size.Width, ToolbarHeight); } public override void LayoutSubviews() { base.LayoutSubviews(); + if (Frame == CGRect.Empty || Frame.Width >= 10000 || Frame.Height >= 10000) + return; - // Navigation bar will not stretch past these values. Prevent content clipping. - // iOS11 does this for us automatically, but apparently iOS10 doesn't. - int toolbarHeight = 44; - if (Device.Idiom == TargetIdiom.Phone && Device.Info.CurrentOrientation.IsLandscape()) - toolbarHeight = 32; + nfloat toolbarHeight = ToolbarHeight; double height = Math.Min(toolbarHeight, Bounds.Height); - Frame = new RectangleF(Frame.X, Frame.Y, Bounds.Width, height); - if (_icon != null) _icon.Frame = new RectangleF(0, 0, IconWidth, Math.Min(toolbarHeight, IconHeight)); if (_child?.Element != null) - Layout.LayoutChildIntoBoundingRegion(_child.Element, new Rectangle(IconWidth, 0, Bounds.Width - IconWidth, height)); + { + var layoutBounds = new Rectangle(IconWidth, 0, Bounds.Width - IconWidth, height); + if (_child.Element.Bounds != layoutBounds) + Layout.LayoutChildIntoBoundingRegion(_child.Element, layoutBounds); + } } - public void DisposeChild() + protected override void Dispose(bool disposing) { - if (_child == null) - return; + if (disposing) + { - if (_child.Element.Platform is Platform platform) - platform.DisposeModelAndChildrenRenderers(_child.Element); + if (_child != null) + { + if (_child.Element.Platform is Platform platform) + platform.DisposeModelAndChildrenRenderers(_child.Element); - _child.NativeView.RemoveFromSuperview(); - _child.Dispose(); - _child = null; + _child.NativeView.RemoveFromSuperview(); + _child.Dispose(); + _child = null; + } + + _view = null; + + _icon?.Dispose(); + _icon = null; + } + base.Dispose(disposing); } } }