using System.Collections.Generic; using System.ComponentModel; using System.Linq; using ElmSharp; using EToolbarItem = ElmSharp.ToolbarItem; using EToolbarItemEventArgs = ElmSharp.ToolbarItemEventArgs; using EColor = ElmSharp.Color; using Xamarin.Forms.PlatformConfiguration.TizenSpecific; using Xamarin.Forms.Internals; namespace Xamarin.Forms.Platform.Tizen { public class TabbedPageRenderer : VisualElementRenderer, IVisualElementRenderer { Box _outterLayout; Box _innerBox; Scroller _scroller; Toolbar _toolbar; Dictionary _itemToItemPage = new Dictionary(); public TabbedPageRenderer() { RegisterPropertyHandler(TabbedPage.TitleProperty, UpdateTitle); RegisterPropertyHandler("CurrentPage", CurrentPageChanged); RegisterPropertyHandler(TabbedPage.BarBackgroundColorProperty, UpdateBarBackgroundColor); } protected override void OnElementChanged(ElementChangedEventArgs e) { if (_toolbar == null) { //Create box that holds toolbar and selected content _outterLayout = new Box(Forms.Context.MainWindow) { AlignmentX = -1, AlignmentY = -1, WeightX = 1, WeightY = 1, IsHorizontal = false, }; _outterLayout.Show(); //Create toolbar that is placed inside the _outterLayout _toolbar = new Toolbar(Forms.Context.MainWindow) { AlignmentX = -1, WeightX = 1, SelectionMode = ToolbarSelectionMode.Always, }; if (Device.Idiom == TargetIdiom.Phone) { //Set ShrinkMode to Expand as defauly only for Mobile profile _toolbar.ShrinkMode = ToolbarShrinkMode.Expand; } else if (Device.Idiom == TargetIdiom.TV) { //According to TV UX Guideline, toolbar style should be set to "tabbar_with_title" in case of TabbedPage only for TV profile. _toolbar.Style = "tabbar_with_title"; } _toolbar.Show(); //Add callback for Toolbar item selection _toolbar.Selected += OnToolbarItemSelected; _outterLayout.PackEnd(_toolbar); _scroller = new Scroller(_outterLayout) { AlignmentX = -1, AlignmentY = -1, WeightX = 1, WeightY = 1, HorizontalPageScrollLimit = 1, ScrollBlock = ScrollBlock.Vertical, HorizontalScrollBarVisiblePolicy = ScrollBarVisiblePolicy.Invisible }; _scroller.SetPageSize(1.0, 1.0); _scroller.PageScrolled += OnItemPageScrolled; _innerBox = new Box(Forms.Context.MainWindow) { AlignmentX = -1, AlignmentY = -1, WeightX = 1, WeightY = 1, IsHorizontal = true, }; _innerBox.SetLayoutCallback(OnInnerLayoutUpdate); _scroller.SetContent(_innerBox); _scroller.Show(); _outterLayout.PackEnd(_scroller); SetNativeControl(_outterLayout); UpdateTitle(); } base.OnElementChanged(e); } protected override void Dispose(bool disposing) { if (disposing) { if (_outterLayout != null) { _outterLayout.Unrealize(); _outterLayout = null; } if (_toolbar != null) { _toolbar.Selected -= OnToolbarItemSelected; _scroller.PageScrolled -= OnItemPageScrolled; _toolbar.Unrealize(); _toolbar = null; } } base.Dispose(disposing); } protected override void OnElementReady() { FillToolbarAndContents(); base.OnElementReady(); } protected override void UpdateThemeStyle() { var style = Element.OnThisPlatform().GetStyle(); if (!string.IsNullOrEmpty(style)) { _toolbar.Style = style; ((IVisualElementController)Element).NativeSizeChanged(); } } void OnInnerLayoutUpdate() { int baseX = _innerBox.Geometry.X; Rect bound = _scroller.Geometry; int index = 0; foreach (var page in Element.Children) { var nativeView = Platform.GetRenderer(page).NativeView; bound.X = baseX + index * bound.Width; nativeView.Geometry = bound; index++; } _innerBox.MinimumWidth = Element.Children.Count * bound.Width; int currentPage = MultiPage.GetIndex(_itemToItemPage[_toolbar.SelectedItem]); _scroller.ScrollTo(currentPage, 0, true); } void OnItemPageScrolled(object sender, System.EventArgs e) { Page newPage = Element.GetPageByIndex(_scroller.HorizontalPageIndex); foreach (var pair in _itemToItemPage) { if (pair.Value == newPage) { pair.Key.IsSelected = true; return; } } } void UpdateBarBackgroundColor() { EColor bgColor = Element.BarBackgroundColor.ToNative(); _toolbar.BackgroundColor = bgColor; foreach (EToolbarItem item in _itemToItemPage.Keys) { if (Element.BarBackgroundColor == Color.Default) { item.DeletePartColor("bg"); } else { item.SetPartColor("bg", bgColor); } } } void UpdateTitle() { _toolbar.Text = Element.Title; } void UpdateTitle(Page page) { if (_itemToItemPage.ContainsValue(page)) { var pair = _itemToItemPage.FirstOrDefault(x => x.Value == page); pair.Key.SetPartText(null, pair.Value.Title); } } void OnPageTitleChanged(object sender, PropertyChangedEventArgs e) { if (e.PropertyName == Page.TitleProperty.PropertyName) { UpdateTitle(sender as Page); } } void FillToolbarAndContents() { //add items to toolbar foreach (Page child in Element.Children) { EToolbarItem toolbarItem = _toolbar.Append(child.Title, string.IsNullOrEmpty(child.Icon) ? null : ResourcePath.GetPath(child.Icon)); if (Element.BarBackgroundColor != Color.Default) { toolbarItem.SetPartColor("bg", _toolbar.BackgroundColor); } _itemToItemPage.Add(toolbarItem, child); var childContent = Platform.GetOrCreateRenderer(child).NativeView; _innerBox.PackEnd(childContent); if (Element.CurrentPage == child) { //select item on the toolbar and fill content toolbarItem.IsSelected = true; } child.PropertyChanged += OnPageTitleChanged; } } void OnToolbarItemSelected(object sender, EToolbarItemEventArgs e) { if (_toolbar.SelectedItem == null) return; var oldPage = Element.CurrentPage; var newPage = _itemToItemPage[_toolbar.SelectedItem]; if (oldPage == newPage) return; oldPage?.SendDisappearing(); Element.CurrentPage = newPage; newPage?.SendAppearing(); int index = MultiPage.GetIndex(newPage); _scroller.ScrollTo(index, 0, true); } void CurrentPageChanged() { foreach (var pair in _itemToItemPage) { if (pair.Value == Element.CurrentPage) { pair.Key.IsSelected = true; return; } } } } }