summaryrefslogtreecommitdiff
path: root/Xamarin.Forms.Platform.MacOS/Renderers/TabbedPageRenderer.cs
diff options
context:
space:
mode:
Diffstat (limited to 'Xamarin.Forms.Platform.MacOS/Renderers/TabbedPageRenderer.cs')
-rw-r--r--Xamarin.Forms.Platform.MacOS/Renderers/TabbedPageRenderer.cs403
1 files changed, 403 insertions, 0 deletions
diff --git a/Xamarin.Forms.Platform.MacOS/Renderers/TabbedPageRenderer.cs b/Xamarin.Forms.Platform.MacOS/Renderers/TabbedPageRenderer.cs
new file mode 100644
index 00000000..3aee095d
--- /dev/null
+++ b/Xamarin.Forms.Platform.MacOS/Renderers/TabbedPageRenderer.cs
@@ -0,0 +1,403 @@
+using System;
+using System.Collections.Specialized;
+using System.ComponentModel;
+using AppKit;
+using CoreGraphics;
+using Xamarin.Forms.Internals;
+using Xamarin.Forms.PlatformConfiguration.macOSSpecific;
+
+namespace Xamarin.Forms.Platform.MacOS
+{
+ public class TabbedPageRenderer : NSTabViewController, IVisualElementRenderer, IEffectControlProvider
+ {
+ const float DefaultImageSizeSegmentedButton = 19;
+ const int TabHolderHeight = 30;
+
+ bool _disposed;
+ bool _updatingControllers;
+ bool _barBackgroundColorWasSet;
+ bool _barTextColorWasSet;
+ bool _defaultBarTextColorSet;
+ bool _defaultBarColorSet;
+ VisualElementTracker _tracker;
+ bool _loaded;
+ Size _queuedSize;
+
+
+ public VisualElement Element { get; private set; }
+
+ public event EventHandler<VisualElementChangedEventArgs> ElementChanged;
+
+ public SizeRequest GetDesiredSize(double widthConstraint, double heightConstraint)
+ {
+ return NativeView.GetSizeRequest(widthConstraint, heightConstraint);
+ }
+
+ public NSView NativeView => View;
+
+ public void SetElement(VisualElement element)
+ {
+ var oldElement = Element;
+ Element = element;
+
+ if (oldElement != null)
+ {
+ oldElement.PropertyChanged -= OnPropertyChanged;
+ var tabbedPage = oldElement as TabbedPage;
+ if (tabbedPage != null) tabbedPage.PagesChanged -= OnPagesChanged;
+ }
+
+ if (element != null)
+ {
+ if (_tracker == null)
+ {
+ _tracker = new VisualElementTracker(this);
+ _tracker.NativeControlUpdated += (sender, e) => UpdateNativeWidget();
+ }
+ }
+
+ OnElementChanged(new VisualElementChangedEventArgs(oldElement, element));
+
+ ConfigureTabView();
+
+ OnPagesChanged(null, new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Reset));
+
+ Tabbed.PropertyChanged += OnPropertyChanged;
+ Tabbed.PagesChanged += OnPagesChanged;
+
+ UpdateBarBackgroundColor();
+
+ UpdateBarTextColor();
+
+ EffectUtilities.RegisterEffectControlProvider(this, oldElement, element);
+ }
+
+ IPageController PageController => Element as IPageController;
+
+ IElementController ElementController => Element;
+
+ void IEffectControlProvider.RegisterEffect(Effect effect)
+ {
+ var platformEffect = effect as PlatformEffect;
+ if (platformEffect != null)
+ platformEffect.Container = View;
+ }
+
+ public void SetElementSize(Size size)
+ {
+ if (_loaded)
+ Element.Layout(new Rectangle(Element.X, Element.Y, size.Width, size.Height));
+ else
+ _queuedSize = size;
+ }
+
+ public NSViewController ViewController => this;
+
+ public override void ViewWillLayout()
+ {
+ base.ViewWillLayout();
+
+ if (Element == null)
+ return;
+
+ if (!Element.Bounds.IsEmpty)
+ View.Frame = new System.Drawing.RectangleF((float)Element.X, (float)Element.Y, (float)Element.Width, (float)Element.Height);
+
+ var frame = View.Frame;
+ PageController.ContainerArea = new Rectangle(0, 0, frame.Width, frame.Height - TabHolderHeight);
+
+ if (!_queuedSize.IsZero)
+ {
+ Element.Layout(new Rectangle(Element.X, Element.Y, _queuedSize.Width, _queuedSize.Height));
+ _queuedSize = Size.Zero;
+ }
+
+ _loaded = true;
+ }
+
+
+ public override nint SelectedTabViewItemIndex
+ {
+ get { return base.SelectedTabViewItemIndex; }
+ set
+ {
+ base.SelectedTabViewItemIndex = value;
+ if (!_updatingControllers)
+ UpdateCurrentPage();
+ }
+ }
+
+ public override void ViewDidAppear()
+ {
+ PageController.SendAppearing();
+ base.ViewDidAppear();
+ }
+
+ public override void ViewDidDisappear()
+ {
+ base.ViewDidDisappear();
+ PageController.SendDisappearing();
+ }
+
+ protected override void Dispose(bool disposing)
+ {
+ if (disposing && !_disposed)
+ {
+ _disposed = true;
+ PageController.SendDisappearing();
+ Tabbed.PropertyChanged -= OnPropertyChanged;
+ Tabbed.PagesChanged -= OnPagesChanged;
+
+ if (_tracker != null)
+ {
+ _tracker.Dispose();
+ _tracker = null;
+ }
+ }
+
+ base.Dispose(disposing);
+ }
+
+ protected virtual void ConfigureTabView()
+ {
+ View.WantsLayer = true;
+ TabView.WantsLayer = true;
+ TabView.DrawsBackground = false;
+ var tabStyle = Tabbed.OnThisPlatform().GetTabsStyle();
+ switch (tabStyle)
+ {
+ case TabsStyle.OnNavigation:
+ case TabsStyle.Hidden:
+ TabStyle = NSTabViewControllerTabStyle.Unspecified;
+ break;
+ case TabsStyle.Icons:
+ TabStyle = NSTabViewControllerTabStyle.Toolbar;
+ break;
+ case TabsStyle.OnBottom:
+ TabStyle = NSTabViewControllerTabStyle.SegmentedControlOnBottom;
+ break;
+ default:
+ TabStyle = NSTabViewControllerTabStyle.SegmentedControlOnTop;
+ break;
+ }
+
+ TabView.TabViewType = NSTabViewType.NSNoTabsNoBorder;
+ }
+
+ protected virtual void OnElementChanged(VisualElementChangedEventArgs e)
+ {
+ ElementChanged?.Invoke(this, e);
+ }
+
+ protected virtual NSTabViewItem GetTabViewItem(Page page, IVisualElementRenderer pageRenderer)
+ {
+ var tvi = new NSTabViewItem { ViewController = pageRenderer.ViewController, Label = page.Title ?? "" };
+ if (!string.IsNullOrEmpty (page.Icon)) {
+ var image = GetTabViewItemIcon (page.Icon);
+ if (image != null)
+ tvi.Image = image;
+ }
+ return tvi;
+ }
+
+ protected virtual NSImage GetTabViewItemIcon(string imageName)
+ {
+ var image = NSImage.ImageNamed (imageName);
+ if(image == null)
+ image = new NSImage (imageName);
+
+ if (image == null)
+ return null;
+
+ bool shouldResize = TabStyle == NSTabViewControllerTabStyle.SegmentedControlOnTop ||
+ TabStyle == NSTabViewControllerTabStyle.SegmentedControlOnBottom;
+ if (shouldResize)
+ image = image.ResizeTo(new CGSize(DefaultImageSizeSegmentedButton, DefaultImageSizeSegmentedButton));
+ return image;
+ }
+
+ protected virtual void UpdateNativeWidget()
+ {
+ TabView.Layout();
+ }
+
+ protected TabbedPage Tabbed => (TabbedPage)Element;
+
+ void OnPagePropertyChanged(object sender, PropertyChangedEventArgs e)
+ {
+ if (e.PropertyName == Page.TitleProperty.PropertyName)
+ {
+ var page = (Page)sender;
+ var index = TabbedPage.GetIndex(page);
+ TabViewItems[index].Label = page.Title;
+ }
+ else if (e.PropertyName == Page.IconProperty.PropertyName)
+ {
+ var page = (Page)sender;
+
+ var index = TabbedPage.GetIndex(page);
+ TabViewItems[index].Label = page.Title;
+
+ if (!string.IsNullOrEmpty(page.Icon))
+ {
+ TabViewItems[index].Image = new NSImage(page.Icon);
+ }
+ else if (TabViewItems[index].Image != null)
+ {
+ TabViewItems[index].Image = new NSImage();
+ }
+ }
+ }
+
+ void OnPagesChanged(object sender, NotifyCollectionChangedEventArgs e)
+ {
+ e.Apply((o, i, c) => SetupPage((Page)o, i), (o, i) => TeardownPage((Page)o), Reset);
+
+ SetControllers();
+
+ UpdateChildrenOrderIndex();
+
+ SetSelectedTabViewItem();
+ }
+
+ void OnPropertyChanged(object sender, PropertyChangedEventArgs e)
+ {
+ if (e.PropertyName == nameof(TabbedPage.CurrentPage))
+ {
+ var current = Tabbed.CurrentPage;
+ if (current == null)
+ return;
+
+ SetSelectedTabViewItem();
+ }
+ else if (e.PropertyName == TabbedPage.BarBackgroundColorProperty.PropertyName)
+ UpdateBarBackgroundColor();
+ else if (e.PropertyName == TabbedPage.BarTextColorProperty.PropertyName)
+ UpdateBarTextColor();
+ }
+
+ void Reset()
+ {
+ var i = 0;
+ foreach (var page in Tabbed.Children)
+ SetupPage(page, i++);
+ }
+
+ void SetControllers()
+ {
+ _updatingControllers = true;
+ for (var i = 0; i < ElementController.LogicalChildren.Count; i++)
+ {
+ var child = ElementController.LogicalChildren[i];
+ var page = child as Page;
+ if (page == null)
+ continue;
+
+ var pageRenderer = Platform.GetRenderer(page);
+ if (pageRenderer != null)
+ {
+ pageRenderer.ViewController.Identifier = i.ToString();
+
+ NSTabViewItem newTvi = GetTabViewItem(page, pageRenderer);
+
+ AddTabViewItem(newTvi);
+ }
+ }
+ _updatingControllers = false;
+ }
+
+ void SetupPage(Page page, int index)
+ {
+ var renderer = Platform.GetRenderer(page);
+ if (renderer == null)
+ {
+ renderer = Platform.CreateRenderer(page);
+ Platform.SetRenderer(page, renderer);
+ }
+
+ renderer.ViewController.Identifier = index.ToString();
+
+ page.PropertyChanged += OnPagePropertyChanged;
+ }
+
+ void TeardownPage(Page page)
+ {
+ page.PropertyChanged -= OnPagePropertyChanged;
+
+ Platform.SetRenderer(page, null);
+ }
+
+ void SetSelectedTabViewItem()
+ {
+ if (Tabbed.CurrentPage == null)
+ return;
+ var selectedIndex = TabbedPage.GetIndex(Tabbed.CurrentPage);
+ SelectedTabViewItemIndex = selectedIndex;
+ }
+
+ void UpdateChildrenOrderIndex()
+ {
+ for (var i = 0; i < TabViewItems.Length; i++)
+ {
+ int originalIndex;
+ if (int.TryParse(TabViewItems[i].ViewController.Identifier, out originalIndex))
+ {
+ var page = PageController.InternalChildren[originalIndex];
+ TabbedPage.SetIndex(page as Page, i);
+ }
+ }
+ }
+
+ void UpdateCurrentPage()
+ {
+ var count = PageController.InternalChildren.Count;
+ Tabbed.CurrentPage = SelectedTabViewItemIndex >= 0 && SelectedTabViewItemIndex < count
+ ? Tabbed.GetPageByIndex((int)SelectedTabViewItemIndex)
+ : null;
+ }
+
+ //TODO: Implement UpdateBarBackgroundColor
+ void UpdateBarBackgroundColor()
+ {
+ if (Tabbed == null || TabView == null)
+ return;
+
+ var barBackgroundColor = Tabbed.BarBackgroundColor;
+ var isDefaultColor = barBackgroundColor.IsDefault;
+
+ if (isDefaultColor && !_barBackgroundColorWasSet)
+ return;
+
+ if (!_defaultBarColorSet)
+ {
+ //_defaultBarColor = TabView.color;
+ _defaultBarColorSet = true;
+ }
+
+ if (!isDefaultColor)
+ _barBackgroundColorWasSet = true;
+ }
+
+ //TODO: Implement UpdateBarTextColor
+ void UpdateBarTextColor()
+ {
+ if (Tabbed == null || TabView == null)
+ return;
+
+ var barTextColor = Tabbed.BarTextColor;
+ var isDefaultColor = barTextColor.IsDefault;
+
+ if (isDefaultColor && !_barTextColorWasSet)
+ return;
+
+ if (!_defaultBarTextColorSet)
+ {
+ // _defaultBarTextColor = TabBar.TintColor;
+ _defaultBarTextColorSet = true;
+ }
+
+ if (!isDefaultColor)
+ _barTextColorWasSet = true;
+ }
+ }
+} \ No newline at end of file