Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Android] Fix Frame Renderer to use Wrapper View correctly #12218

Merged
merged 6 commits into from
Mar 17, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -30,7 +28,7 @@ public static IPropertyMapper<Frame, FrameRenderer> 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<Frame, FrameRenderer> CommandMapper
Expand All @@ -48,6 +46,9 @@ public static CommandMapper<Frame, FrameRenderer> CommandMapper
IMauiContext? _mauiContext;
ViewHandlerDelegator<Frame> _viewHandlerWrapper;
Frame? _element;
bool _hasContainer;
AView? _wrapperView;

public event EventHandler<VisualElementChangedEventArgs>? ElementChanged;
public event EventHandler<PropertyChangedEventArgs>? ElementPropertyChanged;

Expand Down Expand Up @@ -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;

Expand All @@ -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);
Expand Down Expand Up @@ -396,6 +419,7 @@ void IElementHandler.DisconnectHandler()
{
_viewHandlerWrapper.DisconnectHandler();
}

#endregion
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
50 changes: 4 additions & 46 deletions src/Core/src/Handlers/View/ViewHandlerOfT.Android.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}
}
51 changes: 51 additions & 0 deletions src/Core/src/Platform/Android/WrapperView.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
#nullable disable
using System;
using Android.Content;
using Android.Graphics;
using Android.Views;
Expand Down Expand Up @@ -326,5 +327,55 @@ public override ViewStates Visibility
}
}
}

internal static void SetupContainer(AView platformView, Context context, AView containerView, Action<AView> 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();
}
}
}
}