diff --git a/src/Controls/src/Core/Compatibility/Handlers/Android/FrameRenderer.cs b/src/Controls/src/Core/Compatibility/Handlers/Android/FrameRenderer.cs index 6271193e3785..8f319a21ead2 100644 --- a/src/Controls/src/Core/Compatibility/Handlers/Android/FrameRenderer.cs +++ b/src/Controls/src/Core/Compatibility/Handlers/Android/FrameRenderer.cs @@ -4,9 +4,7 @@ using Android.Graphics; using Android.Graphics.Drawables; using Android.Views; -using Android.Views.Animations; using AndroidX.CardView.Widget; -using AndroidX.Core.View; using Microsoft.Maui.Controls.Platform; using Microsoft.Maui.Graphics; using AColor = Android.Graphics.Color; @@ -30,7 +28,7 @@ public static IPropertyMapper Mapper [Frame.BorderColorProperty.PropertyName] = (h, _) => h.UpdateBorderColor(), [Microsoft.Maui.Controls.Compatibility.Layout.IsClippedToBoundsProperty.PropertyName] = (h, _) => h.UpdateClippedToBounds(), [Frame.ContentProperty.PropertyName] = (h, _) => h.UpdateContent(), - [nameof(IView.AutomationId)] = (h, v) => ViewHandler.MapAutomationId(h, v), + [nameof(IView.AutomationId)] = (h, v) => ViewHandler.MapAutomationId(h, v) }; public static CommandMapper CommandMapper @@ -48,6 +46,9 @@ public static CommandMapper CommandMapper IMauiContext? _mauiContext; ViewHandlerDelegator _viewHandlerWrapper; Frame? _element; + bool _hasContainer; + AView? _wrapperView; + public event EventHandler? ElementChanged; public event EventHandler? ElementPropertyChanged; @@ -351,9 +352,31 @@ void UpdateContent() } #region IPlatformViewHandler - bool IViewHandler.HasContainer { get => false; set { } } - object? IViewHandler.ContainerView => null; + bool IViewHandler.HasContainer + { + get => _hasContainer; + set + { + if (_hasContainer == value) + return; + + _hasContainer = value; + + if (value) + SetupContainer(); + else + RemoveContainer(); + } + } + + void SetupContainer() => + WrapperView.SetupContainer(this, Context, _wrapperView, (cv) => _wrapperView = cv); + + void RemoveContainer() => + WrapperView.RemoveContainer(this, Context, _wrapperView, () => _wrapperView = null); + + object? IViewHandler.ContainerView => _wrapperView; IView? IViewHandler.VirtualView => Element; @@ -365,7 +388,7 @@ void UpdateContent() AView IPlatformViewHandler.PlatformView => this; - AView? IPlatformViewHandler.ContainerView => this; + AView? IPlatformViewHandler.ContainerView => _wrapperView; void IViewHandler.PlatformArrange(Graphics.Rect rect) => this.PlatformArrangeHandler(rect); @@ -396,6 +419,7 @@ void IElementHandler.DisconnectHandler() { _viewHandlerWrapper.DisconnectHandler(); } + #endregion } } diff --git a/src/Controls/tests/DeviceTests/Elements/Frame/FrameHandlerTest.Android.cs b/src/Controls/tests/DeviceTests/Elements/Frame/FrameHandlerTest.Android.cs index f05babfdc875..0b754454b489 100644 --- a/src/Controls/tests/DeviceTests/Elements/Frame/FrameHandlerTest.Android.cs +++ b/src/Controls/tests/DeviceTests/Elements/Frame/FrameHandlerTest.Android.cs @@ -8,24 +8,6 @@ namespace Microsoft.Maui.DeviceTests { public partial class FrameHandlerTest { - public override Task ContainerViewInitializesCorrectly() - { - // https://github.com/dotnet/maui/pull/12218 - return Task.CompletedTask; - } - - public override Task ContainerViewAddsAndRemoves() - { - // https://github.com/dotnet/maui/pull/12218 - return Task.CompletedTask; - } - - public override Task ContainerViewRemainsIfShadowMapperRunsAgain() - { - // https://github.com/dotnet/maui/pull/12218 - return Task.CompletedTask; - } - public override async Task ReturnsNonEmptyNativeBoundingBox(int size) { // Frames have a legacy hard-coded minimum size of 20x20 diff --git a/src/Core/src/Handlers/View/ViewHandlerOfT.Android.cs b/src/Core/src/Handlers/View/ViewHandlerOfT.Android.cs index 3df16313bae2..996a2202387c 100644 --- a/src/Core/src/Handlers/View/ViewHandlerOfT.Android.cs +++ b/src/Core/src/Handlers/View/ViewHandlerOfT.Android.cs @@ -17,52 +17,10 @@ public override void PlatformArrange(Rect frame) => public override Size GetDesiredSize(double widthConstraint, double heightConstraint) => this.GetDesiredSizeFromHandler(widthConstraint, heightConstraint); - protected override void SetupContainer() - { - if (Context == null || PlatformView == null || ContainerView != null) - return; + protected override void SetupContainer() => + WrapperView.SetupContainer(PlatformView, Context, ContainerView, (cv) => ContainerView = cv); - var oldParent = (ViewGroup?)PlatformView.Parent; - - var oldIndex = oldParent?.IndexOfChild(PlatformView); - oldParent?.RemoveView(PlatformView); - - ContainerView ??= new WrapperView(Context); - ((ViewGroup)ContainerView).AddView(PlatformView); - - if (oldIndex is int idx && idx >= 0) - oldParent?.AddView(ContainerView, idx); - else - oldParent?.AddView(ContainerView); - } - - protected override void RemoveContainer() - { - if (Context == null || PlatformView == null || ContainerView == null || PlatformView.Parent != ContainerView) - { - CleanupContainerView(ContainerView); - ContainerView = null; - return; - } - - var oldParent = (ViewGroup?)ContainerView.Parent; - - var oldIndex = oldParent?.IndexOfChild(ContainerView); - oldParent?.RemoveView(ContainerView); - - CleanupContainerView(ContainerView); - ContainerView = null; - - if (oldIndex is int idx && idx >= 0) - oldParent?.AddView(PlatformView, idx); - else - oldParent?.AddView(PlatformView); - - void CleanupContainerView(View? containerView) - { - if (containerView is ViewGroup vg) - vg.RemoveAllViews(); - } - } + protected override void RemoveContainer() => + WrapperView.RemoveContainer(PlatformView, Context, ContainerView, () => ContainerView = null); } } diff --git a/src/Core/src/Platform/Android/WrapperView.cs b/src/Core/src/Platform/Android/WrapperView.cs index d309e9284f56..9c735c1b37a8 100644 --- a/src/Core/src/Platform/Android/WrapperView.cs +++ b/src/Core/src/Platform/Android/WrapperView.cs @@ -1,4 +1,5 @@ #nullable disable +using System; using Android.Content; using Android.Graphics; using Android.Views; @@ -326,5 +327,55 @@ public override ViewStates Visibility } } } + + internal static void SetupContainer(AView platformView, Context context, AView containerView, Action setWrapperView) + { + if (context == null || platformView == null || containerView != null) + return; + + var oldParent = (ViewGroup)platformView.Parent; + + var oldIndex = oldParent?.IndexOfChild(platformView); + oldParent?.RemoveView(platformView); + + containerView ??= new WrapperView(context); + setWrapperView.Invoke(containerView); + + ((ViewGroup)containerView).AddView(platformView); + + if (oldIndex is int idx && idx >= 0) + oldParent?.AddView(containerView, idx); + else + oldParent?.AddView(containerView); + } + + internal static void RemoveContainer(AView platformView, Context context, AView containerView, Action clearWrapperView) + { + if (context == null || platformView == null || containerView == null || platformView.Parent != containerView) + { + CleanupContainerView(containerView, clearWrapperView); + return; + } + + var oldParent = (ViewGroup)containerView.Parent; + + var oldIndex = oldParent?.IndexOfChild(containerView); + oldParent?.RemoveView(containerView); + + CleanupContainerView(containerView, clearWrapperView); + + if (oldIndex is int idx && idx >= 0) + oldParent?.AddView(platformView, idx); + else + oldParent?.AddView(platformView); + + void CleanupContainerView(AView containerView, Action clearWrapperView) + { + if (containerView is ViewGroup vg) + vg.RemoveAllViews(); + + clearWrapperView.Invoke(); + } + } } } \ No newline at end of file