зеркало из https://github.com/DeGsoft/maui-linux.git
[iOS] fix full width issues for TitleView (#3939)
* [iOS] fix full width issues for TitleView * [iOS] simplified iOS 10 fixes #3881 fixes #3679
This commit is contained in:
Родитель
16a4e91aac
Коммит
379adeb380
|
@ -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));
|
||||
|
|
|
@ -1,19 +1,29 @@
|
|||
<?xml version="1.0" encoding="utf-8" ?>
|
||||
<?xml version="1.0" encoding="utf-8" ?>
|
||||
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
|
||||
x:Class="Xamarin.Forms.Controls.GalleryPages.TitleView">
|
||||
|
||||
<NavigationPage.TitleView>
|
||||
<StackLayout>
|
||||
<StackLayout BackgroundColor="Pink">
|
||||
<Label Text="This is my TitleView" />
|
||||
<Label Text="I can be a subtitle" />
|
||||
</StackLayout>
|
||||
</NavigationPage.TitleView>
|
||||
|
||||
<StackLayout>
|
||||
<Label Text="Welcome to Xamarin.Forms!"
|
||||
VerticalOptions="CenterAndExpand"
|
||||
HorizontalOptions="CenterAndExpand" />
|
||||
<ScrollView>
|
||||
<StackLayout BackgroundColor="Pink">
|
||||
<Button Clicked="masterDetailsPage_Clicked" Text="Master Details Page"></Button>
|
||||
<Button Clicked="masterDetailsPageIcon_Clicked" Text="Toggle MDP Icon"></Button>
|
||||
<Button Clicked="tabbedPage_Clicked" Text="Tabbed Page"></Button>
|
||||
<Button Clicked="navigationPage_Clicked" Text="Navigation Page"></Button>
|
||||
<Button Clicked="nextPage_Clicked" Text="Push a Page"></Button>
|
||||
<Button Clicked="titleIcon_Clicked" Text="Toggle Title Icon"></Button>
|
||||
<Button Clicked="toggleToolBarItem_Clicked" Text="Toggle Tool Bar Item" ></Button>
|
||||
<Button Clicked="toggleSecondaryToolBarItem_Clicked" Text="Toggle Secondary Tool Bar Item" ></Button>
|
||||
<Button Clicked="toggleLargeTitles_Clicked" Text="Toggle Large Titles" ></Button>
|
||||
<Button Clicked="changeTitleView_Clicked" Text="Toggle Different Title Views"></Button>
|
||||
<Button x:Name="btnToggleBackButtonTitle" Clicked="toggleBackButtonText_Clicked" Text="Toggle Back Button Title Text"></Button>
|
||||
<Button Clicked="backToGallery_Clicked" Text="Back to Gallery"></Button>
|
||||
</StackLayout>
|
||||
|
||||
</ScrollView>
|
||||
</ContentPage>
|
|
@ -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) ? "<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<iOS>().SetPrefersLargeTitles(!navPage.On<iOS>().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());
|
||||
|
||||
}
|
||||
}
|
||||
}
|
|
@ -33,14 +33,14 @@ namespace Xamarin.Forms.Platform.iOS
|
|||
UIImage _defaultNavBarShadowImage;
|
||||
UIImage _defaultNavBarBackImage;
|
||||
|
||||
public NavigationRenderer()
|
||||
public NavigationRenderer() : base(typeof(FormsNavigationBar), null)
|
||||
{
|
||||
MessagingCenter.Subscribe<IVisualElementRenderer>(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<bool> PopToRootAsync(Page page, bool animated = true)
|
||||
|
@ -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();
|
||||
}
|
||||
|
||||
|
@ -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<IImageSourceHandler>(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))
|
||||
n.UpdateTitleArea(this, Child);
|
||||
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))
|
||||
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<IImageSourceHandler>(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<VisualElement>.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,59 +1394,39 @@ 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 (disposing)
|
||||
{
|
||||
if (_child == null)
|
||||
return;
|
||||
|
||||
if (_child != null)
|
||||
{
|
||||
if (_child.Element.Platform is Platform platform)
|
||||
platform.DisposeModelAndChildrenRenderers(_child.Element);
|
||||
|
||||
|
@ -1352,6 +1434,14 @@ namespace Xamarin.Forms.Platform.iOS
|
|||
_child.Dispose();
|
||||
_child = null;
|
||||
}
|
||||
|
||||
_view = null;
|
||||
|
||||
_icon?.Dispose();
|
||||
_icon = null;
|
||||
}
|
||||
base.Dispose(disposing);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Загрузка…
Ссылка в новой задаче