1+ #if IOS
2+ using UIKit ;
3+ using CoreGraphics ;
4+ using Microsoft . Maui . Handlers ;
5+ #endif
6+
7+ namespace Maui . Controls . Sample . Issues ;
8+
9+
10+ [ Issue ( IssueTracker . Github , 30147 , "MauiScrollView resets ContentOffset on first layout pass" , PlatformAffected . iOS ) ]
11+ public class Issue30147 : ContentPage
12+ {
13+ Issue30147CustomScrollView myScroll ;
14+ Label offsetLabel ;
15+
16+ public Issue30147 ( )
17+ {
18+ Title = "Issue 30147" ;
19+
20+ // Create the Label to display scroll offset
21+ offsetLabel = new Label
22+ {
23+ Text = "0" ,
24+ AutomationId = "OffsetLabel" ,
25+ FontSize = 18
26+ } ;
27+
28+ // Create Header with offset display
29+ var headerLayout = new HorizontalStackLayout
30+ {
31+ Padding = new Thickness ( 20 ) ,
32+ BackgroundColor = Colors . LightGray ,
33+ Children =
34+ {
35+ new Label
36+ {
37+ Text = "Offset: X = " ,
38+ FontSize = 18
39+ } ,
40+ offsetLabel
41+ }
42+ } ;
43+
44+ // Create the CustomScrollView
45+ myScroll = new Issue30147CustomScrollView
46+ {
47+ Orientation = ScrollOrientation . Horizontal
48+ } ;
49+
50+ // Add the event handler for offset changes
51+ myScroll . OffsetChanged += ( s , e ) =>
52+ {
53+ offsetLabel . Text = e . X . ToString ( ) ;
54+ } ;
55+
56+ // Create the content for the scroll view
57+ var scrollContent = new StackLayout ( ) ;
58+ scrollContent . Add ( new BoxView { Color = Colors . Red , HeightRequest = 300 , WidthRequest = 2000 } ) ;
59+
60+ myScroll . Content = scrollContent ;
61+
62+ // Create the Grid layout
63+ var grid = new Grid
64+ {
65+ RowDefinitions =
66+ {
67+ new RowDefinition { Height = GridLength . Auto } ,
68+ new RowDefinition { Height = GridLength . Star }
69+ }
70+ } ;
71+
72+ grid . Add ( headerLayout , 0 , 0 ) ;
73+ grid . Add ( myScroll , 0 , 1 ) ;
74+
75+ // Set the page content
76+ Content = grid ;
77+ }
78+ }
79+
80+ public class Issue30147ScrollOffsetChangedEventArgs : EventArgs
81+ {
82+ public double X { get ; }
83+ public double Y { get ; }
84+
85+ public Issue30147ScrollOffsetChangedEventArgs ( double x , double y )
86+ {
87+ X = x ;
88+ Y = y ;
89+ }
90+ }
91+
92+ // Custom ScrollView class for tracking offset changes
93+ public class Issue30147CustomScrollView : ScrollView
94+ {
95+ public event EventHandler < Issue30147ScrollOffsetChangedEventArgs > OffsetChanged ;
96+
97+ // Raise the event from platform-specific code
98+ internal void RaiseOffsetChanged ( double x , double y )
99+ {
100+ OffsetChanged ? . Invoke ( this , new Issue30147ScrollOffsetChangedEventArgs ( x , y ) ) ;
101+ }
102+ }
103+
104+ #if IOS
105+ public class Issue30147CustomMauiScrollView : Microsoft . Maui . Platform . MauiScrollView
106+ {
107+ CGPoint _previousOffset = new ( - 1 , - 1 ) ;
108+ Issue30147CustomScrollView _virtualView ;
109+
110+ public Issue30147CustomMauiScrollView ( Issue30147CustomScrollView virtualView )
111+ {
112+ _virtualView = virtualView ;
113+ }
114+
115+ public override void SetContentOffset ( CGPoint contentOffset , bool animated )
116+ {
117+ base . SetContentOffset ( contentOffset , animated ) ;
118+ NotifyOffsetChanged ( contentOffset ) ;
119+ }
120+
121+ public override CGPoint ContentOffset
122+ {
123+ get => base . ContentOffset ;
124+ set
125+ {
126+ base . ContentOffset = value ;
127+ NotifyOffsetChanged ( value ) ;
128+ }
129+ }
130+
131+ void NotifyOffsetChanged ( CGPoint offset )
132+ {
133+ if ( _previousOffset . X != offset . X || _previousOffset . Y != offset . Y )
134+ {
135+ _previousOffset = offset ;
136+ _virtualView ? . RaiseOffsetChanged ( offset . X , offset . Y ) ;
137+ }
138+ }
139+ }
140+
141+ public class Issue30147CustomScrollViewHandler : ScrollViewHandler
142+ {
143+ bool _initialOffsetApplied = false ;
144+
145+ protected override UIScrollView CreatePlatformView ( )
146+ {
147+ if ( VirtualView is Issue30147CustomScrollView customScrollView )
148+ {
149+ return new Issue30147CustomMauiScrollView ( customScrollView ) ;
150+ }
151+
152+ return base . CreatePlatformView ( ) ;
153+ }
154+
155+ public override void PlatformArrange ( Rect frame )
156+ {
157+ base . PlatformArrange ( frame ) ;
158+
159+ if ( ! _initialOffsetApplied )
160+ {
161+ PlatformView . ContentOffset = new CGPoint ( 500 , 0 ) ;
162+ _initialOffsetApplied = true ;
163+ }
164+ }
165+ }
166+ #endif
0 commit comments