Skip to content

Commit

Permalink
fix: [iOS] fix pass-through element
Browse files Browse the repository at this point in the history
  • Loading branch information
dr1rrb committed Apr 19, 2024
1 parent 81675a2 commit 8e5aca1
Show file tree
Hide file tree
Showing 3 changed files with 39 additions and 11 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -57,9 +57,9 @@ public async Task FlyoutTest_When_NoOverlayInputPassThroughElement_Then_DontPass
}

#if !IS_RUNTIME_UI_TESTS
[Test][AutoRetry] public Task FlyoutTest_When_OverlayInputPassThroughElement_Then_DontPassThrough_withOn() => FlyoutTest_When_OverlayInputPassThroughElement_Then_PassThrough("withOn");
[Test][AutoRetry] public Task FlyoutTest_When_OverlayInputPassThroughElement_Then_DontPassThrough_withOff() => FlyoutTest_When_OverlayInputPassThroughElement_Then_PassThrough("withOff");
[Test][AutoRetry] public Task FlyoutTest_When_OverlayInputPassThroughElement_Then_DontPassThrough_withAuto() => FlyoutTest_When_OverlayInputPassThroughElement_Then_PassThrough("withAuto");
[Test][AutoRetry] public Task FlyoutTest_When_OverlayInputPassThroughElement_Then_PassThrough_withOn() => FlyoutTest_When_OverlayInputPassThroughElement_Then_PassThrough("withOn");
[Test][AutoRetry] public Task FlyoutTest_When_OverlayInputPassThroughElement_Then_PassThrough_withOff() => FlyoutTest_When_OverlayInputPassThroughElement_Then_PassThrough("withOff");
[Test][AutoRetry] public Task FlyoutTest_When_OverlayInputPassThroughElement_Then_PassThrough_withAuto() => FlyoutTest_When_OverlayInputPassThroughElement_Then_PassThrough("withAuto");
#else
[Test]
[AutoRetry]
Expand Down
38 changes: 33 additions & 5 deletions src/Uno.UI/UI/Xaml/Controls/Flyout/FlyoutPopupPanel.cs
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@
using Microsoft.UI.Xaml.Controls.Primitives;
using Microsoft.UI.Xaml.Input;
using Microsoft.UI.Xaml.Media;
using Uno.Extensions;
using Uno.Foundation.Logging;
using Uno.UI.Extensions;
using Uno.UI.Xaml.Core;

Expand Down Expand Up @@ -43,20 +45,42 @@ public FlyoutBasePopupPanel(FlyoutBase flyout) : base(flyout._popup)

private protected override void OnPointerPressedDismissed(PointerRoutedEventArgs args)
{
if (Flyout.OverlayInputPassThroughElement is not UIElement passThroughElement
|| !Flyout.GetAllParents(includeCurrent: false).Contains(passThroughElement))
if (this.Log().IsEnabled(LogLevel.Debug)) this.Log().Debug($"{this.GetDebugName()} Dismissing flyout (OverlayInputPassThroughElement:{Flyout.OverlayInputPassThroughElement.GetDebugIdentifier()}).");

if (Flyout.OverlayInputPassThroughElement is not UIElement passThroughElement)
{
return;
}

if (!Flyout.GetAllParents(includeCurrent: false).Contains(passThroughElement))
{
// The element must be a parent of the Flyout (not 'this') to be able to receive the pointer events.

if (this.Log().IsEnabled(LogLevel.Debug))
this.Log().Debug($"{this.GetDebugName()} PassThroughElement ignored as element ({Flyout.OverlayInputPassThroughElement?.GetAllParents().Reverse().Select(elt => elt.GetDebugName()).JoinBy(">") ?? "--null--"})"
+ $" is not a parent of the Flyout ({Flyout.GetAllParents().Select(elt => elt.GetDebugName()).Reverse().JoinBy(">")}).");

return;
}

var point = args.GetCurrentPoint(null);
var hitTestIgnoringThis = VisualTreeHelper.DefaultGetTestability.Except(this);
var hitTestIgnoringThis = VisualTreeHelper.DefaultGetTestability.Except(XamlRoot?.VisualTree.PopupRoot as UIElement ?? this);
var (elementHitUnderOverlay, _) = VisualTreeHelper.HitTest(point.Position, passThroughElement.XamlRoot, hitTestIgnoringThis);

if (elementHitUnderOverlay is null
|| !VisualTreeHelper.EnumerateAncestors(elementHitUnderOverlay).Contains(passThroughElement))
if (elementHitUnderOverlay is null)
{
if (this.Log().IsEnabled(LogLevel.Debug))
this.Log().Debug($"{this.GetDebugName()} PassThroughElement ({passThroughElement.GetDebugName()}) ignored as hit-tested element is null.");

return;
}

if(!VisualTreeHelper.EnumerateAncestors(elementHitUnderOverlay).Contains(passThroughElement))
{
if (this.Log().IsEnabled(LogLevel.Debug))
this.Log().Debug($"{this.GetDebugName()} PassThroughElement ({passThroughElement.GetDebugName()}) ignored as hit-tested element ({elementHitUnderOverlay.GetDebugIdentifier()})"
+ $" is not a child of the PassThroughElement ({VisualTreeHelper.EnumerateAncestors(elementHitUnderOverlay).Reverse().Select(elt => elt.GetDebugIdentifier()).JoinBy(">") ?? "--null--"}).");

// The element found by the HitTest is not a child of the pass-through element.
return;
}
Expand All @@ -65,6 +89,10 @@ private protected override void OnPointerPressedDismissed(PointerRoutedEventArgs
XamlRoot?.VisualTree.ContentRoot.InputManager.Pointers.ReRoute(args, from: this, to: elementHitUnderOverlay);
#else
XamlRoot?.VisualTree.RootVisual.ReRoutePointerDownEvent(args, from: this, to: elementHitUnderOverlay);
#if __IOS__
// On iOS, the FlyoutPopupPanel does not have nay parent (cf. https://github.com/unoplatform/uno/issues/14405), so we are forcefully causing the ProcessPointerDown here.
XamlRoot?.VisualTree.RootVisual.ProcessPointerDown(args);
#endif
#endif
}
}
Expand Down
6 changes: 3 additions & 3 deletions src/Uno.UI/UI/Xaml/HitTestability.cs
Original file line number Diff line number Diff line change
Expand Up @@ -38,10 +38,10 @@ internal record struct StalePredicate(PredicateOfUIElement Method, string Name);
internal static class GetHitTestabilityExtensions
{
/// <summary>
/// Wrap the given hitTest delegate to exclude (i.e. consider as <see cref="HitTestability.Invisible"/>) the provided element.
/// Wrap the given hitTest delegate to exclude (i.e. consider as <see cref="HitTestability.Collapsed"/>) the provided element.
/// </summary>
/// <param name="hitTest">The hit-testing delegate to wrap.</param>
/// <param name="element">The element that should be considered as <see cref="HitTestability.Invisible"/>)</param>
/// <param name="element">The element that should be considered as <see cref="HitTestability.Collapsed"/>)</param>
/// <returns></returns>
internal static GetHitTestability Except(this GetHitTestability hitTest, UIElement element)
{
Expand All @@ -50,7 +50,7 @@ internal static GetHitTestability Except(this GetHitTestability hitTest, UIEleme
{
if (elt == element)
{
return (HitTestability.Invisible, hitTest);
return (HitTestability.Collapsed, hitTest);
}
else
{
Expand Down

0 comments on commit 8e5aca1

Please sign in to comment.