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

[Issue(IssueTracker.Github, 34917, "SwipeView.Open crashes with ArgumentException on second call", PlatformAffected.iOS)]
public class Issue34917 : TestContentPage
{
const string OpenButtonId = "OpenButton";
const string CloseButtonId = "CloseButton";
const string StatusLabelId = "StatusLabel";

protected override void Init()
{
Title = "Issue 34917";

var statusLabel = new Label
{
AutomationId = StatusLabelId,
Text = "Ready"
};

var swipeItem = new SwipeItem
{
BackgroundColor = Colors.Red,
Text = "Action"
};

var swipeView = new SwipeView
{
HeightRequest = 60,
WidthRequest = 300,
LeftItems = new SwipeItems { swipeItem },
Content = new Grid
{
BackgroundColor = Colors.Gray,
Children =
{
new Label
{
HorizontalOptions = LayoutOptions.Center,
VerticalOptions = LayoutOptions.Center,
Text = "Swipe content"
}
}
}
};

var openButton = new Button
{
AutomationId = OpenButtonId,
Text = "Open SwipeView"
};

var closeButton = new Button
{
AutomationId = CloseButtonId,
Text = "Close SwipeView"
};

int openCount = 0;

openButton.Clicked += (s, e) =>
{
try
{
openCount++;
swipeView.Open(OpenSwipeItem.LeftItems);
statusLabel.Text = $"Opened {openCount}";
}
catch (Exception ex)
{
statusLabel.Text = $"Error: {ex.GetType().Name}";
}
};

closeButton.Clicked += (s, e) =>
{
swipeView.Close();
statusLabel.Text = "Closed";
};

Content = new VerticalStackLayout
{
Spacing = 10,
Padding = 20,
Children = { openButton, closeButton, swipeView, statusLabel }
};
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
using NUnit.Framework;
using UITest.Appium;
using UITest.Core;

namespace Microsoft.Maui.TestCases.Tests.Issues
{
public class Issue34917 : _IssuesUITest
{
public Issue34917(TestDevice testDevice) : base(testDevice)
{
}

public override string Issue => "SwipeView.Open crashes with ArgumentException on second call";

[Test]
[Category(UITestCategories.SwipeView)]
public void SwipeViewOpenDoesNotCrashOnSecondCall()
{
App.WaitForElement("OpenButton");

// First open
App.Tap("OpenButton");
App.WaitForElement("StatusLabel");
var status1 = App.FindElement("StatusLabel").GetText();
Assert.That(status1, Is.EqualTo("Opened 1"), "First Open should succeed");

Comment on lines +23 to +26
// Close
App.Tap("CloseButton");

// Wait for close animation
Task.Delay(500).Wait();

// Second open - this used to crash with ArgumentException
App.Tap("OpenButton");
var status2 = App.FindElement("StatusLabel").GetText();
Assert.That(status2, Is.EqualTo("Opened 2"), "Second Open should succeed without crash");
Comment on lines +28 to +36
}
}
}
7 changes: 6 additions & 1 deletion src/Core/src/Platform/iOS/MauiSwipeView.cs
Original file line number Diff line number Diff line change
Expand Up @@ -294,6 +294,11 @@ void UpdateSwipeItems()
if (items == null || items.Count == 0)
return;

// Clean up any previous swipe items to prevent duplicate key exceptions
// when Open() is called again after _isOpen was reset without DisposeSwipeItems
_swipeItems.Clear();
_actionView?.RemoveFromSuperview();

_swipeItemsRect = new List<CGRect>();

double swipeItemsWidth;
Expand Down Expand Up @@ -802,7 +807,7 @@ void SwipeToThreshold(bool animated = true)
() =>
{
_swipeOffset = Math.Abs(GetSwipeThreshold());

// If the user swiped left or up, we need a negative offset to move content in the correct direction on the screen.
if (_swipeDirection == SwipeDirection.Left || _swipeDirection == SwipeDirection.Up)
_swipeOffset = -_swipeOffset;
Expand Down
Loading