From 10484c54bbd17bc6b61ae60594eec00704fb233d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=9D=B4=EC=8A=B9=EA=B7=BC/Common=20Platform=20Lab=28SR?= =?UTF-8?q?=29/=EC=82=BC=EC=84=B1=EC=A0=84=EC=9E=90?= Date: Tue, 31 May 2022 18:08:45 +0900 Subject: [PATCH] Implement Controls.Compatibility for tizen (#493) --- .../Handlers/Tizen/FrameRenderer.cs | 277 ++++++++++++++++++ .../Handlers/Tizen/ViewRenderer.cs | 77 +++++ .../Handlers/Tizen/VisualElementRenderer.cs | 54 ++++ .../Handlers/ViewHandlerDelegator.cs | 2 +- .../Handlers/VisualElementRenderer.cs | 8 +- .../Xaml/Hosting/AppHostBuilderExtensions.cs | 3 + .../src/Handlers/View/ViewHandlerOfT.Tizen.cs | 53 +--- .../Handlers/ViewHandlerExtensions.Tizen.cs | 101 +++++++ .../src/Platform/Tizen/ContentViewGroup.cs | 11 +- src/Core/src/Platform/Tizen/WrapperView.cs | 15 +- 10 files changed, 545 insertions(+), 56 deletions(-) create mode 100644 src/Controls/src/Core/Compatibility/Handlers/Tizen/FrameRenderer.cs create mode 100644 src/Controls/src/Core/Compatibility/Handlers/Tizen/ViewRenderer.cs create mode 100644 src/Controls/src/Core/Compatibility/Handlers/Tizen/VisualElementRenderer.cs create mode 100644 src/Core/src/Handlers/ViewHandlerExtensions.Tizen.cs diff --git a/src/Controls/src/Core/Compatibility/Handlers/Tizen/FrameRenderer.cs b/src/Controls/src/Core/Compatibility/Handlers/Tizen/FrameRenderer.cs new file mode 100644 index 000000000000..36e5a8888e9f --- /dev/null +++ b/src/Controls/src/Core/Compatibility/Handlers/Tizen/FrameRenderer.cs @@ -0,0 +1,277 @@ +#nullable enable + +using System.ComponentModel; +using Microsoft.Maui.Controls.Platform; +using Microsoft.Maui.Graphics; +using SkiaSharp; +using Tizen.UIExtensions.NUI; +using IMeasurable = Tizen.UIExtensions.Common.IMeasurable; +using TColor = Tizen.UIExtensions.Common.Color; +using NColor = Tizen.NUI.Color; +using TShadow = Tizen.NUI.Shadow; +using TLayoutParamPolicies = Tizen.NUI.BaseComponents.LayoutParamPolicies; + +namespace Microsoft.Maui.Controls.Handlers.Compatibility +{ + public class FrameRenderer : ContentViewGroup, IPlatformViewHandler, IMeasurable + { + public static IPropertyMapper Mapper + = new PropertyMapper(ViewRenderer.VisualElementRendererMapper) + { + [Frame.HasShadowProperty.PropertyName] = (h, _) => h.UpdateShadow(), + [VisualElement.BackgroundColorProperty.PropertyName] = (h, _) => h.UpdateBackgroundColor(), + [VisualElement.BackgroundProperty.PropertyName] = (h, _) => h.UpdateBackground(), + [Frame.CornerRadiusProperty.PropertyName] = (h, _) => h.UpdateCornerRadius(), + [Frame.BorderColorProperty.PropertyName] = (h, _) => h.UpdateBorderColor(), + [Microsoft.Maui.Controls.Compatibility.Layout.IsClippedToBoundsProperty.PropertyName] = (h, _) => h.UpdateClippedToBounds(), + [Frame.ContentProperty.PropertyName] = (h, _) => h.UpdateContent() + }; + + public static CommandMapper CommandMapper + = new CommandMapper(ViewRenderer.VisualElementRendererCommandMapper); + + bool _disposed; + + SKClipperView _clipperView; + + IMauiContext? _mauiContext; + ViewHandlerDelegator _viewHandlerWrapper; + IPlatformViewHandler? _contentHandler; + + + public FrameRenderer() : base(null) + { + _clipperView = new SKClipperView() + { + WidthSpecification = TLayoutParamPolicies.MatchParent, + HeightSpecification = TLayoutParamPolicies.MatchParent + }; + _clipperView.DrawClippingArea += OnDrawClippingArea; + + Children.Add(_clipperView); + + BorderlineColor = NColor.Black; + BorderlineWidth = 1.0.ToScaledPixel(); + _viewHandlerWrapper = new ViewHandlerDelegator(Mapper, CommandMapper, this); + } + + protected Frame? Element + { + get { return _viewHandlerWrapper.Element; } + set + { + if (value != null) + (this as IPlatformViewHandler).SetVirtualView(value); + } + } + + protected override void Dispose(bool disposing) + { + if (_disposed) + return; + + _disposed = true; + + if (disposing) + { + if (Element != null) + { + Element.PropertyChanged -= OnElementPropertyChanged; + } + + Element?.Handler?.DisconnectHandler(); + } + + base.Dispose(disposing); + } + + protected virtual void OnElementChanged(ElementChangedEventArgs e) + { + if (e.NewElement != null) + { + CrossPlatformArrange = e.NewElement.CrossPlatformArrange; + CrossPlatformMeasure = e.NewElement.CrossPlatformMeasure; + } + } + + protected virtual void OnElementPropertyChanged(object? sender, PropertyChangedEventArgs e) + { + if (_disposed) + { + return; + } + + if (Element != null && e.PropertyName != null) + _viewHandlerWrapper.UpdateProperty(e.PropertyName); + } + + void OnDrawClippingArea(object? sender, SkiaSharp.Views.Tizen.SKPaintSurfaceEventArgs e) + { + if (Element == null || _disposed) + return; + + var canvas = e.Surface.Canvas; + var directRect = e.Info.Rect; + canvas.Clear(); + + if (!Element.IsClippedToBounds) + { + canvas.Clear(SKColors.White); + return; + } + var radius = ((double)Element.CornerRadius).ToScaledPixel(); + using var paint = new SKPaint + { + Color = SKColors.White, + }; + canvas.DrawRoundRect(directRect, new SKSize(radius, radius), paint); + } + + void UpdateClippedToBounds() + { + if (Element == null || _disposed) + return; + + _clipperView.Invalidate(); + } + + void UpdateBackgroundColor() + { + if (Element == null || _disposed) + return; + + BackgroundColor = Element.BackgroundColor.ToNUIColor(); + } + + void UpdateBackground() + { + if (Element == null || _disposed) + return; + + var color = ((Paint)Element.Background)?.ToColor(); + if (color != null) + BackgroundColor = color.ToNUIColor(); + } + + void UpdateBorderColor() + { + if (Element == null || _disposed) + return; + + if (Element.BorderColor.IsNotDefault()) + BorderlineColor = Element.BorderColor.ToNUIColor(); + else + BorderlineColor = Tizen.NUI.Color.Black; + } + + void UpdateShadow() + { + if (Element == null || _disposed) + return; + + if (Element.HasShadow) + { + BoxShadow = new TShadow(6.0.ToScaledPixel(), TColor.FromHex("#111111").ToNative()); + } + else + { + BoxShadow = null; + } + } + + void UpdateCornerRadius() + { + if (Element == null || _disposed) + return; + + CornerRadius = ((double)Element.CornerRadius).ToScaledPixel(); + } + + void UpdateContent() + { + var content = Element?.Content; + + if (_contentHandler != null) + { + if (_contentHandler.PlatformView != null) + { + _clipperView.Remove(_contentHandler.PlatformView); + } + _contentHandler?.Dispose(); + _contentHandler = null; + } + + + if (content == null || _mauiContext == null || _disposed) + { + return; + } + + var platformView = content.ToPlatform(_mauiContext); + platformView.WidthSpecification = TLayoutParamPolicies.MatchParent; + platformView.HeightSpecification = TLayoutParamPolicies.MatchParent; + _clipperView.Add(platformView); + if (content.Handler is IPlatformViewHandler thandler) + { + _contentHandler = thandler; + } + } + + #region IPlatformViewHandler + Size IViewHandler.GetDesiredSize(double widthConstraint, double heightConstraint) + { + if (Element?.Handler is IPlatformViewHandler pvh && Element is IContentView cv) + { + return pvh.MeasureVirtualView(widthConstraint, heightConstraint, cv.CrossPlatformMeasure); + } + else + { + return Graphics.Size.Zero; + } + } + + bool IViewHandler.HasContainer { get => false; set { } } + + object? IViewHandler.ContainerView => null; + + IView? IViewHandler.VirtualView => Element; + + object IElementHandler.PlatformView => this; + + Maui.IElement? IElementHandler.VirtualView => Element; + + IMauiContext? IElementHandler.MauiContext => _mauiContext; + + Tizen.NUI.BaseComponents.View? IPlatformViewHandler.PlatformView => this; + + Tizen.NUI.BaseComponents.View? IPlatformViewHandler.ContainerView => this; + + void IViewHandler.PlatformArrange(Graphics.Rect rect) => + this.PlatformArrangeHandler(rect); + + void IElementHandler.SetMauiContext(IMauiContext mauiContext) => + _mauiContext = mauiContext; + + void IElementHandler.SetVirtualView(Maui.IElement view) => + _viewHandlerWrapper.SetVirtualView(view, OnElementChanged, false); + + void IElementHandler.UpdateValue(string property) + { + if (Element != null) + { + OnElementPropertyChanged(Element, new PropertyChangedEventArgs(property)); + } + } + + void IElementHandler.Invoke(string command, object? args) + { + _viewHandlerWrapper.Invoke(command, args); + } + + void IElementHandler.DisconnectHandler() + { + _viewHandlerWrapper.DisconnectHandler(); + } + #endregion + } +} diff --git a/src/Controls/src/Core/Compatibility/Handlers/Tizen/ViewRenderer.cs b/src/Controls/src/Core/Compatibility/Handlers/Tizen/ViewRenderer.cs new file mode 100644 index 000000000000..1021adbb00a3 --- /dev/null +++ b/src/Controls/src/Core/Compatibility/Handlers/Tizen/ViewRenderer.cs @@ -0,0 +1,77 @@ +#nullable enable +using Tizen.UIExtensions.NUI; +using PlatformView = Tizen.NUI.BaseComponents.View; + +namespace Microsoft.Maui.Controls.Handlers.Compatibility +{ + public abstract partial class ViewRenderer : ViewRenderer + { + } + + public abstract partial class ViewRenderer : VisualElementRenderer, IPlatformViewHandler + where TElement : View, IView + where TPlatformView : PlatformView + { + TPlatformView? _platformView; + ViewGroup? _container; + + public TPlatformView? Control => ((IElementHandler)this).PlatformView as TPlatformView ?? _platformView; + object? IElementHandler.PlatformView => _platformView; + + public ViewRenderer() : this(VisualElementRendererMapper, VisualElementRendererCommandMapper) + { + } + + internal ViewRenderer(IPropertyMapper mapper, CommandMapper? commandMapper = null) + : base(mapper, commandMapper) + { + } + + protected virtual TPlatformView CreateNativeControl() + { + return default(TPlatformView)!; + } + + protected void SetNativeControl(TPlatformView control) + { + SetNativeControl(control, this); + } + + internal void SetNativeControl(TPlatformView control, ViewGroup container) + { + if (Control != null) + { + Children.Remove(Control); + } + + _container = container; + _platformView = control; + + var toAdd = container == this ? control : (PlatformView)container; + toAdd.WidthSpecification = Tizen.NUI.BaseComponents.LayoutParamPolicies.MatchParent; + toAdd.HeightSpecification = Tizen.NUI.BaseComponents.LayoutParamPolicies.MatchParent; + Children.Add(toAdd); + } + + private protected override void DisconnectHandlerCore() + { + if (_platformView != null && Element != null) + { + // We set the PlatformView to null so no one outside of this handler tries to access + // PlatformView. PlatformView access should be isolated to the instance passed into + // DisconnectHandler + var oldPlatformView = _platformView; + _platformView = null; + DisconnectHandler(oldPlatformView); + } + + base.DisconnectHandlerCore(); + } + + protected virtual void DisconnectHandler(TPlatformView oldPlatformView) + { + } + + PlatformView? IPlatformViewHandler.ContainerView => _container; + } +} \ No newline at end of file diff --git a/src/Controls/src/Core/Compatibility/Handlers/Tizen/VisualElementRenderer.cs b/src/Controls/src/Core/Compatibility/Handlers/Tizen/VisualElementRenderer.cs new file mode 100644 index 000000000000..29872ddefbe4 --- /dev/null +++ b/src/Controls/src/Core/Compatibility/Handlers/Tizen/VisualElementRenderer.cs @@ -0,0 +1,54 @@ +#nullable enable +using Microsoft.Maui.Controls.Platform; +using Microsoft.Maui.Graphics; +using Tizen.UIExtensions.NUI; +using IMeasurable = Tizen.UIExtensions.Common.IMeasurable; +using TSize = Tizen.UIExtensions.Common.Size; + +namespace Microsoft.Maui.Controls.Handlers.Compatibility +{ + public abstract partial class VisualElementRenderer : ViewGroup, IPlatformViewHandler, IMeasurable + where TElement : Element, IView + { + object? IElementHandler.PlatformView => Children.Count > 0 ? Children[0] : null; + + static partial void ProcessAutoPackage(IElement element) + { + if (element?.Handler?.PlatformView is not ViewGroup viewGroup) + return; + + viewGroup.Children.Clear(); + + if (element is not IVisualTreeElement vte) + return; + + var mauiContext = element?.Handler?.MauiContext; + if (mauiContext == null) + return; + + foreach (var child in vte.GetVisualChildren()) + { + if (child is IElement childElement) + viewGroup.Children.Add(childElement.ToPlatform(mauiContext)); + } + } + + public void UpdateLayout() + { + if (Element != null) + this.InvalidateMeasure(Element); + } + + TSize IMeasurable.Measure(double availableWidth, double availableHeight) + { + if (Children.Count > 0 && Children[0] is IMeasurable measurable) + { + return measurable.Measure(availableWidth, availableHeight); + } + else + { + return NaturalSize2D.ToCommon(); + } + } + } +} diff --git a/src/Controls/src/Core/Compatibility/Handlers/ViewHandlerDelegator.cs b/src/Controls/src/Core/Compatibility/Handlers/ViewHandlerDelegator.cs index d38d53dc7cb1..da8ededfc58d 100644 --- a/src/Controls/src/Core/Compatibility/Handlers/ViewHandlerDelegator.cs +++ b/src/Controls/src/Core/Compatibility/Handlers/ViewHandlerDelegator.cs @@ -1,6 +1,6 @@ #nullable enable -#if WINDOWS || IOS || ANDROID +#if WINDOWS || IOS || ANDROID || TIZEN using System; using System.Collections.Generic; using System.Text; diff --git a/src/Controls/src/Core/Compatibility/Handlers/VisualElementRenderer.cs b/src/Controls/src/Core/Compatibility/Handlers/VisualElementRenderer.cs index 70829f5f4161..789187f086fb 100644 --- a/src/Controls/src/Core/Compatibility/Handlers/VisualElementRenderer.cs +++ b/src/Controls/src/Core/Compatibility/Handlers/VisualElementRenderer.cs @@ -1,5 +1,5 @@ #nullable enable -#if WINDOWS || ANDROID || IOS +#if WINDOWS || ANDROID || IOS || TIZEN using System; using System.Collections.Generic; @@ -13,6 +13,8 @@ using PlatformView = Android.Views.View; #elif IOS using PlatformView = UIKit.UIView; +#elif TIZEN +using PlatformView = Tizen.NUI.BaseComponents.View; #endif namespace Microsoft.Maui.Controls.Handlers.Compatibility @@ -153,7 +155,11 @@ public virtual SizeRequest GetDesiredSize(double widthConstraint, double heightC return new SizeRequest(size, minSize); } +#if TIZEN + protected new virtual Size MinimumSize() +#else protected virtual Size MinimumSize() +#endif { return new Size(); } diff --git a/src/Controls/src/Xaml/Hosting/AppHostBuilderExtensions.cs b/src/Controls/src/Xaml/Hosting/AppHostBuilderExtensions.cs index c835a26effe7..e006424c99de 100644 --- a/src/Controls/src/Xaml/Hosting/AppHostBuilderExtensions.cs +++ b/src/Controls/src/Xaml/Hosting/AppHostBuilderExtensions.cs @@ -108,6 +108,9 @@ public static IMauiHandlersCollection AddMauiControlsHandlers(this IMauiHandlers handlersCollection.AddHandler(typeof(TableView), typeof(Handlers.Compatibility.TableViewRenderer)); handlersCollection.AddHandler(typeof(Frame), typeof(Handlers.Compatibility.FrameRenderer)); #endif +#if TIZEN + handlersCollection.AddHandler(typeof(Frame), typeof(Handlers.Compatibility.FrameRenderer)); +#endif #if WINDOWS || MACCATALYST handlersCollection.AddHandler(typeof(MenuFlyout), typeof(MenuFlyoutHandler)); diff --git a/src/Core/src/Handlers/View/ViewHandlerOfT.Tizen.cs b/src/Core/src/Handlers/View/ViewHandlerOfT.Tizen.cs index c2e8eeed2285..dcbb4d55968d 100644 --- a/src/Core/src/Handlers/View/ViewHandlerOfT.Tizen.cs +++ b/src/Core/src/Handlers/View/ViewHandlerOfT.Tizen.cs @@ -32,56 +32,11 @@ public abstract partial class ViewHandler : IPlatfo VirtualView?.Shadow != null || base.NeedsContainer; - public override void PlatformArrange(Rect frame) - { - var platformView = this.ToPlatform(); - - if (platformView == null) - return; - - if (frame.Width < 0 || frame.Height < 0) - { - // This is just some initial Forms value nonsense, nothing is actually laying out yet - return; - } - platformView.UpdateBounds(frame.ToPixel()); - } - - public override Size GetDesiredSize(double widthConstraint, double heightConstraint) - { - var platformView = base.PlatformView; - - if (platformView == null || VirtualView == null) - { - return VirtualView == null || double.IsNaN(VirtualView.Width) || double.IsNaN(VirtualView.Height) ? Size.Zero : new Size(VirtualView.Width, VirtualView.Height); - } + public override void PlatformArrange(Rect frame) => + this.PlatformArrangeHandler(frame); - double availableWidth = widthConstraint.ToScaledPixel(); - double availableHeight = heightConstraint.ToScaledPixel(); - - if (availableWidth < 0) - availableWidth = double.PositiveInfinity; - if (availableHeight < 0) - availableHeight = double.PositiveInfinity; - - var explicitWidth = VirtualView.Width; - var explicitHeight = VirtualView.Height; - var hasExplicitWidth = explicitWidth >= 0; - var hasExplicitHeight = explicitHeight >= 0; - - Size measured; - if (platformView is IMeasurable platformViewMeasurable) - { - measured = platformViewMeasurable.Measure(availableWidth, availableHeight).ToDP(); - } - else - { - measured = Measure(availableWidth, availableHeight); - } - - return new Size(hasExplicitWidth ? explicitWidth : measured.Width, - hasExplicitHeight ? explicitHeight : measured.Height); - } + public override Size GetDesiredSize(double widthConstraint, double heightConstraint) => + this.GetDesiredSizeFromHandler(widthConstraint, heightConstraint); protected virtual Size Measure(double availableWidth, double availableHeight) { diff --git a/src/Core/src/Handlers/ViewHandlerExtensions.Tizen.cs b/src/Core/src/Handlers/ViewHandlerExtensions.Tizen.cs new file mode 100644 index 000000000000..bc34dad2567d --- /dev/null +++ b/src/Core/src/Handlers/ViewHandlerExtensions.Tizen.cs @@ -0,0 +1,101 @@ +using System; +using Microsoft.Maui.Graphics; +using Tizen.UIExtensions.NUI; +using NView = Tizen.NUI.BaseComponents.View; +using IMeasurable = Tizen.UIExtensions.Common.IMeasurable; + +namespace Microsoft.Maui +{ + internal static partial class ViewHandlerExtensions + { + internal static Size LayoutVirtualView( + this IPlatformViewHandler viewHandler, Rect frame, + Func? arrangeFunc = null) + { + var virtualView = viewHandler.VirtualView; + var platformView = viewHandler.PlatformView; + + if (virtualView == null || platformView == null) + { + return Size.Zero; + } + + arrangeFunc ??= virtualView.Arrange; + return arrangeFunc(frame); + } + + internal static Size MeasureVirtualView( + this IPlatformViewHandler viewHandler, + double widthConstraint, + double heightConstraint, + Func? measureFunc = null) + { + var virtualView = viewHandler.VirtualView; + var platformView = viewHandler.PlatformView; + + if (virtualView == null || platformView == null) + { + return Size.Zero; + } + + measureFunc ??= virtualView.Measure; + var measure = measureFunc(widthConstraint, heightConstraint); + + return measure; + } + + internal static Size GetDesiredSizeFromHandler(this IViewHandler viewHandler, double widthConstraint, double heightConstraint) + { + var platformView = viewHandler.ToPlatform(); + var virtualView = viewHandler.VirtualView; + + if (platformView == null || virtualView == null) + { + return virtualView == null || double.IsNaN(virtualView.Width) || double.IsNaN(virtualView.Height) ? Size.Zero : new Size(virtualView.Width, virtualView.Height); + } + + double availableWidth = widthConstraint.ToScaledPixel(); + double availableHeight = heightConstraint.ToScaledPixel(); + + if (availableWidth < 0) + availableWidth = double.PositiveInfinity; + if (availableHeight < 0) + availableHeight = double.PositiveInfinity; + + var explicitWidth = virtualView.Width; + var explicitHeight = virtualView.Height; + var hasExplicitWidth = explicitWidth >= 0; + var hasExplicitHeight = explicitHeight >= 0; + + Size measured; + if (platformView is IMeasurable platformViewMeasurable) + { + measured = platformViewMeasurable.Measure(availableWidth, availableHeight).ToDP(); + } + else + { + measured = platformView.NaturalSize2D.ToCommon().ToDP(); + } + + return new Size(hasExplicitWidth ? explicitWidth : measured.Width, + hasExplicitHeight ? explicitHeight : measured.Height); + } + + internal static void PlatformArrangeHandler(this IViewHandler viewHandler, Rect frame) + { + var platformView = viewHandler.ToPlatform(); + + if (platformView == null) + return; + + if (frame.Width < 0 || frame.Height < 0) + { + // This is just some initial Forms value nonsense, nothing is actually laying out yet + return; + } + platformView.UpdateBounds(frame.ToPixel()); + + viewHandler.Invoke(nameof(IView.Frame), frame); + } + } +} diff --git a/src/Core/src/Platform/Tizen/ContentViewGroup.cs b/src/Core/src/Platform/Tizen/ContentViewGroup.cs index f5fe644cacaa..3d137033c6ad 100644 --- a/src/Core/src/Platform/Tizen/ContentViewGroup.cs +++ b/src/Core/src/Platform/Tizen/ContentViewGroup.cs @@ -10,10 +10,10 @@ namespace Microsoft.Maui.Platform { public class ContentViewGroup : ViewGroup, IMeasurable { - IView _virtualView; + IView? _virtualView; Size _measureCache; - public ContentViewGroup(IView view) + public ContentViewGroup(IView? view) { _virtualView = view; LayoutUpdated += OnLayoutUpdated; @@ -30,9 +30,12 @@ public TSize Measure(double availableWidth, double availableHeight) void OnLayoutUpdated(object? sender, LayoutEventArgs e) { + if (CrossPlatformArrange == null || CrossPlatformMeasure == null) + return; + var platformGeometry = this.GetBounds().ToDP(); - var measured = CrossPlatformMeasure!(platformGeometry.Width, platformGeometry.Height); + var measured = CrossPlatformMeasure(platformGeometry.Width, platformGeometry.Height); if (measured != _measureCache && _virtualView?.Parent is IView parentView) { parentView?.InvalidateMeasure(); @@ -43,7 +46,7 @@ void OnLayoutUpdated(object? sender, LayoutEventArgs e) { platformGeometry.X = 0; platformGeometry.Y = 0; - CrossPlatformArrange!(platformGeometry); + CrossPlatformArrange(platformGeometry); } } } diff --git a/src/Core/src/Platform/Tizen/WrapperView.cs b/src/Core/src/Platform/Tizen/WrapperView.cs index 38a46f7ad87c..3937a0abb99c 100644 --- a/src/Core/src/Platform/Tizen/WrapperView.cs +++ b/src/Core/src/Platform/Tizen/WrapperView.cs @@ -5,10 +5,11 @@ using Tizen.UIExtensions.NUI.GraphicsView; using NView = Tizen.NUI.BaseComponents.View; using TRect = Tizen.UIExtensions.Common.Rect; +using TSize = Tizen.UIExtensions.Common.Size; namespace Microsoft.Maui.Platform { - public partial class WrapperView : ViewGroup + public partial class WrapperView : ViewGroup, IMeasurable { Lazy _drawableCanvas; Lazy _clipperView; @@ -166,5 +167,17 @@ void UpdateDrawableCanvasGeometry() } _drawableCanvas.Value.UpdateBounds(bounds); } + + TSize IMeasurable.Measure(double availableWidth, double availableHeight) + { + if (Content is IMeasurable measurable) + { + return measurable.Measure(availableWidth, availableHeight); + } + else + { + return NaturalSize2D.ToCommon(); + } + } } }