From 8dc22a0fb6aebfa6e39c49fc01c9163a92c01f09 Mon Sep 17 00:00:00 2001 From: Kangho Hur Date: Mon, 28 Sep 2020 06:41:04 +0900 Subject: [PATCH] [Tizen] Replace MDP to FlyoutPage --- Stubs/Xamarin.Forms.Platform.cs | 6 +- .../{MasterDetailPage.cs => FlyoutPage.cs} | 154 +++++++++--------- .../Properties/AssemblyInfo.cs | 1 + .../Renderers/FlyoutContainer.cs | 135 +++++++++++++++ .../Renderers/FlyoutPageRenderer.cs | 154 ++++++++++++++++++ .../Renderers/MasterDetailContainer.cs | 1 + .../Renderers/MasterDetailPageRenderer.cs | 9 +- .../StaticRegistrar.cs | 1 + 8 files changed, 374 insertions(+), 87 deletions(-) rename Xamarin.Forms.Platform.Tizen/Native/{MasterDetailPage.cs => FlyoutPage.cs} (65%) create mode 100644 Xamarin.Forms.Platform.Tizen/Renderers/FlyoutContainer.cs create mode 100644 Xamarin.Forms.Platform.Tizen/Renderers/FlyoutPageRenderer.cs diff --git a/Stubs/Xamarin.Forms.Platform.cs b/Stubs/Xamarin.Forms.Platform.cs index faddca60599..17fa0e51cea 100644 --- a/Stubs/Xamarin.Forms.Platform.cs +++ b/Stubs/Xamarin.Forms.Platform.cs @@ -163,12 +163,8 @@ internal class _PageRenderer { } -#if !__IOS__ && !TIZEN4_0 +#if !__IOS__ [RenderWith(typeof(FlyoutPageRenderer))] -#elif TIZEN4_0 -#pragma warning disable CS0618 // Type or member is obsolete - [RenderWith (typeof(MasterDetailPageRenderer))] -#pragma warning restore CS0618 // Type or member is obsolete #else [RenderWith (typeof (PhoneFlyoutPageRenderer))] #endif diff --git a/Xamarin.Forms.Platform.Tizen/Native/MasterDetailPage.cs b/Xamarin.Forms.Platform.Tizen/Native/FlyoutPage.cs similarity index 65% rename from Xamarin.Forms.Platform.Tizen/Native/MasterDetailPage.cs rename to Xamarin.Forms.Platform.Tizen/Native/FlyoutPage.cs index 5475335877f..606a0ce47c0 100644 --- a/Xamarin.Forms.Platform.Tizen/Native/MasterDetailPage.cs +++ b/Xamarin.Forms.Platform.Tizen/Native/FlyoutPage.cs @@ -5,49 +5,49 @@ namespace Xamarin.Forms.Platform.Tizen.Native { /// - /// The native widget which provides Xamarin.MasterDetailPage features. + /// The native widget which provides Xamarin.FlyoutPage features. /// - public class MasterDetailPage : Box + public class FlyoutPage : Box { /// - /// The default master behavior (a.k.a mode). + /// The default flyout layout behavior (a.k.a mode). /// - static readonly MasterBehavior s_defaultMasterBehavior = (Device.Idiom == TargetIdiom.Phone || Device.Idiom == TargetIdiom.Watch) ? MasterBehavior.Popover : MasterBehavior.SplitOnLandscape; + static readonly FlyoutLayoutBehavior s_defaultFlyoutLayoutBehavior = (Device.Idiom == TargetIdiom.Phone || Device.Idiom == TargetIdiom.Watch) ? FlyoutLayoutBehavior.Popover : FlyoutLayoutBehavior.SplitOnLandscape; /// - /// The MasterPage native container. + /// The Flyout native container. /// - readonly Canvas _masterCanvas; + readonly Canvas _flyoutCanvas; /// - /// The DetailPage native container. + /// The Detail native container. /// readonly Canvas _detailCanvas; /// - /// The container for _masterCanvas and _detailCanvas used in split mode. + /// The container for _flyoutCanvas and _detailCanvas used in split mode. /// readonly Panes _splitPane; /// - /// The container for _masterCanvas used in popover mode. + /// The container for _flyoutCanvas used in popover mode. /// readonly Panel _drawer; /// - /// The property value. + /// The property value. /// - MasterBehavior _masterBehavior = s_defaultMasterBehavior; + FlyoutLayoutBehavior _flyoutLayoutBehavior = s_defaultFlyoutLayoutBehavior; /// - /// The actual MasterDetailPage mode - either split or popover. It depends on _masterBehavior and screen orientation. + /// The actual FlyoutPage mode - either split or popover. It depends on _flyoutLayoutBehavior and screen orientation. /// - MasterBehavior _internalMasterBehavior = MasterBehavior.Popover; + FlyoutLayoutBehavior _internalFlyoutLayoutBehavior = FlyoutLayoutBehavior.Popover; /// - /// The property value. + /// The property value. /// - EvasObject _master; + EvasObject _flyout; /// /// The property value. @@ -65,33 +65,33 @@ public class MasterDetailPage : Box bool _isGestureEnabled = true; /// - /// The portion of the screen that the MasterPage takes in Split mode. + /// The portion of the screen that the Flyout takes in Split mode. /// double _splitRatio = 0.35; /// - /// The portion of the screen that the MasterPage takes in Popover mode. + /// The portion of the screen that the Flyout takes in Popover mode. /// double _popoverRatio = 0.8; /// - /// Initializes a new instance of the class. + /// Initializes a new instance of the class. /// /// Parent evas object. - public MasterDetailPage(EvasObject parent) : base(parent) + public FlyoutPage(EvasObject parent) : base(parent) { LayoutUpdated += (s, e) => { UpdateChildCanvasGeometry(); }; - // create the controls which will hold the master and detail pages - _masterCanvas = new Canvas(this); - _masterCanvas.SetAlignment(-1.0, -1.0); // fill - _masterCanvas.SetWeight(1.0, 1.0); // expand - _masterCanvas.LayoutUpdated += (sender, e) => + // create the controls which will hold the flyout and detail pages + _flyoutCanvas = new Canvas(this); + _flyoutCanvas.SetAlignment(-1.0, -1.0); // fill + _flyoutCanvas.SetWeight(1.0, 1.0); // expand + _flyoutCanvas.LayoutUpdated += (sender, e) => { - UpdatePageGeometry(_master); + UpdatePageGeometry(_flyout); }; _detailCanvas = new Canvas(this); @@ -131,13 +131,13 @@ public MasterDetailPage(EvasObject parent) : base(parent) { if (e.PropertyName == nameof(Device.Info.CurrentOrientation)) { - UpdateMasterBehavior(); + UpdateFlyoutLayoutBehavior(); } }; } /// - /// Occurs when the MasterPage is shown or hidden. + /// Occurs when the Flyout is shown or hidden. /// public event EventHandler IsPresentedChanged; @@ -147,47 +147,47 @@ public MasterDetailPage(EvasObject parent) : base(parent) public event EventHandler UpdateIsPresentChangeable; /// - /// Gets or sets the MasterDetailPage behavior. + /// Gets or sets the FlyoutPage behavior. /// - /// The behavior of the MasterDetailPage requested by the user. - public MasterBehavior MasterBehavior + /// The behavior of the FlyoutPage requested by the user. + public FlyoutLayoutBehavior FlyoutLayoutBehavior { get { - return _masterBehavior; + return _flyoutLayoutBehavior; } set { - _masterBehavior = value; - UpdateMasterBehavior(); + _flyoutLayoutBehavior = value; + UpdateFlyoutLayoutBehavior(); } } /// - /// Gets the MasterDEtailPage was splited + /// Gets the FlyoutPage was splited /// - public bool IsSplit => _internalMasterBehavior == MasterBehavior.Split; + public bool IsSplit => _internalFlyoutLayoutBehavior == FlyoutLayoutBehavior.Split; /// - /// Gets or sets the content of the MasterPage. + /// Gets or sets the content of the Flyout. /// - /// The MasterPage. - public EvasObject Master + /// The Flyout. + public EvasObject Flyout { get { - return _master; + return _flyout; } set { - if (_master != value) + if (_flyout != value) { - _master = value; - UpdatePageGeometry(_master); - _masterCanvas.Children.Clear(); - _masterCanvas.Children.Add(_master); + _flyout = value; + UpdatePageGeometry(_flyout); + _flyoutCanvas.Children.Clear(); + _flyoutCanvas.Children.Add(_flyout); if (!IsSplit) UpdateFocusPolicy(); } @@ -220,9 +220,9 @@ public EvasObject Detail } /// - /// Gets or sets a value indicating whether the MasterPage is shown. + /// Gets or sets a value indicating whether the Flyout is shown. /// - /// true if the MasterPage is presented. + /// true if the Flyout is presented. public bool IsPresented { get @@ -240,9 +240,9 @@ public bool IsPresented } /// - /// Gets or sets a value indicating whether a MasterDetailPage allows showing MasterPage with swipe gesture. + /// Gets or sets a value indicating whether a FlyoutPage allows showing FlyoutPage with swipe gesture. /// - /// true if the MasterPage can be revealed with a gesture. + /// true if the FlyoutPage can be revealed with a gesture. public bool IsGestureEnabled { get @@ -264,7 +264,7 @@ public bool IsGestureEnabled } /// - /// Gets or Sets the portion of the screen that the MasterPage takes in split mode. + /// Gets or Sets the portion of the screen that the FlyoutPage takes in split mode. /// /// The portion. public double SplitRatio @@ -285,7 +285,7 @@ public double SplitRatio } /// - /// Gets or sets the portion of the screen that the MasterPage takes in Popover mode. + /// Gets or sets the portion of the screen that the FlyoutPage takes in Popover mode. /// /// The portion. public double PopoverRatio @@ -324,15 +324,15 @@ protected override void OnUnrealize() /// /// Updates the geometry of the selected page. /// - /// Master or Detail page to be updated. + /// Flyout or Detail page to be updated. void UpdatePageGeometry(EvasObject page) { if (page != null) { - if (_master == page) + if (_flyout == page) { - // update the geometry of the master page - page.Geometry = _masterCanvas.Geometry; + // update the geometry of the flyout page + page.Geometry = _flyoutCanvas.Geometry; } else if (_detail == page) { @@ -343,32 +343,30 @@ void UpdatePageGeometry(EvasObject page) } /// - /// Updates according to set by the user and current screen orientation. + /// Updates according to set by the user and current screen orientation. /// - void UpdateMasterBehavior() + void UpdateFlyoutLayoutBehavior() { - var behavior = (_masterBehavior == MasterBehavior.Default) ? s_defaultMasterBehavior : _masterBehavior; + var behavior = (_flyoutLayoutBehavior == FlyoutLayoutBehavior.Default) ? s_defaultFlyoutLayoutBehavior : _flyoutLayoutBehavior; // Screen orientation affects those 2 behaviors - if (behavior == MasterBehavior.SplitOnLandscape || - behavior == MasterBehavior.SplitOnPortrait) + if (behavior == FlyoutLayoutBehavior.SplitOnLandscape || behavior == FlyoutLayoutBehavior.SplitOnPortrait) { var orientation = Device.Info.CurrentOrientation; - if ((orientation.IsLandscape() && behavior == MasterBehavior.SplitOnLandscape) || - (orientation.IsPortrait() && behavior == MasterBehavior.SplitOnPortrait)) + if ((orientation.IsLandscape() && behavior == FlyoutLayoutBehavior.SplitOnLandscape) || (orientation.IsPortrait() && behavior == FlyoutLayoutBehavior.SplitOnPortrait)) { - behavior = MasterBehavior.Split; + behavior = FlyoutLayoutBehavior.Split; } else { - behavior = MasterBehavior.Popover; + behavior = FlyoutLayoutBehavior.Popover; } } - if (behavior != _internalMasterBehavior) + if (behavior != _internalFlyoutLayoutBehavior) { - _internalMasterBehavior = behavior; + _internalFlyoutLayoutBehavior = behavior; ConfigureLayout(); } } @@ -390,7 +388,7 @@ void ConfigureLayout() // the structure for split mode and for popover mode looks differently if (IsSplit) { - _splitPane.SetLeftPart(_masterCanvas, true); + _splitPane.SetLeftPart(_flyoutCanvas, true); _splitPane.SetRightPart(_detailCanvas, true); _splitPane.Show(); _mainWidget = _splitPane; @@ -402,7 +400,7 @@ void ConfigureLayout() } else { - _drawer.SetContent(_masterCanvas, true); + _drawer.SetContent(_flyoutCanvas, true); _drawer.Show(); _mainWidget = _detailCanvas; PackEnd(_detailCanvas); @@ -413,7 +411,7 @@ void ConfigureLayout() UpdateFocusPolicy(); } - _masterCanvas.Show(); + _flyoutCanvas.Show(); _detailCanvas.Show(); // even though child was changed, Layout callback was not called, so i manually call layout function. @@ -424,7 +422,7 @@ void ConfigureLayout() void UpdateChildCanvasGeometry() { var bound = Geometry; - // main widget should fill the area of the MasterDetailPage + // main widget should fill the area of the FlyoutPage if (_mainWidget != null) { _mainWidget.Geometry = bound; @@ -434,7 +432,7 @@ void UpdateChildCanvasGeometry() _drawer.Geometry = bound; // When a _drawer.IsOpen was false, Content of _drawer area is not allocated. So, need to manaully set the content area if (!IsSplit) - _masterCanvas.Geometry = bound; + _flyoutCanvas.Geometry = bound; } /// @@ -442,13 +440,13 @@ void UpdateChildCanvasGeometry() /// void UpdateFocusPolicy(bool forceAllowFocusAll=false) { - var master = _master as Widget; + var flyout = _flyout as Widget; var detail = _detail as Widget; if(forceAllowFocusAll) { - if (master != null) - master.AllowTreeFocus = true; + if (flyout != null) + flyout.AllowTreeFocus = true; if (detail != null) detail.AllowTreeFocus = true; return; @@ -460,17 +458,17 @@ void UpdateFocusPolicy(bool forceAllowFocusAll=false) { detail.AllowTreeFocus = false; } - if (master != null) + if (flyout != null) { - master.AllowTreeFocus = true; - master.SetFocus(true); + flyout.AllowTreeFocus = true; + flyout.SetFocus(true); } } else { - if (master != null) + if (flyout != null) { - master.AllowTreeFocus = false; + flyout.AllowTreeFocus = false; } if (detail != null) { diff --git a/Xamarin.Forms.Platform.Tizen/Properties/AssemblyInfo.cs b/Xamarin.Forms.Platform.Tizen/Properties/AssemblyInfo.cs index 11ae976d86c..a81899d88ed 100644 --- a/Xamarin.Forms.Platform.Tizen/Properties/AssemblyInfo.cs +++ b/Xamarin.Forms.Platform.Tizen/Properties/AssemblyInfo.cs @@ -14,6 +14,7 @@ #pragma warning disable CS0618 // Type or member is obsolete [assembly: ExportRenderer(typeof(MasterDetailPage), typeof(MasterDetailPageRenderer))] #pragma warning restore CS0618 // Type or member is obsolete +[assembly: ExportRenderer(typeof(FlyoutPage), typeof(FlyoutPageRenderer))] [assembly: ExportRenderer(typeof(TabbedPage), typeof(TabbedPageRenderer))] [assembly: ExportRenderer(typeof(Shell), typeof(ShellRenderer))] diff --git a/Xamarin.Forms.Platform.Tizen/Renderers/FlyoutContainer.cs b/Xamarin.Forms.Platform.Tizen/Renderers/FlyoutContainer.cs new file mode 100644 index 00000000000..401773c75f8 --- /dev/null +++ b/Xamarin.Forms.Platform.Tizen/Renderers/FlyoutContainer.cs @@ -0,0 +1,135 @@ +using System; + +namespace Xamarin.Forms.Platform.Tizen.Renderers +{ + public class FlyoutContainer : ElmSharp.Box, IDisposable + { + readonly FlyoutPage _parent; + readonly bool _isFlyout; + + VisualElement _childView; + bool _disposed; + bool _hasAppearedToParent; + + IPageController PageController => ChildView as IPageController; + + IFlyoutPageController FlyoutPageController => _parent as IFlyoutPageController; + + public FlyoutContainer(FlyoutPage parentElement, bool isFlyout) : base(Forms.NativeParent) + { + _parent = parentElement; + _isFlyout = isFlyout; + + SetLayoutCallback(OnLayoutUpdated); + Show(); + } + + ~FlyoutContainer() + { + Dispose(false); + } + + public VisualElement ChildView + { + get { return _childView; } + set + { + if (_childView == value) + return; + + if (_childView != null) + { + RemoveChildView(); + } + + _childView = value; + + if (_childView == null) + return; + + AddChildView(_childView); + + if (_hasAppearedToParent) + { + Device.BeginInvokeOnMainThread(() => + { + if (!_disposed && _hasAppearedToParent) + PageController?.SendAppearing(); + }); + } + } + } + + public void Dispose() + { + Dispose(true); + GC.SuppressFinalize(this); + } + + protected void RemoveChildView() + { + IVisualElementRenderer childRenderer = Platform.GetRenderer(_childView); + if (childRenderer != null) + { + UnPack(childRenderer.NativeView); + childRenderer.Dispose(); + } + } + + protected void AddChildView(VisualElement childView) + { + IVisualElementRenderer renderer = Platform.GetOrCreateRenderer(childView); + this.PackEnd(renderer.NativeView); + } + + protected virtual void Dispose(bool disposing) + { + if (_disposed) + return; + + if (disposing) + { + if (_childView != null) + { + RemoveChildView(); + } + SetLayoutCallback(null); + } + _disposed = true; + } + + void OnLayoutUpdated() + { + if (_childView != null) + { + if (_isFlyout) + FlyoutPageController.FlyoutBounds = this.Geometry.ToDP(); + else + FlyoutPageController.DetailBounds = this.Geometry.ToDP(); + + IVisualElementRenderer renderer = Platform.GetRenderer(_childView); + renderer.NativeView.Geometry = this.Geometry; + } + } + + public void SendAppearing() + { + if (_hasAppearedToParent) + return; + + _hasAppearedToParent = true; + + PageController?.SendAppearing(); + } + + public void SendDisappearing() + { + if (!_hasAppearedToParent) + return; + + _hasAppearedToParent = false; + + PageController?.SendDisappearing(); + } + } +} \ No newline at end of file diff --git a/Xamarin.Forms.Platform.Tizen/Renderers/FlyoutPageRenderer.cs b/Xamarin.Forms.Platform.Tizen/Renderers/FlyoutPageRenderer.cs new file mode 100644 index 00000000000..7ecf427d7db --- /dev/null +++ b/Xamarin.Forms.Platform.Tizen/Renderers/FlyoutPageRenderer.cs @@ -0,0 +1,154 @@ +using System; +using Xamarin.Forms.Platform.Tizen.Renderers; + +namespace Xamarin.Forms.Platform.Tizen +{ + public class FlyoutPageRenderer : VisualElementRenderer + { + Native.FlyoutPage _flyoutPage; + FlyoutContainer _flyoutContainer = null; + FlyoutContainer _detailContainer = null; + + /// + /// Default constructor. + /// + public FlyoutPageRenderer() + { + RegisterPropertyHandler(nameof(Element.Flyout), UpdateFlyout); + RegisterPropertyHandler(nameof(Element.Detail), UpdateDetail); + RegisterPropertyHandler(FlyoutPage.IsPresentedProperty, UpdateIsPresented); + RegisterPropertyHandler(FlyoutPage.FlyoutLayoutBehaviorProperty, UpdateFlyoutLayoutBehavior); + RegisterPropertyHandler(FlyoutPage.IsGestureEnabledProperty, UpdateIsGestureEnabled); + } + + protected override void OnElementChanged(ElementChangedEventArgs e) + { + if (_flyoutPage == null) + { + _flyoutPage = new Native.FlyoutPage(Forms.NativeParent) + { + IsPresented = e.NewElement.IsPresented, + Flyout = _flyoutContainer = new FlyoutContainer(Element, true), + Detail = _detailContainer = new FlyoutContainer(Element, false), + }; + + _flyoutPage.IsPresentedChanged += (sender, ev) => + { + Element.IsPresented = ev.IsPresent; + }; + _flyoutPage.UpdateIsPresentChangeable += (sender, ev) => + { + (Element as IFlyoutPageController).CanChangeIsPresented = ev.CanChange; + }; + SetNativeView(_flyoutPage); + } + + if (e.OldElement != null) + { + (e.OldElement as IFlyoutPageController).BackButtonPressed -= OnBackButtonPressed; + e.OldElement.Appearing -= OnFlyoutPageAppearing; + e.OldElement.Disappearing -= OnFlyoutPageDisappearing; + } + + if (e.NewElement != null) + { + (e.NewElement as IFlyoutPageController).BackButtonPressed += OnBackButtonPressed; + e.NewElement.Appearing += OnFlyoutPageAppearing; + e.NewElement.Disappearing += OnFlyoutPageDisappearing; + } + + UpdateFlyoutLayoutBehavior(); + base.OnElementChanged(e); + } + + void OnFlyoutPageDisappearing(object sender, EventArgs e) + { + _flyoutContainer?.SendDisappearing(); + _detailContainer?.SendDisappearing(); + } + + void OnFlyoutPageAppearing(object sender, EventArgs e) + { + _flyoutContainer?.SendAppearing(); + _detailContainer?.SendAppearing(); + } + + protected override void OnElementReady() + { + base.OnElementReady(); + UpdateFlyout(false); + UpdateDetail(false); + } + + protected override void Dispose(bool disposing) + { + if (disposing) + { + if (_flyoutContainer != null) + { + _flyoutContainer.Dispose(); + _flyoutContainer = null; + } + + if (_detailContainer != null) + { + _detailContainer.Dispose(); + _detailContainer = null; + } + + if (Element != null) + { + Element.Appearing -= OnFlyoutPageAppearing; + Element.Disappearing -= OnFlyoutPageDisappearing; + } + } + + base.Dispose(disposing); + } + + protected void UpdateFlyoutRatio(double popoverRatio, double splitRatio) + { + _flyoutPage.PopoverRatio = popoverRatio; + _flyoutPage.SplitRatio = splitRatio; + } + + void OnBackButtonPressed(object sender, BackButtonPressedEventArgs e) + { + if ((Element != null) && Element.IsPresented && !_flyoutPage.IsSplit) + { + Element.IsPresented = false; + e.Handled = true; + } + } + + void UpdateFlyoutLayoutBehavior() + { + _flyoutPage.FlyoutLayoutBehavior = Element.FlyoutLayoutBehavior; + } + + void UpdateFlyout(bool isInit) + { + if (!isInit) + _flyoutContainer.ChildView = Element.Flyout; + } + + void UpdateDetail(bool isInit) + { + if (!isInit) + _detailContainer.ChildView = Element.Detail; + } + + void UpdateIsPresented() + { + // To update TabIndex order + CustomFocusManager.StartReorderTabIndex(); + + _flyoutPage.IsPresented = Element.IsPresented; + } + + void UpdateIsGestureEnabled() + { + _flyoutPage.IsGestureEnabled = Element.IsGestureEnabled; + } + } +} diff --git a/Xamarin.Forms.Platform.Tizen/Renderers/MasterDetailContainer.cs b/Xamarin.Forms.Platform.Tizen/Renderers/MasterDetailContainer.cs index c6b93819b15..ab8dc5e455c 100644 --- a/Xamarin.Forms.Platform.Tizen/Renderers/MasterDetailContainer.cs +++ b/Xamarin.Forms.Platform.Tizen/Renderers/MasterDetailContainer.cs @@ -2,6 +2,7 @@ namespace Xamarin.Forms.Platform.Tizen.Renderers { + [Obsolete("MasterDetailContainer is obsolete as of version 5.0.0. Please use FlyoutContainer instead.")] public class MasterDetailContainer : ElmSharp.Box, IDisposable { #pragma warning disable CS0618 // Type or member is obsolete diff --git a/Xamarin.Forms.Platform.Tizen/Renderers/MasterDetailPageRenderer.cs b/Xamarin.Forms.Platform.Tizen/Renderers/MasterDetailPageRenderer.cs index 0a13adc7069..589767e0e15 100644 --- a/Xamarin.Forms.Platform.Tizen/Renderers/MasterDetailPageRenderer.cs +++ b/Xamarin.Forms.Platform.Tizen/Renderers/MasterDetailPageRenderer.cs @@ -4,9 +4,10 @@ namespace Xamarin.Forms.Platform.Tizen { #pragma warning disable CS0618 // Type or member is obsolete + [Obsolete("MasterDetailPage is obsolete as of version 5.0.0. Please use FlyoutPage instead.")] public class MasterDetailPageRenderer : VisualElementRenderer { - Native.MasterDetailPage _mdpage; + Native.FlyoutPage _mdpage; MasterDetailContainer _masterContainer = null; MasterDetailContainer _detailContainer = null; @@ -29,10 +30,10 @@ protected override void OnElementChanged(ElementChangedEventArgs> custom #pragma warning disable CS0618 // Type or member is obsolete Registered.Register(typeof(MasterDetailPage), () => new MasterDetailPageRenderer()); #pragma warning restore CS0618 // Type or member is obsolete + Registered.Register(typeof(FlyoutPage), () => new FlyoutPageRenderer()); Registered.Register(typeof(TabbedPage), () => new TabbedPageRenderer()); Registered.Register(typeof(Label), () => new LabelRenderer()); Registered.Register(typeof(Button), () => new ButtonRenderer());