diff --git a/src/SamplesApp/UITests.Shared/UITests.Shared.projitems b/src/SamplesApp/UITests.Shared/UITests.Shared.projitems
index df5919797d12..0890fa6560f4 100644
--- a/src/SamplesApp/UITests.Shared/UITests.Shared.projitems
+++ b/src/SamplesApp/UITests.Shared/UITests.Shared.projitems
@@ -3570,6 +3570,10 @@
Designer
MSBuild:Compile
+
+ Designer
+ MSBuild:Compile
+
Designer
MSBuild:Compile
@@ -9150,6 +9154,9 @@
NavigationView_TopNavigation.xaml
+
+ NavigationView_Tapped.xaml
+
ListView_DataContext_Propagation.xaml
diff --git a/src/SamplesApp/UITests.Shared/Windows_UI_Xaml_Controls/NavigationViewTests/NavigationView_Tapped.xaml b/src/SamplesApp/UITests.Shared/Windows_UI_Xaml_Controls/NavigationViewTests/NavigationView_Tapped.xaml
new file mode 100644
index 000000000000..51a1da3b66bd
--- /dev/null
+++ b/src/SamplesApp/UITests.Shared/Windows_UI_Xaml_Controls/NavigationViewTests/NavigationView_Tapped.xaml
@@ -0,0 +1,32 @@
+
+
+
+
+
+
+
+
+
+
+
+ Manual test for https://github.com/unoplatform/uno/issues/18024
+
+ Test steps:
+
+ 1. Press the hamburger menu on the left. A pane is supposed to open up (or expand).
+
+ 2. Press the "Item 1" item in the pane. A new "Item 1.1" item should appear.
+
+ 3. Press the "Item 1.1" item in the pane. The pane is supposed to collapse. (IMPORTANT) No popups or tooltips should be visible.
+
+
+
diff --git a/src/SamplesApp/UITests.Shared/Windows_UI_Xaml_Controls/NavigationViewTests/NavigationView_Tapped.xaml.cs b/src/SamplesApp/UITests.Shared/Windows_UI_Xaml_Controls/NavigationViewTests/NavigationView_Tapped.xaml.cs
new file mode 100644
index 000000000000..59216ef6cc8c
--- /dev/null
+++ b/src/SamplesApp/UITests.Shared/Windows_UI_Xaml_Controls/NavigationViewTests/NavigationView_Tapped.xaml.cs
@@ -0,0 +1,14 @@
+using Uno.UI.Samples.Controls;
+using Microsoft.UI.Xaml.Controls;
+
+namespace UITests.Shared.Windows_UI_Xaml_Controls.NavigationViewTests
+{
+ [SampleControlInfo("NavigationView", nameof(NavigationView_Tapped), IsManualTest = true)]
+ public sealed partial class NavigationView_Tapped : UserControl
+ {
+ public NavigationView_Tapped()
+ {
+ this.InitializeComponent();
+ }
+ }
+}
diff --git a/src/Uno.UI/UI/Xaml/Input/PointerRoutedEventArgs.Android.cs b/src/Uno.UI/UI/Xaml/Input/PointerRoutedEventArgs.Android.cs
index 044f130d36d9..08d86ad9a1ae 100644
--- a/src/Uno.UI/UI/Xaml/Input/PointerRoutedEventArgs.Android.cs
+++ b/src/Uno.UI/UI/Xaml/Input/PointerRoutedEventArgs.Android.cs
@@ -39,6 +39,12 @@ partial class PointerRoutedEventArgs
private const int _pointerIdsCount = (int)MotionEventActions.PointerIndexMask >> (int)MotionEventActions.PointerIndexShift; // 0xff
private const int _pointerIdsShift = 31 - (int)MotionEventActions.PointerIndexShift; // 23
+ // _lastNativeEvent.lastArgs is not necessary equal to LastPointerEvent. _lastNativeEvent.lastArgs is
+ // the last PointerRoutedEventArgs that was created as part of the native bubbling of _lastNativeEvent.nativeEvent.
+ // In other words, if a PointerRoutedEventArgs was created in managed (using the parameterless constructor),
+ // then _lastNativeEvent.lastArgs and LastPointerEvent will diverge.
+ private static (MotionEvent nativeEvent, PointerRoutedEventArgs lastArgs)? _lastNativeEvent;
+
private readonly MotionEvent _nativeEvent;
private readonly int _pointerIndex;
private readonly UIElement _receiver;
@@ -72,6 +78,18 @@ internal PointerRoutedEventArgs(MotionEvent nativeEvent, int pointerIndex, UIEle
KeyModifiers = keys;
OriginalSource = originalSource;
+ // On platforms with managed pointers, we reuse the same PointerRoutedEventArgs instance
+ // as we bubble up the event in the visual tree. On Android, the event bubbling is done
+ // natively and we create a corresponding (new) managed PointerRoutedEventArgs instance
+ // for each element up the tree. This means that parents won't see modifications in the
+ // PointerRoutedEventArgs instance that were done by the children. We have to detect
+ // this and copy the relevant fields ourselves.
+ if (_lastNativeEvent?.nativeEvent == nativeEvent)
+ {
+ GestureEventsAlreadyRaised = _lastNativeEvent.Value.lastArgs.GestureEventsAlreadyRaised;
+ }
+ _lastNativeEvent = (nativeEvent, this);
+
var inputManager = VisualTree.GetContentRootForElement(originalSource)?.InputManager;
if (inputManager is not null)
{