Skip to content
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
126 changes: 126 additions & 0 deletions src/Controls/tests/TestCases.HostApp/Issues/Issue36154.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,126 @@
namespace Maui.Controls.Sample.Issues;

[Issue(IssueTracker.Github, 36154, "WebView inside SwipeView no longer responds to swipe gestures on Android", PlatformAffected.Android)]
public class Issue36154 : ContentPage
{
public Issue36154()
{
var directionLabel = new Label
{
AutomationId = "DirectionLabel",
Text = "Direction: — Offset: 0",
HorizontalOptions = LayoutOptions.Center,
Margin = new Thickness(4, 8),
FontSize = 13
};

var resultLabel = new Label
{
AutomationId = "ResultLabel",
Text = "Swipe result will appear here",
HorizontalOptions = LayoutOptions.Center,
Margin = new Thickness(4, 0, 4, 12),
FontSize = 13,
TextColor = Colors.Gray
};

var webView = new WebView
{
AutomationId = "TheWebView",
HorizontalOptions = LayoutOptions.Fill,
VerticalOptions = LayoutOptions.Fill,
// Long scrollable page so vertical scroll can be verified
Source = new HtmlWebViewSource
{
Html = """
<html>
<body style="font-family:sans-serif;padding:16px">
<h3>Issue 36154 – WebView scroll test</h3>
<p>Scroll down to verify WebView vertical scrolling works inside SwipeView.</p>
<p>Then swipe left/right to reveal swipe items.</p>
<p>At the top edge, swipe down to reveal TopItems.</p>
<p>At the bottom edge, swipe up to reveal BottomItems.</p>
""" + string.Concat(Enumerable.Range(1, 40).Select(i =>
$"<p>Line {i}: Lorem ipsum dolor sit amet consectetur adipiscing elit.</p>"))
+ "</body></html>"
}
};

var swipeView = new SwipeView
{
AutomationId = "TheSwipeView",
Threshold = 80,

LeftItems = new SwipeItems(new[]
{
new SwipeItem
{
AutomationId = "LeftItem",
Text = "◀ LEFT",
BackgroundColor = Colors.MediumSeaGreen,
Command = new Command(() =>
{
resultLabel.Text = "LEFT item invoked";
})
}
})
{ Mode = SwipeMode.Execute, SwipeBehaviorOnInvoked = SwipeBehaviorOnInvoked.Close },

RightItems = new SwipeItems(new[]
{
new SwipeItem
{
AutomationId = "RightItem",
Text = "RIGHT ▶",
BackgroundColor = Colors.CornflowerBlue,
Command = new Command(() =>
{
resultLabel.Text = "RIGHT invoked!";
})
}
})
{ Mode = SwipeMode.Execute, SwipeBehaviorOnInvoked = SwipeBehaviorOnInvoked.Close },

Content = webView
};

swipeView.SwipeStarted += (s, e) =>
{
directionLabel.Text = $"Direction: {e.SwipeDirection} Offset: 0";
};

swipeView.SwipeChanging += (s, e) =>
directionLabel.Text = $"Direction: {e.SwipeDirection} Offset: {e.Offset:F0}";

swipeView.SwipeEnded += (s, e) =>
{
directionLabel.Text = $"Direction: {e.SwipeDirection} Open: {e.IsOpen}";
};

Content = new Grid
{
RowDefinitions =
[
new RowDefinition { Height = GridLength.Auto },
new RowDefinition { Height = GridLength.Star },
new RowDefinition { Height = GridLength.Auto },
new RowDefinition { Height = GridLength.Auto },
],
Children =
{
new Label
{
Text = "Swipe on WebView · scroll mid-page · swipe at edges",
HorizontalOptions = LayoutOptions.Center,
Margin = new Thickness(8),
FontSize = 13,
FontAttributes = FontAttributes.Bold
}.Row(0),

Check failure on line 118 in src/Controls/tests/TestCases.HostApp/Issues/Issue36154.cs

View check run for this annotation

Azure Pipelines / maui-pr (Build .NET MAUI Build macOS (Debug))

src/Controls/tests/TestCases.HostApp/Issues/Issue36154.cs#L118

src/Controls/tests/TestCases.HostApp/Issues/Issue36154.cs(118,7): error CS1061: (NETCORE_ENGINEERING_TELEMETRY=Build) 'Label' does not contain a definition for 'Row' and no accessible extension method 'Row' accepting a first argument of type 'Label' could be found (are you missing a using directive or an assembly reference?)

Check failure on line 118 in src/Controls/tests/TestCases.HostApp/Issues/Issue36154.cs

View check run for this annotation

Azure Pipelines / maui-pr (Build .NET MAUI Build macOS (Release))

src/Controls/tests/TestCases.HostApp/Issues/Issue36154.cs#L118

src/Controls/tests/TestCases.HostApp/Issues/Issue36154.cs(118,7): error CS1061: (NETCORE_ENGINEERING_TELEMETRY=Build) 'Label' does not contain a definition for 'Row' and no accessible extension method 'Row' accepting a first argument of type 'Label' could be found (are you missing a using directive or an assembly reference?)

swipeView.Row(1),

Check failure on line 120 in src/Controls/tests/TestCases.HostApp/Issues/Issue36154.cs

View check run for this annotation

Azure Pipelines / maui-pr (Build .NET MAUI Build macOS (Debug))

src/Controls/tests/TestCases.HostApp/Issues/Issue36154.cs#L120

src/Controls/tests/TestCases.HostApp/Issues/Issue36154.cs(120,15): error CS1061: (NETCORE_ENGINEERING_TELEMETRY=Build) 'SwipeView' does not contain a definition for 'Row' and no accessible extension method 'Row' accepting a first argument of type 'SwipeView' could be found (are you missing a using directive or an assembly reference?)

Check failure on line 120 in src/Controls/tests/TestCases.HostApp/Issues/Issue36154.cs

View check run for this annotation

Azure Pipelines / maui-pr (Build .NET MAUI Build macOS (Release))

src/Controls/tests/TestCases.HostApp/Issues/Issue36154.cs#L120

src/Controls/tests/TestCases.HostApp/Issues/Issue36154.cs(120,15): error CS1061: (NETCORE_ENGINEERING_TELEMETRY=Build) 'SwipeView' does not contain a definition for 'Row' and no accessible extension method 'Row' accepting a first argument of type 'SwipeView' could be found (are you missing a using directive or an assembly reference?)
directionLabel.Row(2),

Check failure on line 121 in src/Controls/tests/TestCases.HostApp/Issues/Issue36154.cs

View check run for this annotation

Azure Pipelines / maui-pr (Build .NET MAUI Build macOS (Debug))

src/Controls/tests/TestCases.HostApp/Issues/Issue36154.cs#L121

src/Controls/tests/TestCases.HostApp/Issues/Issue36154.cs(121,20): error CS1061: (NETCORE_ENGINEERING_TELEMETRY=Build) 'Label' does not contain a definition for 'Row' and no accessible extension method 'Row' accepting a first argument of type 'Label' could be found (are you missing a using directive or an assembly reference?)

Check failure on line 121 in src/Controls/tests/TestCases.HostApp/Issues/Issue36154.cs

View check run for this annotation

Azure Pipelines / maui-pr (Build .NET MAUI Build macOS (Release))

src/Controls/tests/TestCases.HostApp/Issues/Issue36154.cs#L121

src/Controls/tests/TestCases.HostApp/Issues/Issue36154.cs(121,20): error CS1061: (NETCORE_ENGINEERING_TELEMETRY=Build) 'Label' does not contain a definition for 'Row' and no accessible extension method 'Row' accepting a first argument of type 'Label' could be found (are you missing a using directive or an assembly reference?)
resultLabel.Row(3)
}
};
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
using NUnit.Framework;
using UITest.Appium;
using UITest.Core;

namespace Microsoft.Maui.TestCases.Tests.Issues;

public class Issue36154 : _IssuesUITest
{
public Issue36154(TestDevice testDevice) : base(testDevice)
{
}

public override string Issue => "WebView inside SwipeView no longer responds to swipe gestures on Android";

// Verify that swiping left on the WebView reveals the Right swipe items
[Test]
[Category(UITestCategories.SwipeView)]
public void Issue36154SwipeViewShouldRevealItems()
{
var rect = App.WaitForElement("TheSwipeView").GetRect();
var centerX = rect.X + rect.Width / 2;
var centerY = rect.Y + rect.Height / 2;

// Swipe left (finger moves left) → reveals RightItems
App.DragCoordinates(centerX, centerY, centerX - 200, centerY);

Assert.That(App.WaitForElement("ResultLabel").GetText(), Is.EqualTo("RIGHT invoked!"));
}
}
16 changes: 16 additions & 0 deletions src/Core/src/Platform/Android/MauiSwipeView.cs
Original file line number Diff line number Diff line change
Expand Up @@ -133,6 +133,11 @@ bool ShouldInterceptScrollChildrenTouch(SwipeDirection swipeDirection)
if (_contentView is null || _initialPoint is null)
return false;

if (_contentView is AWebView contentWebView)
{
return ShouldInterceptWebViewTouch(contentWebView, swipeDirection);
}

var viewGroup = _contentView as ViewGroup;

if (viewGroup is not null)
Expand Down Expand Up @@ -166,6 +171,17 @@ bool ShouldInterceptScrollChildrenTouch(SwipeDirection swipeDirection)
return true;
}

// Determines whether the SwipeView should intercept touch events when the content is a WebView, based on the WebView's scroll position and the swipe direction.
static bool ShouldInterceptWebViewTouch(AWebView webView, SwipeDirection swipeDirection) =>
swipeDirection switch
{
SwipeDirection.Right => !webView.CanScrollHorizontally(-1), // at left edge
SwipeDirection.Left => !webView.CanScrollHorizontally(1), // at right edge
Comment thread
SubhikshaSf4851 marked this conversation as resolved.
SwipeDirection.Down => !webView.CanScrollVertically(-1), // at top
SwipeDirection.Up => !webView.CanScrollVertically(1), // at bottom
_ => true,
};

static bool ShouldInterceptScrollChildrenTouch(ViewGroup scrollView, bool isHorizontal)
{
AView? scrollViewContent = scrollView.GetChildAt(0);
Expand Down
12 changes: 11 additions & 1 deletion src/Core/src/Platform/Android/MauiWebView.cs
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ public class MauiWebView : WebView, IWebViewDelegate

readonly WebViewHandler _handler;
readonly Rect _clipRect;
bool _hasSwipeViewParent;
volatile bool _detachPending;

// True after the first layout pass where exactly one dimension is positive and the other is zero.
Expand Down Expand Up @@ -60,6 +61,8 @@ protected override void OnAttachedToWindow()
// Re-evaluate ClipBounds when re-parented (e.g., wrapped in WrapperView for shadow)
UpdateClipBounds(Width, Height);

_hasSwipeViewParent = ((View)this).GetParentOfType<MauiSwipeView>() is not null;

if (RefreshViewWebViewScrollCapture.IsInsideMauiSwipeRefreshLayout(this))
{
RefreshViewWebViewScrollCapture.Attach(this);
Expand Down Expand Up @@ -99,6 +102,7 @@ protected override void OnDetachedFromWindow()
}

base.OnDetachedFromWindow();
_hasSwipeViewParent = false;
}

void UpdateClipBounds(int width, int height)
Expand Down Expand Up @@ -151,7 +155,13 @@ public override bool OnTouchEvent(MotionEvent? e)
{
case MotionEventActions.Down:
case MotionEventActions.Move:
Parent?.RequestDisallowInterceptTouchEvent(true);
// Do not request disallow intercept when inside a SwipeView — that would set
// FLAG_DISALLOW_INTERCEPT on the SwipeView and prevent it from detecting
// swipe gestures
if (!_hasSwipeViewParent)
{
Parent?.RequestDisallowInterceptTouchEvent(true);
}
break;

case MotionEventActions.Up:
Expand Down
Loading