Skip to content
166 changes: 166 additions & 0 deletions src/Controls/tests/TestCases.HostApp/Issues/Issue30147.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,166 @@
#if IOS
using UIKit;
using CoreGraphics;
using Microsoft.Maui.Handlers;
#endif

namespace Maui.Controls.Sample.Issues;


[Issue(IssueTracker.Github, 30147, "MauiScrollView resets ContentOffset on first layout pass", PlatformAffected.iOS)]
public class Issue30147 : ContentPage
{
Issue30147CustomScrollView myScroll;
Label offsetLabel;

public Issue30147()
{
Title = "Issue 30147";

// Create the Label to display scroll offset
offsetLabel = new Label
{
Text = "0",
AutomationId = "OffsetLabel",
FontSize = 18
};

// Create Header with offset display
var headerLayout = new HorizontalStackLayout
{
Padding = new Thickness(20),
BackgroundColor = Colors.LightGray,
Children =
{
new Label
{
Text = "Offset: X = ",
FontSize = 18
},
offsetLabel
}
};

// Create the CustomScrollView
myScroll = new Issue30147CustomScrollView
{
Orientation = ScrollOrientation.Horizontal
};

// Add the event handler for offset changes
myScroll.OffsetChanged += (s, e) =>
{
offsetLabel.Text = e.X.ToString();
};

// Create the content for the scroll view
var scrollContent = new StackLayout();
scrollContent.Add(new BoxView { Color = Colors.Red, HeightRequest = 300, WidthRequest = 2000 });

myScroll.Content = scrollContent;

// Create the Grid layout
var grid = new Grid
{
RowDefinitions =
{
new RowDefinition { Height = GridLength.Auto },
new RowDefinition { Height = GridLength.Star }
}
};

grid.Add(headerLayout, 0, 0);
grid.Add(myScroll, 0, 1);

// Set the page content
Content = grid;
}
}

public class Issue30147ScrollOffsetChangedEventArgs : EventArgs
{
public double X { get; }
public double Y { get; }

public Issue30147ScrollOffsetChangedEventArgs(double x, double y)
{
X = x;
Y = y;
}
}

// Custom ScrollView class for tracking offset changes
public class Issue30147CustomScrollView : ScrollView
{
public event EventHandler<Issue30147ScrollOffsetChangedEventArgs> OffsetChanged;

// Raise the event from platform-specific code
internal void RaiseOffsetChanged(double x, double y)
{
OffsetChanged?.Invoke(this, new Issue30147ScrollOffsetChangedEventArgs(x, y));
}
}

#if IOS
public class Issue30147CustomMauiScrollView : Microsoft.Maui.Platform.MauiScrollView
{
CGPoint _previousOffset = new(-1, -1);
Issue30147CustomScrollView _virtualView;

public Issue30147CustomMauiScrollView(Issue30147CustomScrollView virtualView)
{
_virtualView = virtualView;
}

public override void SetContentOffset(CGPoint contentOffset, bool animated)
{
base.SetContentOffset(contentOffset, animated);
NotifyOffsetChanged(contentOffset);
}

public override CGPoint ContentOffset
{
get => base.ContentOffset;
set
{
base.ContentOffset = value;
NotifyOffsetChanged(value);
}
}

void NotifyOffsetChanged(CGPoint offset)
{
if (_previousOffset.X != offset.X || _previousOffset.Y != offset.Y)
{
_previousOffset = offset;
_virtualView?.RaiseOffsetChanged(offset.X, offset.Y);
}
}
}

public class Issue30147CustomScrollViewHandler : ScrollViewHandler
{
bool _initialOffsetApplied = false;

protected override UIScrollView CreatePlatformView()
{
if (VirtualView is Issue30147CustomScrollView customScrollView)
{
return new Issue30147CustomMauiScrollView(customScrollView);
}

return base.CreatePlatformView();
}

public override void PlatformArrange(Rect frame)
{
base.PlatformArrange(frame);

if (!_initialOffsetApplied)
{
PlatformView.ContentOffset = new CGPoint(500, 0);
_initialOffsetApplied = true;
}
}
}
#endif
3 changes: 3 additions & 0 deletions src/Controls/tests/TestCases.HostApp/MauiProgram.cs
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,9 @@ public static MauiApp CreateMauiApp()
handlers.AddHandler(typeof(UITestEditor), typeof(UITestEditorHandler));
handlers.AddHandler(typeof(UITestEntry), typeof(UITestEntryHandler));
handlers.AddHandler(typeof(UITestSearchBar), typeof(UITestSearchBarHandler));
#endif
#if IOS
handlers.AddHandler(typeof(Issue30147CustomScrollView), typeof(Issue30147CustomScrollViewHandler));
#endif
});

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
#if IOS // The issue is specific to iOS, so restricting other platforms
using NUnit.Framework;
using UITest.Appium;
using UITest.Core;

namespace Microsoft.Maui.TestCases.Tests.Issues;

public class Issue30147 : _IssuesUITest
{
public override string Issue => "MauiScrollView resets ContentOffset on first layout pass";

public Issue30147(TestDevice device)
: base(device)
{ }

[Test]
[Category(UITestCategories.ScrollView)]
public void VerifyScrollViewContentOffsetValue()
{
App.WaitForElement("OffsetLabel");
Assert.That(App.FindElement("OffsetLabel").GetText(), Is.EqualTo("500"));
}
}
#endif
Loading