From 9be72fbc477ecae15394a9025d12f419014013af Mon Sep 17 00:00:00 2001 From: Ramez Ragaa Date: Thu, 19 Dec 2024 19:23:10 +0200 Subject: [PATCH 1/3] fix(popup): fall back to PlacementArrangeOverride when popup would otherwise be placed outside the window --- .../UI/Xaml/Controls/Popup/PopupPanel.cs | 38 +++++++++---------- 1 file changed, 19 insertions(+), 19 deletions(-) diff --git a/src/Uno.UI/UI/Xaml/Controls/Popup/PopupPanel.cs b/src/Uno.UI/UI/Xaml/Controls/Popup/PopupPanel.cs index 5fd44c548318..0418977bc708 100644 --- a/src/Uno.UI/UI/Xaml/Controls/Popup/PopupPanel.cs +++ b/src/Uno.UI/UI/Xaml/Controls/Popup/PopupPanel.cs @@ -121,25 +121,6 @@ protected override Size ArrangeOverride(Size finalSize) } else if (Popup.CustomLayouter == null) { - // TODO: For now, the layouting logic for managed DatePickerFlyout or TimePickerFlyout does not correctly work - // against the placement target approach. - var isFlyoutManagedDatePicker = - (Popup.AssociatedFlyout is DatePickerFlyout || Popup.AssociatedFlyout is TimePickerFlyout) -#if __ANDROID__ || __IOS__ - && (Popup.AssociatedFlyout is not NativeDatePickerFlyout && Popup.AssociatedFlyout is not NativeTimePickerFlyout) -#endif - ; - - if (!isFlyoutManagedDatePicker && - Popup.PlacementTarget is not null -#if __ANDROID__ || __IOS__ - || NativeAnchor is not null -#endif - ) - { - return PlacementArrangeOverride(Popup, finalSize); - } - // Gets the location of the popup (or its Anchor) in the VisualTree, so we will align Top/Left with it // Note: we do not prevent overflow of the popup on any side as UWP does not! // (And actually it also lets the view appear out of the window ...) @@ -175,6 +156,25 @@ Popup.PlacementTarget is not null size.Width, size.Height); + // TODO: For now, the layouting logic for managed DatePickerFlyout or TimePickerFlyout does not correctly work + // against the placement target approach. + var isFlyoutManagedDatePicker = + (Popup.AssociatedFlyout is DatePickerFlyout || Popup.AssociatedFlyout is TimePickerFlyout) +#if __ANDROID__ || __IOS__ + && (Popup.AssociatedFlyout is not NativeDatePickerFlyout && Popup.AssociatedFlyout is not NativeTimePickerFlyout) +#endif + ; + + if (!isFlyoutManagedDatePicker && Popup.PlacementTarget is not null +#if __ANDROID__ || __IOS__ + || NativeAnchor is not null +#endif + || !finalFrame.IntersectWith(GetVisibleBounds()).Equals(finalFrame) // if the finalFrame spills out of the window, always use PlacementArrangeOverride + ) + { + return PlacementArrangeOverride(Popup, finalSize); + } + ArrangeElement(child, finalFrame); // Temporary workaround to avoid layout cycle on iOS. This block was added specifically for a bug on Android's From 77656ae0d3c1351e5a0fb574c9b256170fb25763 Mon Sep 17 00:00:00 2001 From: Ramez Ragaa Date: Thu, 19 Dec 2024 19:58:10 +0200 Subject: [PATCH 2/3] test: add When_TimePickerFlyout_Placed_Outside_Window --- .../Given_TimePicker.cs | 21 +++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/src/Uno.UI.RuntimeTests/Tests/Windows_UI_Xaml_Controls/Given_TimePicker.cs b/src/Uno.UI.RuntimeTests/Tests/Windows_UI_Xaml_Controls/Given_TimePicker.cs index db3cc5ef1b31..053b611679b9 100644 --- a/src/Uno.UI.RuntimeTests/Tests/Windows_UI_Xaml_Controls/Given_TimePicker.cs +++ b/src/Uno.UI.RuntimeTests/Tests/Windows_UI_Xaml_Controls/Given_TimePicker.cs @@ -26,6 +26,27 @@ namespace Uno.UI.RuntimeTests.Tests.Windows_UI_Xaml_Controls [RunsOnUIThread] public class Given_TimePicker { +#if HAS_UNO + [TestMethod] + [RequiresFullWindow] + public async Task When_TimePickerFlyout_Placed_Outside_Window() + { + var btn = new Button + { + HorizontalAlignment = HorizontalAlignment.Right, + Content = "Open Flyout", + Flyout = new TimePickerFlyout() + }; + + await UITestHelper.Load(btn); + btn.ProgrammaticClick(); + await UITestHelper.WaitForIdle(); + + var presenter = (TimePickerFlyoutPresenter)VisualTreeHelper.GetOpenPopupsForXamlRoot(TestServices.WindowHelper.XamlRoot)[0].Child; + Assert.IsTrue(presenter.GetAbsoluteBoundsRect().IntersectWith(TestServices.WindowHelper.XamlRoot.VisualTree.VisibleBounds).Equals(presenter.GetAbsoluteBoundsRect())); + } +#endif + [TestMethod] public async Task When_MinuteIncrement_In_Range_Should_Be_Set_Properly() { From 4aee3bfd661daed5a61b4b7d900178fee01dae4f Mon Sep 17 00:00:00 2001 From: Ramez Ragaa Date: Tue, 24 Dec 2024 13:40:57 +0200 Subject: [PATCH 3/3] chore: fix PlacementArrangeOverride condition --- src/Uno.UI/UI/Xaml/Controls/Popup/PopupPanel.cs | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/Uno.UI/UI/Xaml/Controls/Popup/PopupPanel.cs b/src/Uno.UI/UI/Xaml/Controls/Popup/PopupPanel.cs index 0418977bc708..0c1d2e8118c7 100644 --- a/src/Uno.UI/UI/Xaml/Controls/Popup/PopupPanel.cs +++ b/src/Uno.UI/UI/Xaml/Controls/Popup/PopupPanel.cs @@ -165,11 +165,12 @@ protected override Size ArrangeOverride(Size finalSize) #endif ; - if (!isFlyoutManagedDatePicker && Popup.PlacementTarget is not null + if ((!isFlyoutManagedDatePicker #if __ANDROID__ || __IOS__ - || NativeAnchor is not null + || NativeAnchor is not null #endif - || !finalFrame.IntersectWith(GetVisibleBounds()).Equals(finalFrame) // if the finalFrame spills out of the window, always use PlacementArrangeOverride + || !finalFrame.IntersectWith(GetVisibleBounds()).Equals(finalFrame) // if the finalFrame spills out of the window, always use PlacementArrangeOverride + ) && Popup.PlacementTarget is not null ) { return PlacementArrangeOverride(Popup, finalSize);