@onekeyfe/react-native-pager-view 6.7.0-alpha.327 → 6.7.0-alpha.336

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,6 +1,7 @@
1
1
  #import <XCTest/XCTest.h>
2
2
  #import "RNCCollapsiblePagerViewComponentView.h"
3
3
  #import "RNCNativeScrollerComponentView.h"
4
+ #import <react/renderer/components/pagerview/Props.h>
4
5
  #import <react/renderer/mounting/MountingTransaction.h>
5
6
 
6
7
  using namespace facebook::react;
@@ -22,6 +23,10 @@ using namespace facebook::react;
22
23
  - (void)updateHeaderSettledStateForceBusy:(BOOL)forceBusy;
23
24
  - (void)preparePageForHorizontalTransitionAtIndex:(NSInteger)index;
24
25
  - (void)applyInsetsToScrollView:(UIScrollView *)scrollView pageIndex:(NSInteger)index restore:(BOOL)restore;
26
+ - (void)updateProps:(const Props::Shared &)props oldProps:(const Props::Shared &)oldProps;
27
+ - (void)mountChildComponentView:(UIView<RCTComponentViewProtocol> *)childComponentView index:(NSInteger)index;
28
+ - (CGFloat)effectiveTopOverlayHeight;
29
+ - (void)updateRefreshControlForScrollView:(UIScrollView *)scrollView;
25
30
  @end
26
31
 
27
32
  @interface RNCNativeScrollerComponentView (ScrollCommandTesting)
@@ -34,6 +39,125 @@ using namespace facebook::react;
34
39
 
35
40
  @implementation RNCCollapsiblePagerFirstFrameTests
36
41
 
42
+ - (void)testPendingLocalOverlayReservesManagedScrollerInsetBeforeSlotRebuild
43
+ {
44
+ RNCCollapsiblePagerViewComponentView *pager =
45
+ [[RNCCollapsiblePagerViewComponentView alloc] initWithFrame:CGRectMake(0, 0, 320, 844)];
46
+ UIWindow *window = [[UIWindow alloc] initWithFrame:pager.frame];
47
+ UIViewController *root = [UIViewController new];
48
+ window.rootViewController = root;
49
+ [root.view addSubview:pager];
50
+ window.hidden = NO;
51
+ [self addTeardownBlock:^{
52
+ [pager prepareForRecycle];
53
+ window.hidden = YES;
54
+ }];
55
+
56
+ auto baseline = std::make_shared<RNCCollapsiblePagerViewProps>();
57
+ baseline->nativeSmoothHeaderScrollEnabled = true;
58
+ baseline->headerHeight = 120;
59
+ baseline->stickyHeaderHeight = 44;
60
+ baseline->pageKeys = "[\"page-0\"]";
61
+ [pager updateProps:baseline oldProps:nullptr];
62
+
63
+ UIView *header = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 320, 120)];
64
+ UIView *sticky = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 320, 44)];
65
+ UIView *page = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 320, 844)];
66
+ RNCNativeScrollerComponentView *scroller = [RNCNativeScrollerComponentView new];
67
+ scroller.frame = page.bounds;
68
+ scroller.scrollView.frame = scroller.bounds;
69
+ scroller.scrollView.contentSize = CGSizeMake(320, 1500);
70
+ [page addSubview:scroller];
71
+ [pager mountChildComponentView:(id)header index:0];
72
+ [pager mountChildComponentView:(id)sticky index:1];
73
+ [pager mountChildComponentView:(id)page index:2];
74
+ [root.view layoutIfNeeded];
75
+ [pager layoutIfNeeded];
76
+ XCTestExpectation *settled = [self expectationWithDescription:@"Baseline slots and observer settled"];
77
+ dispatch_async(dispatch_get_main_queue(), ^{ [settled fulfill]; });
78
+ [self waitForExpectations:@[settled] timeout:1];
79
+ [pager attachScrollObserverForCurrentPage];
80
+ UIScrollView *ownedScroll = scroller.scrollView;
81
+ XCTAssertEqual([pager valueForKey:@"observedScrollView"], ownedScroll);
82
+ XCTAssertEqualWithAccuracy(ownedScroll.contentInset.top, 164, 0.01);
83
+ [scroller scrollTo:0 y:40 - ownedScroll.contentInset.top animated:NO];
84
+ [pager setValue:@40 forKey:@"headerOffset"];
85
+ CGFloat initialLogicalOffset = ownedScroll.contentOffset.y + ownedScroll.contentInset.top;
86
+ XCTAssertEqualWithAccuracy(initialLogicalOffset, 40, 0.01);
87
+
88
+ auto hard = std::make_shared<RNCCollapsiblePagerViewProps>();
89
+ hard->nativeSmoothHeaderScrollEnabled = true;
90
+ hard->headerHeight = 120;
91
+ hard->stickyHeaderHeight = 44;
92
+ hard->pageKeys = "[\"page-0\"]";
93
+ hard->topScrollEdgeEffect = RNCCollapsiblePagerViewTopScrollEdgeEffect::Hard;
94
+ hard->topOverlayHeight = 162;
95
+ [pager updateProps:hard oldProps:baseline];
96
+ XCTAssertNil([pager valueForKey:@"topOverlayView"]);
97
+ XCTAssertEqual([pager valueForKey:@"observedScrollView"], ownedScroll);
98
+ XCTAssertEqualWithAccuracy([pager effectiveTopOverlayHeight], 162, 0.01);
99
+ XCTAssertEqualWithAccuracy(ownedScroll.contentInset.top, 326, 0.01);
100
+ XCTAssertEqualWithAccuracy(ownedScroll.contentOffset.y + ownedScroll.contentInset.top,
101
+ initialLogicalOffset, 0.01);
102
+ [self finishMount:pager];
103
+ XCTAssertNil([pager valueForKey:@"topOverlayView"]);
104
+ XCTAssertTrue([[pager valueForKey:@"deferTopEdgeSlotRebuild"] boolValue]);
105
+
106
+ UIView *overlay = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 320, 162)];
107
+ [pager mountChildComponentView:(id)overlay index:2];
108
+ XCTAssertNil([pager valueForKey:@"topOverlayView"]);
109
+ [self finishMount:pager];
110
+ UIView *overlayHost = [pager valueForKey:@"topOverlayHostView"];
111
+ XCTAssertEqual([pager valueForKey:@"topOverlayView"], overlay);
112
+ XCTAssertEqual(overlay.superview, overlayHost);
113
+ XCTAssertEqual(overlay.window, window);
114
+ XCTAssertEqualWithAccuracy(ownedScroll.contentInset.top, 326, 0.01);
115
+ XCTAssertEqualWithAccuracy(ownedScroll.contentOffset.y + ownedScroll.contentInset.top,
116
+ initialLogicalOffset, 0.01);
117
+ XCTestExpectation *rebuilt = [self expectationWithDescription:@"Post-mount observer restored"];
118
+ dispatch_async(dispatch_get_main_queue(), ^{ [rebuilt fulfill]; });
119
+ [self waitForExpectations:@[rebuilt] timeout:1];
120
+ [pager attachScrollObserverForCurrentPage];
121
+ XCTAssertEqual([pager valueForKey:@"topOverlayView"], overlay);
122
+ XCTAssertEqual([pager valueForKey:@"observedScrollView"], ownedScroll);
123
+ XCTAssertEqualWithAccuracy(ownedScroll.contentInset.top, 326, 0.01);
124
+ XCTAssertEqualWithAccuracy(ownedScroll.contentOffset.y + ownedScroll.contentInset.top,
125
+ initialLogicalOffset, 0.01);
126
+
127
+ UIRefreshControl *control = [UIRefreshControl new];
128
+ ownedScroll.refreshControl = control;
129
+ [pager updateRefreshControlForScrollView:ownedScroll];
130
+ UIEdgeInsets refreshingInset = ownedScroll.contentInset;
131
+ refreshingInset.top += 60;
132
+ ownedScroll.contentInset = refreshingInset;
133
+ auto disabled = std::make_shared<RNCCollapsiblePagerViewProps>();
134
+ disabled->nativeSmoothHeaderScrollEnabled = true;
135
+ disabled->headerHeight = 120;
136
+ disabled->stickyHeaderHeight = 44;
137
+ disabled->pageKeys = "[\"page-0\"]";
138
+ disabled->topScrollEdgeEffect = RNCCollapsiblePagerViewTopScrollEdgeEffect::None;
139
+ disabled->topOverlayHeight = 0;
140
+ [pager updateProps:disabled oldProps:hard];
141
+ XCTAssertEqual(ownedScroll.refreshControl, control);
142
+ XCTAssertEqualWithAccuracy([pager effectiveTopOverlayHeight], 0, 0.01);
143
+ XCTAssertEqualWithAccuracy(ownedScroll.contentInset.top, 224, 0.01);
144
+ }
145
+
146
+ - (void)testPendingLocalOverlayHeightDoesNotOverrideExternalGeometry
147
+ {
148
+ RNCCollapsiblePagerViewComponentView *pager = [RNCCollapsiblePagerViewComponentView new];
149
+ auto props = std::make_shared<RNCCollapsiblePagerViewProps>();
150
+ props->topScrollEdgeEffect = RNCCollapsiblePagerViewTopScrollEdgeEffect::Hard;
151
+ props->topOverlayHeight = 162;
152
+ props->externalTopOverlayTag = 999;
153
+ [pager updateProps:props oldProps:nullptr];
154
+ XCTAssertNil([pager valueForKey:@"topOverlayView"]);
155
+ XCTAssertEqualWithAccuracy([pager effectiveTopOverlayHeight], 0, 0.01);
156
+ [pager setValue:@64 forKey:@"externalTopOverlayHeight"];
157
+ XCTAssertEqualWithAccuracy([pager effectiveTopOverlayHeight], 64, 0.01);
158
+ [pager prepareForRecycle];
159
+ }
160
+
37
161
  - (void)testHeaderSettledAtTopRequiresCurrentQuietOwnerAndCancelsDetachedTimer
38
162
  {
39
163
  RNCCollapsiblePagerViewComponentView *pager = [self pagerWithPageCount:1];
@@ -8,6 +8,7 @@ using namespace facebook::react;
8
8
 
9
9
  @interface RNCCollapsiblePagerViewComponentView (ScrollEdgeTesting)
10
10
  - (void)updateTopScrollEdgeForScrollView:(UIScrollView *)scrollView;
11
+ - (void)updateScrollEdgeContentMasks;
11
12
  @end
12
13
 
13
14
  @interface RNCCollapsiblePagerHitTestTests : XCTestCase
@@ -151,4 +152,163 @@ using namespace facebook::react;
151
152
  }
152
153
  }
153
154
 
155
+ - (void)testPinnedHardEdgeHidesOnlyTopSeparatorCoverUntilUnpinned
156
+ {
157
+ if (@available(iOS 26.0, *)) {
158
+ UIWindow *window = [[UIWindow alloc] initWithFrame:self.root.bounds];
159
+ [window addSubview:self.root];
160
+ [self addTeardownBlock:^{ window.hidden = YES; }];
161
+ window.hidden = NO;
162
+ UIScrollView *scrollView = [[UIScrollView alloc] initWithFrame:self.pager.bounds];
163
+ [self.pager addSubview:scrollView];
164
+ [self.pager setValue:@YES forKey:@"topScrollEdgeEnabled"];
165
+ [self.pager setValue:@(static_cast<NSInteger>(RNCCollapsiblePagerViewTopScrollEdgeEffect::Hard))
166
+ forKey:@"topScrollEdgeEffect"];
167
+ [self.pager setValue:@123 forKey:@"externalTopOverlayTag"];
168
+ [self.pager setValue:@64 forKey:@"externalTopOverlayHeight"];
169
+ [self.pager setValue:self.sticky forKey:@"stickyHeaderView"];
170
+ UIView *container = [self.pager valueForKey:@"containerView"];
171
+ container.frame = self.pager.bounds;
172
+ UIView *overlayHost = [self.pager valueForKey:@"topOverlayHostView"];
173
+ overlayHost.frame = CGRectMake(0, 0, 320, 64);
174
+ overlayHost.hidden = NO;
175
+ UIView *pinnedHost = [self.pager valueForKey:@"pinnedStickyHostView"];
176
+ pinnedHost.frame = CGRectMake(0, 64, 320, 44);
177
+ pinnedHost.hidden = NO;
178
+ [scrollView addSubview:pinnedHost];
179
+
180
+ [self.pager updateTopScrollEdgeForScrollView:scrollView];
181
+ UIScrollEdgeElementContainerInteraction *topInteraction =
182
+ [self.pager valueForKey:@"topEdgeInteraction"];
183
+ CALayer *topCover = [self.pager valueForKey:@"topEdgeSeparatorCover"];
184
+ XCTAssertNotNil(topInteraction);
185
+ XCTAssertNotNil(topCover);
186
+ XCTAssertFalse(topCover.hidden);
187
+ XCTAssertEqual(scrollView.topEdgeEffect.style, UIScrollEdgeEffectStyle.hardStyle);
188
+
189
+ [self.pager setValue:@YES forKey:@"stickyHeaderIsPinned"];
190
+ [self.pager updateTopScrollEdgeForScrollView:scrollView];
191
+ UIScrollEdgeElementContainerInteraction *stickyInteraction =
192
+ [self.pager valueForKey:@"stickyEdgeInteraction"];
193
+ CALayer *stickyCover = [self.pager valueForKey:@"stickyEdgeSeparatorCover"];
194
+ XCTAssertEqual([self.pager valueForKey:@"topEdgeInteraction"], topInteraction);
195
+ XCTAssertEqual(topInteraction.scrollView, scrollView);
196
+ XCTAssertEqual(stickyInteraction.scrollView, scrollView);
197
+ XCTAssertEqual([self.pager valueForKey:@"topEdgeSeparatorCover"], topCover);
198
+ XCTAssertTrue(topCover.hidden);
199
+ XCTAssertNotNil(stickyCover);
200
+ XCTAssertFalse(stickyCover.hidden);
201
+ XCTAssertEqual(scrollView.topEdgeEffect.style, UIScrollEdgeEffectStyle.hardStyle);
202
+
203
+ [self.pager setValue:@NO forKey:@"stickyHeaderIsPinned"];
204
+ [self.pager updateTopScrollEdgeForScrollView:scrollView];
205
+ XCTAssertEqual([self.pager valueForKey:@"topEdgeInteraction"], topInteraction);
206
+ XCTAssertEqual([self.pager valueForKey:@"topEdgeSeparatorCover"], topCover);
207
+ XCTAssertFalse(topCover.hidden);
208
+ XCTAssertEqual(scrollView.topEdgeEffect.style, UIScrollEdgeEffectStyle.hardStyle);
209
+ [self.root removeFromSuperview];
210
+ } else {
211
+ XCTSkip(@"Scroll-edge interactions require iOS 26 or newer");
212
+ }
213
+ }
214
+
215
+ - (void)testIOS27LocalHardThemeBackgroundTracksMaskedHeaderGeometry
216
+ {
217
+ if (@available(iOS 27.0, *)) {
218
+ UIWindowScene *scene = nil;
219
+ for (UIScene *connectedScene in UIApplication.sharedApplication.connectedScenes) {
220
+ if ([connectedScene isKindOfClass:UIWindowScene.class]) {
221
+ scene = (UIWindowScene *)connectedScene;
222
+ break;
223
+ }
224
+ }
225
+ XCTAssertNotNil(scene);
226
+ UIWindow *window = [[UIWindow alloc] initWithWindowScene:scene];
227
+ window.frame = self.root.bounds;
228
+ [window addSubview:self.root];
229
+ window.hidden = NO;
230
+ [self addTeardownBlock:^{ window.hidden = YES; }];
231
+ [self.pager layoutIfNeeded];
232
+ self.pager.backgroundColor = [UIColor colorWithWhite:0.2 alpha:1];
233
+ UIView *container = [self.pager valueForKey:@"containerView"];
234
+ container.frame = self.pager.bounds;
235
+ UIScrollView *scroll = [[UIScrollView alloc] initWithFrame:container.bounds];
236
+ scroll.contentInsetAdjustmentBehavior = UIScrollViewContentInsetAdjustmentNever;
237
+ scroll.alwaysBounceVertical = YES;
238
+ scroll.contentSize = CGSizeMake(320, 1200);
239
+ scroll.contentInset = UIEdgeInsetsMake(50 + 100 + 20, 0, 0, 0);
240
+ [container insertSubview:scroll atIndex:0];
241
+ UIView *sharedHost = [self.pager valueForKey:@"sharedHeaderHostView"];
242
+ for (UIView *child in sharedHost.subviews.copy) [child removeFromSuperview];
243
+ [scroll addSubview:sharedHost];
244
+ sharedHost.frame = CGRectMake(0, -120, 320, 120);
245
+ UIView *header = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 320, 100)];
246
+ [sharedHost addSubview:header];
247
+ [self.pager setValue:header forKey:@"headerView"];
248
+ UIView *overlayHost = [self.pager valueForKey:@"topOverlayHostView"];
249
+ overlayHost.frame = CGRectMake(0, 0, 320, 50);
250
+ overlayHost.hidden = NO;
251
+ UIView *overlay = [[UIView alloc] initWithFrame:overlayHost.bounds];
252
+ [overlayHost addSubview:overlay];
253
+ [self.pager setValue:overlay forKey:@"topOverlayView"];
254
+ [self.pager setValue:@50 forKey:@"topOverlayHeight"];
255
+ [self.pager setValue:@100 forKey:@"headerHeight"];
256
+ [self.pager setValue:@20 forKey:@"stickyHeaderHeight"];
257
+ [self.pager setValue:@YES forKey:@"nativeSmoothHeaderScrollEnabled"];
258
+ [self.pager setValue:@YES forKey:@"topScrollEdgeEnabled"];
259
+ [self.pager setValue:@(static_cast<NSInteger>(RNCCollapsiblePagerViewTopScrollEdgeEffect::Hard))
260
+ forKey:@"topScrollEdgeEffect"];
261
+ [self.pager setValue:scroll forKey:@"observedScrollView"];
262
+ [self.pager setValue:scroll forKey:@"sharedHeaderScrollView"];
263
+ scroll.contentOffset = CGPointMake(0, -170);
264
+ [self.pager updateTopScrollEdgeForScrollView:scroll];
265
+ CALayer *layer = [self.pager valueForKey:@"topOverlayThemeBackgroundLayer"];
266
+ XCTAssertNotNil(layer);
267
+ XCTAssertEqual(layer.superlayer, overlayHost.layer);
268
+ XCTAssertEqualWithAccuracy(layer.opacity, 1, 0.01);
269
+ XCTAssertEqual(scroll.topEdgeEffect.style, UIScrollEdgeEffectStyle.hardStyle);
270
+ XCTAssertEqual([self.pager valueForKey:@"topEdgeScrollView"], scroll);
271
+
272
+ scroll.contentOffset = CGPointMake(0, -120);
273
+ [self.pager updateScrollEdgeContentMasks];
274
+ XCTAssertEqualWithAccuracy(layer.opacity, 0.5, 0.01);
275
+ scroll.contentOffset = CGPointMake(0, -70);
276
+ [self.pager updateScrollEdgeContentMasks];
277
+ XCTAssertEqualWithAccuracy(layer.opacity, 0, 0.01);
278
+ scroll.contentOffset = CGPointMake(0, -210);
279
+ [self.pager updateScrollEdgeContentMasks];
280
+ XCTAssertEqualWithAccuracy(layer.opacity, 1, 0.01);
281
+
282
+ scroll.contentInset = UIEdgeInsetsMake(230, 0, 0, 0);
283
+ scroll.contentOffset = CGPointMake(0, -230);
284
+ [self.pager updateScrollEdgeContentMasks];
285
+ XCTAssertEqualWithAccuracy(layer.opacity, 1, 0.01);
286
+ self.pager.backgroundColor = UIColor.whiteColor;
287
+ [self.pager updateScrollEdgeContentMasks];
288
+ XCTAssertTrue(CGColorEqualToColor(layer.backgroundColor, UIColor.whiteColor.CGColor));
289
+
290
+ [self.pager updateTopScrollEdgeForScrollView:nil];
291
+ XCTAssertEqual([self.pager valueForKey:@"topOverlayThemeBackgroundLayer"], layer);
292
+ XCTAssertEqualWithAccuracy(layer.opacity, 1, 0.01);
293
+ [self.pager setValue:@YES forKey:@"topScrollEdgeEnabled"];
294
+ [self.pager updateTopScrollEdgeForScrollView:scroll];
295
+ [self.pager setValue:@123 forKey:@"externalTopOverlayTag"];
296
+ [self.pager updateScrollEdgeContentMasks];
297
+ XCTAssertNil([self.pager valueForKey:@"topOverlayThemeBackgroundLayer"]);
298
+ [self.pager setValue:@0 forKey:@"externalTopOverlayTag"];
299
+ [self.pager updateTopScrollEdgeForScrollView:scroll];
300
+ XCTAssertEqual(scroll.topEdgeEffect.style, UIScrollEdgeEffectStyle.hardStyle);
301
+ [self.pager setValue:@NO forKey:@"topScrollEdgeEnabled"];
302
+ [self.pager updateTopScrollEdgeForScrollView:scroll];
303
+ XCTAssertNil([self.pager valueForKey:@"topOverlayThemeBackgroundLayer"]);
304
+ [self.pager setValue:@YES forKey:@"topScrollEdgeEnabled"];
305
+ [self.pager updateTopScrollEdgeForScrollView:scroll];
306
+ XCTAssertNotNil([self.pager valueForKey:@"topOverlayThemeBackgroundLayer"]);
307
+ [self.pager prepareForRecycle];
308
+ XCTAssertNil([self.pager valueForKey:@"topOverlayThemeBackgroundLayer"]);
309
+ } else {
310
+ XCTSkip(@"The theme background applies only on iOS 27 or newer");
311
+ }
312
+ }
313
+
154
314
  @end
@@ -60,6 +60,56 @@
60
60
  XCTAssertEqualWithAccuracy(control.bounds.origin.x, 3, 0.001);
61
61
  }
62
62
 
63
+ - (void)testRefreshLayerWindowGeometryStartsBelowFixedOverlay
64
+ {
65
+ for (NSNumber *overlayHeight in @[@0, @162]) {
66
+ CGFloat fixedHeight = overlayHeight.doubleValue;
67
+ CGFloat baseInset = fixedHeight + 180 + 44;
68
+ UIWindow *window = [[UIWindow alloc] initWithFrame:CGRectMake(0, 0, 390, 844)];
69
+ UIViewController *root = [UIViewController new];
70
+ window.rootViewController = root;
71
+ UIScrollView *scroll = [[UIScrollView alloc] initWithFrame:window.bounds];
72
+ scroll.contentInsetAdjustmentBehavior = UIScrollViewContentInsetAdjustmentNever;
73
+ scroll.contentSize = CGSizeMake(390, 1500);
74
+ scroll.contentInset = UIEdgeInsetsMake(baseInset + 60, 0, 0, 0);
75
+ scroll.contentOffset = CGPointMake(0, -baseInset - 102);
76
+ [root.view addSubview:scroll];
77
+ UIView *overlay = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 390, fixedHeight)];
78
+ [root.view addSubview:overlay];
79
+ UIRefreshControl *control = [UIRefreshControl new];
80
+ scroll.refreshControl = control;
81
+ window.hidden = NO;
82
+ [root.view layoutIfNeeded];
83
+ [control layoutIfNeeded];
84
+ // Match the control's window position recorded during a real refresh drag.
85
+ control.frame = [scroll convertRect:CGRectMake(0, baseInset, 390, 60)
86
+ fromView:window];
87
+
88
+ RNCCollapsiblePagerViewComponentView *pager = [self pagerWithHeader:180];
89
+ [pager setValue:@(fixedHeight) forKey:@"topOverlayHeight"];
90
+ if (fixedHeight > 0) [pager setValue:overlay forKey:@"topOverlayView"];
91
+ [pager updateRefreshControlForScrollView:scroll];
92
+ [CATransaction flush];
93
+ CALayer *firstChild = control.layer.sublayers.firstObject;
94
+ XCTAssertNotNil(firstChild);
95
+ XCTAssertEqual(control.window, window);
96
+ CGRect overlayWindow = [overlay convertRect:overlay.bounds toView:window];
97
+ CGRect controlWindow = [control convertRect:control.bounds toView:window];
98
+ CGRect childWindow = [firstChild convertRect:firstChild.bounds toLayer:window.layer];
99
+ XCTAssertEqualWithAccuracy(CGRectGetMinY(controlWindow), baseInset, 0.01);
100
+ XCTAssertEqualWithAccuracy(CGRectGetMinY(childWindow),
101
+ CGRectGetMaxY(overlayWindow), 0.01);
102
+ XCTAssertEqualWithAccuracy(scroll.contentInset.top, baseInset + 60, 0.01);
103
+ [pager updateRefreshControlForScrollView:scroll];
104
+ XCTAssertEqualWithAccuracy(CGRectGetMinY(
105
+ [firstChild convertRect:firstChild.bounds toLayer:window.layer]),
106
+ CGRectGetMaxY(overlayWindow), 0.01);
107
+ [pager releaseRefreshControlForScrollView:scroll];
108
+ XCTAssertTrue(CATransform3DIsIdentity(control.layer.sublayerTransform));
109
+ window.hidden = YES;
110
+ }
111
+ }
112
+
63
113
  - (void)testUIKitSizeChangesAndRefreshCycleDoNotAccumulateOffset
64
114
  {
65
115
  RNCCollapsiblePagerViewComponentView *pager = [self pagerWithHeader:64];
@@ -23,7 +23,7 @@ const pageKey = (child, index) => {
23
23
  */
24
24
  export class CollapsiblePagerView extends React.PureComponent {
25
25
  state = {
26
- topOverlayHeight: 0,
26
+ topOverlayHeight: null,
27
27
  selectedPage: clampedPageIndex(this.props.initialPage ?? 0, React.Children.toArray(this.props.children).length),
28
28
  transientRetainedPages: []
29
29
  };
@@ -41,7 +41,14 @@ export class CollapsiblePagerView extends React.PureComponent {
41
41
  componentDidMount() {
42
42
  this.notifyMountedPagesChanged();
43
43
  }
44
- componentDidUpdate() {
44
+ componentDidUpdate(previousProps) {
45
+ const previousOverlayEnabled = previousProps.topOverlay != null && (previousProps.topScrollEdgeEffect === "hard" || previousProps.topScrollEdgeEffect === "soft");
46
+ const overlayEnabled = this.props.topOverlay != null && (this.props.topScrollEdgeEffect === "hard" || this.props.topScrollEdgeEffect === "soft");
47
+ if (previousOverlayEnabled && !overlayEnabled && this.state.topOverlayHeight !== null) {
48
+ this.setState({
49
+ topOverlayHeight: null
50
+ });
51
+ }
45
52
  const pageCount = this.pages().length;
46
53
  const selectedPage = clampedPageIndex(this.state.selectedPage, pageCount);
47
54
  if (selectedPage !== this.state.selectedPage) {
@@ -197,6 +204,7 @@ export class CollapsiblePagerView extends React.PureComponent {
197
204
  headerHeight,
198
205
  stickyHeaderHeight,
199
206
  topOverlay,
207
+ topOverlayHeightHint,
200
208
  externalTopOverlayTag,
201
209
  topScrollEdgeEffect,
202
210
  topOverlayColorScheme,
@@ -219,6 +227,7 @@ export class CollapsiblePagerView extends React.PureComponent {
219
227
  const supportsTopScrollEdge = Platform.OS === "ios" && parseInt(String(Platform.Version), 10) >= 26;
220
228
  const scrollEdgeEnabled = supportsTopScrollEdge && (topScrollEdgeEffect === "hard" || topScrollEdgeEffect === "soft");
221
229
  const hasTopOverlay = scrollEdgeEnabled && topOverlay != null;
230
+ const initialTopOverlayHeight = typeof topOverlayHeightHint === "number" && Number.isFinite(topOverlayHeightHint) ? Math.max(0, Math.ceil(topOverlayHeightHint)) : 0;
222
231
  const pageKeys = pages.map(pageKey);
223
232
  const retained = new Set(this.mountedPages(pages.length));
224
233
  const deducedLayoutDirection = !layoutDirection || layoutDirection === "locale" ? I18nManager.isRTL ? "rtl" : "ltr" : layoutDirection;
@@ -245,7 +254,7 @@ export class CollapsiblePagerView extends React.PureComponent {
245
254
  stickyHeaderHeight: Math.max(0, Math.round(stickyHeaderHeight)),
246
255
  topScrollEdgeEffect: scrollEdgeEnabled ? topScrollEdgeEffect : "none",
247
256
  topOverlayColorScheme: scrollEdgeEnabled ? topOverlayColorScheme : undefined,
248
- topOverlayHeight: hasTopOverlay ? this.state.topOverlayHeight : 0,
257
+ topOverlayHeight: hasTopOverlay ? this.state.topOverlayHeight ?? initialTopOverlayHeight : 0,
249
258
  externalTopOverlayTag: supportsTopScrollEdge && !hasTopOverlay ? externalTopOverlayTag ?? 0 : 0,
250
259
  nativeSmoothHeaderScrollEnabled: nativeSmoothHeaderScrollEnabled,
251
260
  pageKeys: JSON.stringify(pageKeys),