@onekeyfe/react-native-pager-view 6.7.0-15 → 6.7.0-17
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.
- package/README.md +5 -0
- package/android/src/androidTest/AndroidManifest.xml +7 -0
- package/android/src/androidTest/java/com/reactnativepagerview/CollapsiblePagerTabReservationTest.kt +247 -0
- package/android/src/main/java/com/reactnativepagerview/CollapsiblePagerHost.kt +76 -21
- package/android/src/main/java/com/reactnativepagerview/CollapsiblePagerNativeHeaders.kt +72 -7
- package/android/src/main/java/com/reactnativepagerview/CollapsiblePagerViewManager.kt +27 -0
- package/android/src/main/java/com/reactnativepagerview/NativeScrollerView.kt +50 -6
- package/docs/SPEC.md +146 -1
- package/ios/RNCCollapsiblePagerViewComponentView.mm +355 -40
- package/ios/RNCNativeScrollerComponentView.h +2 -0
- package/ios/RNCNativeScrollerComponentView.mm +18 -0
- package/ios/tests/RNCCollapsiblePagerFirstFrameTests.mm +186 -0
- package/ios/tests/RNCCollapsiblePagerHitTestTests.mm +178 -0
- package/ios/tests/RNCCollapsiblePagerPressCancellationTests.mm +74 -9
- package/lib/module/CollapsiblePagerView.js +20 -4
- package/lib/module/CollapsiblePagerView.web.js +11 -2
- package/lib/module/CollapsiblePagerViewNativeComponent.ts +13 -0
- package/lib/typescript/src/CollapsiblePagerView.d.ts +6 -1
- package/lib/typescript/src/CollapsiblePagerView.web.d.ts +2 -0
- package/lib/typescript/src/CollapsiblePagerViewNativeComponent.d.ts +5 -0
- package/package.json +2 -2
- package/src/CollapsiblePagerView.tsx +68 -4
- package/src/CollapsiblePagerView.web.tsx +19 -2
- package/src/CollapsiblePagerViewNativeComponent.ts +13 -0
|
@@ -18,6 +18,7 @@
|
|
|
18
18
|
|
|
19
19
|
// OneKey patch: deduplicate structural mutation parents before scanning the page.
|
|
20
20
|
#include <unordered_set>
|
|
21
|
+
#include <cmath>
|
|
21
22
|
|
|
22
23
|
using namespace facebook::react;
|
|
23
24
|
|
|
@@ -157,6 +158,20 @@ static NSString *const RNCCollapsiblePagerNativeScrollerIDPrefix =
|
|
|
157
158
|
|
|
158
159
|
static const CFTimeInterval RNCCollapsiblePagerFallbackDebounceInterval = 0.5;
|
|
159
160
|
|
|
161
|
+
typedef NS_ENUM(NSInteger, RNCScrollCandidateTier) {
|
|
162
|
+
RNCScrollCandidateTierNone = 0,
|
|
163
|
+
RNCScrollCandidateTierGenericFallback = 1,
|
|
164
|
+
RNCScrollCandidateTierVerifiedNativeList = 2,
|
|
165
|
+
RNCScrollCandidateTierFabricScrollView = 3,
|
|
166
|
+
RNCScrollCandidateTierExplicitScroller = 4,
|
|
167
|
+
};
|
|
168
|
+
|
|
169
|
+
struct RNCScrollCandidateResolution {
|
|
170
|
+
UIScrollView *scrollView = nil;
|
|
171
|
+
RNCScrollCandidateTier tier = RNCScrollCandidateTierNone;
|
|
172
|
+
BOOL hasUnreadyScrollHost = NO;
|
|
173
|
+
};
|
|
174
|
+
|
|
160
175
|
// OneKey patch: native scroll views can survive a move or be reused for a new
|
|
161
176
|
// Fabric component. Keep weak identity until their page is attached again.
|
|
162
177
|
@interface RNCCollapsiblePagerReleasedScrollState : NSObject
|
|
@@ -368,7 +383,9 @@ static void RNCLogNativeTabScrollBoundary(NSString *owner,
|
|
|
368
383
|
@property (nonatomic, copy) RNCCollapsiblePagerNativeTabPressHandler onTabPress;
|
|
369
384
|
- (void)updateItemsJSON:(NSString *)itemsJSON;
|
|
370
385
|
- (void)updateStyleWithHeight:(CGFloat)height
|
|
386
|
+
variant:(NSString *)variant
|
|
371
387
|
contentPaddingHorizontal:(CGFloat)contentPaddingHorizontal
|
|
388
|
+
contentPaddingVertical:(CGFloat)contentPaddingVertical
|
|
372
389
|
itemSpacing:(CGFloat)itemSpacing
|
|
373
390
|
fontSize:(CGFloat)fontSize
|
|
374
391
|
fontFamily:(NSString *)fontFamily
|
|
@@ -385,12 +402,15 @@ static void RNCLogNativeTabScrollBoundary(NSString *owner,
|
|
|
385
402
|
|
|
386
403
|
@implementation RNCCollapsiblePagerNativeTabBarView {
|
|
387
404
|
RNCCollapsiblePagerHorizontalScrollView *_scrollView;
|
|
405
|
+
UIView *_trackView;
|
|
388
406
|
UIView *_indicatorView;
|
|
389
407
|
NSArray<NSDictionary *> *_items;
|
|
390
408
|
NSMutableArray<UIButton *> *_buttons;
|
|
391
409
|
NSMutableArray<NSValue *> *_indicatorFrames;
|
|
392
410
|
CGFloat _barHeight;
|
|
393
411
|
CGFloat _contentPaddingHorizontal;
|
|
412
|
+
CGFloat _contentPaddingVertical;
|
|
413
|
+
BOOL _segmented;
|
|
394
414
|
CGFloat _itemSpacing;
|
|
395
415
|
CGFloat _fontSize;
|
|
396
416
|
NSString *_fontFamily;
|
|
@@ -413,6 +433,8 @@ static void RNCLogNativeTabScrollBoundary(NSString *owner,
|
|
|
413
433
|
_indicatorFrames = [NSMutableArray new];
|
|
414
434
|
_barHeight = 44;
|
|
415
435
|
_contentPaddingHorizontal = 20;
|
|
436
|
+
_contentPaddingVertical = 0;
|
|
437
|
+
_segmented = NO;
|
|
416
438
|
_itemSpacing = 8;
|
|
417
439
|
_fontSize = 16;
|
|
418
440
|
_activeTextColor = UIColor.labelColor;
|
|
@@ -434,6 +456,10 @@ static void RNCLogNativeTabScrollBoundary(NSString *owner,
|
|
|
434
456
|
_scrollView.delegate = self;
|
|
435
457
|
[self addSubview:_scrollView];
|
|
436
458
|
|
|
459
|
+
_trackView = [UIView new];
|
|
460
|
+
_trackView.userInteractionEnabled = NO;
|
|
461
|
+
[_scrollView addSubview:_trackView];
|
|
462
|
+
|
|
437
463
|
_indicatorView = [UIView new];
|
|
438
464
|
_indicatorView.userInteractionEnabled = NO;
|
|
439
465
|
[_scrollView addSubview:_indicatorView];
|
|
@@ -488,7 +514,9 @@ static void RNCLogNativeTabScrollBoundary(NSString *owner,
|
|
|
488
514
|
}
|
|
489
515
|
|
|
490
516
|
- (void)updateStyleWithHeight:(CGFloat)height
|
|
517
|
+
variant:(NSString *)variant
|
|
491
518
|
contentPaddingHorizontal:(CGFloat)contentPaddingHorizontal
|
|
519
|
+
contentPaddingVertical:(CGFloat)contentPaddingVertical
|
|
492
520
|
itemSpacing:(CGFloat)itemSpacing
|
|
493
521
|
fontSize:(CGFloat)fontSize
|
|
494
522
|
fontFamily:(NSString *)fontFamily
|
|
@@ -500,19 +528,26 @@ static void RNCLogNativeTabScrollBoundary(NSString *owner,
|
|
|
500
528
|
indicatorBottom:(CGFloat)indicatorBottom
|
|
501
529
|
{
|
|
502
530
|
_barHeight = MAX(1, height);
|
|
531
|
+
BOOL wasSegmented = _segmented;
|
|
532
|
+
_segmented = [variant isEqualToString:@"segmented"];
|
|
503
533
|
_contentPaddingHorizontal = MAX(0, contentPaddingHorizontal);
|
|
534
|
+
_contentPaddingVertical = MAX(0, contentPaddingVertical);
|
|
504
535
|
_itemSpacing = MAX(0, itemSpacing);
|
|
505
536
|
_fontSize = MAX(1, fontSize);
|
|
506
537
|
_fontFamily = [fontFamily copy];
|
|
507
|
-
self.backgroundColor = backgroundColor ?: UIColor.clearColor;
|
|
538
|
+
self.backgroundColor = _segmented ? UIColor.clearColor : (backgroundColor ?: UIColor.clearColor);
|
|
508
539
|
_scrollView.backgroundColor = self.backgroundColor;
|
|
540
|
+
_scrollView.scrollEnabled = !_segmented;
|
|
541
|
+
if (_segmented && !wasSegmented) [_scrollView setContentOffset:CGPointZero animated:NO];
|
|
542
|
+
_trackView.hidden = !_segmented;
|
|
543
|
+
_trackView.backgroundColor = backgroundColor ?: UIColor.clearColor;
|
|
509
544
|
_activeTextColor = activeTextColor ?: UIColor.labelColor;
|
|
510
545
|
_inactiveTextColor = inactiveTextColor ?: UIColor.secondaryLabelColor;
|
|
511
546
|
_indicatorColor = indicatorColor ?: _activeTextColor;
|
|
512
547
|
_indicatorHeight = MAX(0, indicatorHeight);
|
|
513
548
|
_indicatorBottom = MAX(0, indicatorBottom);
|
|
514
549
|
_indicatorView.backgroundColor = _indicatorColor;
|
|
515
|
-
_indicatorView.layer.cornerRadius = _indicatorHeight / 2;
|
|
550
|
+
_indicatorView.layer.cornerRadius = _segmented ? 0 : _indicatorHeight / 2;
|
|
516
551
|
for (UIButton *button in _buttons) button.titleLabel.font = self.tabFont;
|
|
517
552
|
[self setNeedsLayout];
|
|
518
553
|
}
|
|
@@ -571,6 +606,33 @@ static void RNCLogNativeTabScrollBoundary(NSString *owner,
|
|
|
571
606
|
{
|
|
572
607
|
[super layoutSubviews];
|
|
573
608
|
_scrollView.frame = self.bounds;
|
|
609
|
+
if (_segmented) {
|
|
610
|
+
CGFloat width = CGRectGetWidth(self.bounds);
|
|
611
|
+
CGFloat height = CGRectGetHeight(self.bounds);
|
|
612
|
+
CGFloat insetX = MIN(_contentPaddingHorizontal, width / 2);
|
|
613
|
+
CGFloat insetY = MIN(_contentPaddingVertical, height / 2);
|
|
614
|
+
CGRect trackFrame = CGRectMake(insetX, insetY,
|
|
615
|
+
MAX(0, width - 2 * insetX), MAX(0, height - 2 * insetY));
|
|
616
|
+
_trackView.frame = trackFrame;
|
|
617
|
+
_trackView.layer.cornerRadius = CGRectGetHeight(trackFrame) / 2;
|
|
618
|
+
_scrollView.contentSize = self.bounds.size;
|
|
619
|
+
[_indicatorFrames removeAllObjects];
|
|
620
|
+
NSUInteger count = _buttons.count;
|
|
621
|
+
[_buttons enumerateObjectsUsingBlock:^(UIButton *button, NSUInteger index, BOOL *stop) {
|
|
622
|
+
CGFloat first = CGRectGetMinX(trackFrame) + CGRectGetWidth(trackFrame) * index / count;
|
|
623
|
+
CGFloat last = CGRectGetMinX(trackFrame) + CGRectGetWidth(trackFrame) * (index + 1) / count;
|
|
624
|
+
CGFloat x = self->_leftToRight ? first : CGRectGetMaxX(trackFrame) - (last - CGRectGetMinX(trackFrame));
|
|
625
|
+
CGFloat end = self->_leftToRight ? last : CGRectGetMaxX(trackFrame) - (first - CGRectGetMinX(trackFrame));
|
|
626
|
+
button.frame = CGRectMake(x, CGRectGetMinY(trackFrame), MAX(0, end - x), CGRectGetHeight(trackFrame));
|
|
627
|
+
CGRect thumbFrame = CGRectMake(x + 2, CGRectGetMinY(trackFrame) + 2,
|
|
628
|
+
MAX(0, CGRectGetWidth(button.frame) - 4), MAX(0, CGRectGetHeight(trackFrame) - 4));
|
|
629
|
+
[self->_indicatorFrames addObject:[NSValue valueWithCGRect:thumbFrame]];
|
|
630
|
+
}];
|
|
631
|
+
_indicatorView.layer.cornerRadius = MAX(0, CGRectGetHeight(trackFrame) - 4) / 2;
|
|
632
|
+
[self updatePresentation];
|
|
633
|
+
return;
|
|
634
|
+
}
|
|
635
|
+
_trackView.frame = CGRectZero;
|
|
574
636
|
UIFont *font = self.tabFont;
|
|
575
637
|
NSMutableArray<NSNumber *> *widths = [NSMutableArray arrayWithCapacity:_buttons.count];
|
|
576
638
|
CGFloat itemsWidth = 0;
|
|
@@ -634,10 +696,10 @@ static void RNCLogNativeTabScrollBoundary(NSString *owner,
|
|
|
634
696
|
CGRectGetMinX(fromFrame) + (CGRectGetMinX(toFrame) - CGRectGetMinX(fromFrame)) * fraction,
|
|
635
697
|
CGRectGetMinY(fromFrame),
|
|
636
698
|
CGRectGetWidth(fromFrame) + (CGRectGetWidth(toFrame) - CGRectGetWidth(fromFrame)) * fraction,
|
|
637
|
-
_indicatorHeight
|
|
699
|
+
_segmented ? CGRectGetHeight(fromFrame) : _indicatorHeight
|
|
638
700
|
);
|
|
639
701
|
_indicatorView.frame = indicatorFrame;
|
|
640
|
-
_indicatorView.hidden =
|
|
702
|
+
_indicatorView.hidden = CGRectGetHeight(indicatorFrame) <= 0;
|
|
641
703
|
|
|
642
704
|
NSInteger selectedIndex = (NSInteger)round(progress);
|
|
643
705
|
[_buttons enumerateObjectsUsingBlock:^(UIButton *button, NSUInteger index, BOOL *stop) {
|
|
@@ -654,7 +716,7 @@ static void RNCLogNativeTabScrollBoundary(NSString *owner,
|
|
|
654
716
|
: UIAccessibilityTraitButton;
|
|
655
717
|
}];
|
|
656
718
|
|
|
657
|
-
if (_shouldCenterSelectedItem && !_scrollView.tracking && !_scrollView.dragging &&
|
|
719
|
+
if (_shouldCenterSelectedItem && !_segmented && !_scrollView.tracking && !_scrollView.dragging &&
|
|
658
720
|
!_scrollView.decelerating && CGRectGetWidth(_scrollView.bounds) > 0) {
|
|
659
721
|
CGFloat maximumOffset = MAX(0, _scrollView.contentSize.width - CGRectGetWidth(_scrollView.bounds));
|
|
660
722
|
CGFloat desiredOffset = RNCClamp(
|
|
@@ -1471,13 +1533,17 @@ static void RNCLogNativeTabScrollBoundary(NSString *owner,
|
|
|
1471
1533
|
- (void)liftSharedHeadersForPagerTransition:(NSString *)reason;
|
|
1472
1534
|
- (void)restoreSharedHeadersToContainer;
|
|
1473
1535
|
- (void)layoutSharedHeaders;
|
|
1536
|
+
- (void)bringReservedStickyControlToFront;
|
|
1474
1537
|
- (void)restorePinnedStickyHeader;
|
|
1475
1538
|
- (void)updatePinnedStickyHeader;
|
|
1476
1539
|
- (UIScrollView *)currentVerticalScrollViewForParentPager;
|
|
1477
1540
|
- (UIScrollView *)verticalScrollViewForPageAtIndex:(NSInteger)pageIndex;
|
|
1541
|
+
- (RNCScrollCandidateResolution)resolveScrollCandidateForPageAtIndex:(NSInteger)pageIndex;
|
|
1542
|
+
- (RNCScrollCandidateResolution)resolveScrollCandidateInView:(UIView *)view;
|
|
1478
1543
|
- (UIScrollView *)findExplicitNativeScrollerInView:(UIView *)view;
|
|
1479
1544
|
- (UIScrollView *)findFabricScrollViewInView:(UIView *)view;
|
|
1480
1545
|
- (UIScrollView *)findVerticalScrollViewInView:(UIView *)view;
|
|
1546
|
+
- (void)scheduleCoalescedScrollReconcile;
|
|
1481
1547
|
- (void)scheduleScrollObserverRetryForCurrentPage;
|
|
1482
1548
|
- (void)preparePageForHorizontalTransitionAtIndex:(NSInteger)pageIndex;
|
|
1483
1549
|
- (void)updateSharedHeaderPressCancellationGesture;
|
|
@@ -1558,6 +1624,7 @@ static void RNCLogNativeTabScrollBoundary(NSString *owner,
|
|
|
1558
1624
|
NSUInteger _pendingTopInsetReboundGeneration;
|
|
1559
1625
|
NSTimer *_topInsetReboundTimer;
|
|
1560
1626
|
CGFloat _nativeTabBarHeight;
|
|
1627
|
+
CGFloat _nativeTabBarTrailingReservedWidth;
|
|
1561
1628
|
CGFloat _nativeSubHeaderHeight;
|
|
1562
1629
|
CGFloat _headerOffset;
|
|
1563
1630
|
BOOL _scrollEnabled;
|
|
@@ -1644,6 +1711,8 @@ static void RNCLogNativeTabScrollBoundary(NSString *owner,
|
|
|
1644
1711
|
RNCCollapsiblePagerOuterPagerPanGestureRecognizer *_sharedHeaderOuterPagerGesture;
|
|
1645
1712
|
RNCCollapsiblePagerVerticalPagerGuardGestureRecognizer *_verticalPagerGesture;
|
|
1646
1713
|
BOOL _observingContentOffset;
|
|
1714
|
+
BOOL _awaitingScrollOwnerForCurrentPage;
|
|
1715
|
+
BOOL _scrollReconcileScheduled;
|
|
1647
1716
|
BOOL _scrollResolveRetryScheduled;
|
|
1648
1717
|
CFTimeInterval _pendingFallbackScrollViewDetectedAt;
|
|
1649
1718
|
NSInteger _scrollResolveRetryPageIndex;
|
|
@@ -1675,6 +1744,8 @@ static void RNCLogNativeTabScrollBoundary(NSString *owner,
|
|
|
1675
1744
|
_displayBodyOverrides = [NSMutableDictionary new];
|
|
1676
1745
|
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(nativeListScrollCommandAccepted:)
|
|
1677
1746
|
name:@"OneKeyNativeListScrollCommandAccepted" object:nil];
|
|
1747
|
+
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(nativeScrollViewDidBecomeReadyNotification:)
|
|
1748
|
+
name:@"OneKeyNativeScrollViewDidBecomeReady" object:nil];
|
|
1678
1749
|
_pendingPageRestoreKeys = [NSMutableSet new];
|
|
1679
1750
|
_releasedPageScrollStates = [NSMutableDictionary new];
|
|
1680
1751
|
_mountingRemovedScrollViews = [NSHashTable weakObjectsHashTable];
|
|
@@ -2332,6 +2403,7 @@ static void RNCLogNativeTabScrollBoundary(NSString *owner,
|
|
|
2332
2403
|
[self updateTopScrollEdgeForScrollView:nil];
|
|
2333
2404
|
[self cancelHeaderSettledCheck];
|
|
2334
2405
|
[[NSNotificationCenter defaultCenter] removeObserver:self name:@"OneKeyNativeListScrollCommandAccepted" object:nil];
|
|
2406
|
+
[[NSNotificationCenter defaultCenter] removeObserver:self name:@"OneKeyNativeScrollViewDidBecomeReady" object:nil];
|
|
2335
2407
|
for (UIScrollView *scrollView in _originalInsets.keyEnumerator) {
|
|
2336
2408
|
[self updateNativeScrollerViewport:scrollView stickyHeight:0];
|
|
2337
2409
|
}
|
|
@@ -2479,6 +2551,7 @@ static void RNCLogNativeTabScrollBoundary(NSString *owner,
|
|
|
2479
2551
|
}
|
|
2480
2552
|
[_nativeTabBarView updateAncestorGesturePrecedence];
|
|
2481
2553
|
[_nativeSubHeaderView updateAncestorGesturePrecedence];
|
|
2554
|
+
[self bringReservedStickyControlToFront];
|
|
2482
2555
|
}
|
|
2483
2556
|
|
|
2484
2557
|
- (void)restoreSharedHeadersToContainer
|
|
@@ -2584,10 +2657,11 @@ static void RNCLogNativeTabScrollBoundary(NSString *owner,
|
|
|
2584
2657
|
CGFloat nativeTabBarVisibleHeight = _nativeTabBarView.hidden
|
|
2585
2658
|
? 0
|
|
2586
2659
|
: MIN(_stickyHeaderHeight, _nativeTabBarHeight);
|
|
2660
|
+
CGFloat tabReservedWidth = MIN(width, MAX(0, _nativeTabBarTrailingReservedWidth));
|
|
2587
2661
|
_nativeTabBarView.frame = CGRectMake(
|
|
2588
|
-
0,
|
|
2662
|
+
self.isLtrLayout ? 0 : tabReservedWidth,
|
|
2589
2663
|
stickyChildY,
|
|
2590
|
-
width,
|
|
2664
|
+
width - tabReservedWidth,
|
|
2591
2665
|
nativeTabBarVisibleHeight
|
|
2592
2666
|
);
|
|
2593
2667
|
_nativeSubHeaderView.frame = CGRectMake(
|
|
@@ -2601,9 +2675,26 @@ static void RNCLogNativeTabScrollBoundary(NSString *owner,
|
|
|
2601
2675
|
);
|
|
2602
2676
|
_topOverlayHostView.frame = CGRectMake(0, 0, width, self.effectiveTopOverlayHeight);
|
|
2603
2677
|
_topOverlayView.frame = _topOverlayHostView.bounds;
|
|
2678
|
+
[self bringReservedStickyControlToFront];
|
|
2604
2679
|
[self applyHeaderOffset];
|
|
2605
2680
|
}
|
|
2606
2681
|
|
|
2682
|
+
- (void)bringReservedStickyControlToFront
|
|
2683
|
+
{
|
|
2684
|
+
if (_stickyHeaderView != nil &&
|
|
2685
|
+
_stickyHeaderView.superview == _nativeTabBarView.superview) {
|
|
2686
|
+
if (_nativeTabBarTrailingReservedWidth > 0) {
|
|
2687
|
+
[_stickyHeaderView.superview bringSubviewToFront:_stickyHeaderView];
|
|
2688
|
+
} else {
|
|
2689
|
+
[_nativeTabBarView.superview bringSubviewToFront:_nativeTabBarView];
|
|
2690
|
+
if (!_nativeSubHeaderView.hidden &&
|
|
2691
|
+
_nativeSubHeaderView.superview == _nativeTabBarView.superview) {
|
|
2692
|
+
[_nativeSubHeaderView.superview bringSubviewToFront:_nativeSubHeaderView];
|
|
2693
|
+
}
|
|
2694
|
+
}
|
|
2695
|
+
}
|
|
2696
|
+
}
|
|
2697
|
+
|
|
2607
2698
|
- (void)updatePinnedStickyHeader
|
|
2608
2699
|
{
|
|
2609
2700
|
BOOL attachedToList = _nativeSmoothHeaderScrollEnabled &&
|
|
@@ -2650,8 +2741,10 @@ static void RNCLogNativeTabScrollBoundary(NSString *owner,
|
|
|
2650
2741
|
CGFloat childY = shouldPin ? 0 : _headerHeight;
|
|
2651
2742
|
CGFloat width = CGRectGetWidth(self.bounds);
|
|
2652
2743
|
CGFloat tabHeight = _nativeTabBarView.hidden ? 0 : MIN(_stickyHeaderHeight, _nativeTabBarHeight);
|
|
2744
|
+
CGFloat tabReservedWidth = MIN(width, MAX(0, _nativeTabBarTrailingReservedWidth));
|
|
2653
2745
|
_stickyHeaderView.frame = CGRectMake(0, childY, width, _stickyHeaderHeight);
|
|
2654
|
-
_nativeTabBarView.frame = CGRectMake(0
|
|
2746
|
+
_nativeTabBarView.frame = CGRectMake(self.isLtrLayout ? 0 : tabReservedWidth,
|
|
2747
|
+
childY, width - tabReservedWidth, tabHeight);
|
|
2655
2748
|
_nativeSubHeaderView.frame = CGRectMake(0, childY + tabHeight, width,
|
|
2656
2749
|
MIN(MAX(0, _stickyHeaderHeight - tabHeight), _nativeSubHeaderHeight));
|
|
2657
2750
|
_pinnedStickyHostView.hidden = !shouldPin;
|
|
@@ -2671,6 +2764,7 @@ static void RNCLogNativeTabScrollBoundary(NSString *owner,
|
|
|
2671
2764
|
}
|
|
2672
2765
|
[_nativeTabBarView updateAncestorGesturePrecedence];
|
|
2673
2766
|
[_nativeSubHeaderView updateAncestorGesturePrecedence];
|
|
2767
|
+
[self bringReservedStickyControlToFront];
|
|
2674
2768
|
[self updateTopScrollEdgeForScrollView:_observedScrollView];
|
|
2675
2769
|
[self logHomeVisualGeometry:shouldPin ? @"pin" : @"unpin"
|
|
2676
2770
|
scrollView:_observedScrollView];
|
|
@@ -2874,6 +2968,23 @@ static void RNCLogNativeTabScrollBoundary(NSString *owner,
|
|
|
2874
2968
|
[self applyInsetsToScrollView:scrollView pageIndex:index restore:YES];
|
|
2875
2969
|
}
|
|
2876
2970
|
}
|
|
2971
|
+
UIView *page = _pageControllers[_currentIndex].view;
|
|
2972
|
+
if (_scrollResolveRetryAttempt >= 12 &&
|
|
2973
|
+
_releasedPageScrollStates[self.currentPageKey] != nil) {
|
|
2974
|
+
for (const auto &mutation : transaction.getMutations()) {
|
|
2975
|
+
if (mutation.type == ShadowViewMutation::Insert && mutation.parentTag > 0 &&
|
|
2976
|
+
[page viewWithTag:mutation.parentTag] != nil) {
|
|
2977
|
+
// A new current-page insertion starts a bounded recovery round after
|
|
2978
|
+
// the previous replacement search has scheduled its final retry.
|
|
2979
|
+
_scrollResolveRetryToken += 1;
|
|
2980
|
+
_scrollResolveRetryScheduled = NO;
|
|
2981
|
+
_scrollResolveRetryAttempt = 0;
|
|
2982
|
+
break;
|
|
2983
|
+
}
|
|
2984
|
+
}
|
|
2985
|
+
}
|
|
2986
|
+
|
|
2987
|
+
// Record recovery during transitions; ownership still waits for settlement.
|
|
2877
2988
|
if (_transitioning || _isPagerDragging) return;
|
|
2878
2989
|
|
|
2879
2990
|
// OneKey patch: a release must recover even when the changed parent is above
|
|
@@ -2882,7 +2993,6 @@ static void RNCLogNativeTabScrollBoundary(NSString *owner,
|
|
|
2882
2993
|
[self attachScrollObserverForCurrentPage];
|
|
2883
2994
|
return;
|
|
2884
2995
|
}
|
|
2885
|
-
UIView *page = _pageControllers[_currentIndex].view;
|
|
2886
2996
|
BOOL headerIsAttached = [_sharedHeaderHostView isDescendantOfView:self];
|
|
2887
2997
|
BOOL currentListIsAttached = _observedScrollView != nil &&
|
|
2888
2998
|
[_observedScrollView isDescendantOfView:page] && headerIsAttached;
|
|
@@ -3050,18 +3160,14 @@ static void RNCLogNativeTabScrollBoundary(NSString *owner,
|
|
|
3050
3160
|
if (_stickyHeaderView != nil) [_sharedHeaderHostView bringSubviewToFront:_stickyHeaderView];
|
|
3051
3161
|
if (!_nativeTabBarView.hidden) [_sharedHeaderHostView bringSubviewToFront:_nativeTabBarView];
|
|
3052
3162
|
if (!_nativeSubHeaderView.hidden) [_sharedHeaderHostView bringSubviewToFront:_nativeSubHeaderView];
|
|
3163
|
+
[self bringReservedStickyControlToFront];
|
|
3053
3164
|
[_containerView bringSubviewToFront:_sharedHeaderHostView];
|
|
3054
3165
|
if (_stickyHeaderIsPinned) {
|
|
3055
3166
|
[_pinnedStickyHostView.superview bringSubviewToFront:_pinnedStickyHostView];
|
|
3056
3167
|
}
|
|
3057
3168
|
if (self.hasFixedTopOverlay) [_containerView bringSubviewToFront:_topOverlayHostView];
|
|
3058
3169
|
[self setNeedsLayout];
|
|
3059
|
-
|
|
3060
|
-
if (!self->_isBeingRecycled) {
|
|
3061
|
-
[self prepareAdjacentPageInsets];
|
|
3062
|
-
[self attachScrollObserverForCurrentPage];
|
|
3063
|
-
}
|
|
3064
|
-
});
|
|
3170
|
+
[self scheduleCoalescedScrollReconcile];
|
|
3065
3171
|
}
|
|
3066
3172
|
|
|
3067
3173
|
- (void)layoutSubviews
|
|
@@ -3138,12 +3244,7 @@ static void RNCLogNativeTabScrollBoundary(NSString *owner,
|
|
|
3138
3244
|
[self updateScrollEdgeContentMasks];
|
|
3139
3245
|
[self updateHeaderSettledStateForceBusy:NO];
|
|
3140
3246
|
[self logHomeVisualGeometry:@"layout" scrollView:_observedScrollView];
|
|
3141
|
-
|
|
3142
|
-
if (!self->_isBeingRecycled) {
|
|
3143
|
-
[self prepareAdjacentPageInsets];
|
|
3144
|
-
[self attachScrollObserverForCurrentPage];
|
|
3145
|
-
}
|
|
3146
|
-
});
|
|
3247
|
+
[self scheduleCoalescedScrollReconcile];
|
|
3147
3248
|
}
|
|
3148
3249
|
|
|
3149
3250
|
- (void)prepareForRecycle
|
|
@@ -3161,6 +3262,8 @@ static void RNCLogNativeTabScrollBoundary(NSString *owner,
|
|
|
3161
3262
|
_generation++;
|
|
3162
3263
|
[_mountingRemovedScrollViews removeAllObjects];
|
|
3163
3264
|
_needsScrollObserverReattachAfterMount = NO;
|
|
3265
|
+
_awaitingScrollOwnerForCurrentPage = NO;
|
|
3266
|
+
_scrollReconcileScheduled = NO;
|
|
3164
3267
|
[_releasedPageScrollStates removeAllObjects];
|
|
3165
3268
|
[self detachSharedHeaderPressCancellationGesture];
|
|
3166
3269
|
[self detachScrollObserver];
|
|
@@ -3262,6 +3365,7 @@ static void RNCLogNativeTabScrollBoundary(NSString *owner,
|
|
|
3262
3365
|
_homeVisualLastLayoutLog = 0;
|
|
3263
3366
|
_homeVisualLastGeometrySignature = nil;
|
|
3264
3367
|
_nativeTabBarHeight = 44;
|
|
3368
|
+
_nativeTabBarTrailingReservedWidth = 0;
|
|
3265
3369
|
_nativeSubHeaderHeight = 74;
|
|
3266
3370
|
_headerOffset = 0;
|
|
3267
3371
|
_currentLogicalOffset = 0;
|
|
@@ -3343,6 +3447,13 @@ static void RNCLogNativeTabScrollBoundary(NSString *owner,
|
|
|
3343
3447
|
_layoutDirection = RCTNSStringFromString(toString(newViewProps.layoutDirection));
|
|
3344
3448
|
[_nativeTabBarView setLeftToRight:self.isLtrLayout];
|
|
3345
3449
|
[_nativeSubHeaderView setLeftToRight:self.isLtrLayout];
|
|
3450
|
+
[self setNeedsLayout];
|
|
3451
|
+
}
|
|
3452
|
+
if (_needsPropsReapply ||
|
|
3453
|
+
oldViewProps.nativeTabBarTrailingReservedWidth != newViewProps.nativeTabBarTrailingReservedWidth) {
|
|
3454
|
+
double reserved = newViewProps.nativeTabBarTrailingReservedWidth;
|
|
3455
|
+
_nativeTabBarTrailingReservedWidth = std::isfinite(reserved) && reserved >= 0 ? reserved : 0;
|
|
3456
|
+
[self setNeedsLayout];
|
|
3346
3457
|
}
|
|
3347
3458
|
BOOL insetsChanged = NO;
|
|
3348
3459
|
if (_needsPropsReapply || oldViewProps.headerHeight != newViewProps.headerHeight) {
|
|
@@ -3423,7 +3534,9 @@ static void RNCLogNativeTabScrollBoundary(NSString *owner,
|
|
|
3423
3534
|
}
|
|
3424
3535
|
if (_needsPropsReapply ||
|
|
3425
3536
|
oldViewProps.nativeTabBarHeight != newViewProps.nativeTabBarHeight ||
|
|
3537
|
+
oldViewProps.nativeTabBarVariant != newViewProps.nativeTabBarVariant ||
|
|
3426
3538
|
oldViewProps.nativeTabBarContentPaddingHorizontal != newViewProps.nativeTabBarContentPaddingHorizontal ||
|
|
3539
|
+
oldViewProps.nativeTabBarContentPaddingVertical != newViewProps.nativeTabBarContentPaddingVertical ||
|
|
3427
3540
|
oldViewProps.nativeTabBarItemSpacing != newViewProps.nativeTabBarItemSpacing ||
|
|
3428
3541
|
oldViewProps.nativeTabBarFontSize != newViewProps.nativeTabBarFontSize ||
|
|
3429
3542
|
oldViewProps.nativeTabBarFontFamily != newViewProps.nativeTabBarFontFamily ||
|
|
@@ -3440,7 +3553,9 @@ static void RNCLogNativeTabScrollBoundary(NSString *owner,
|
|
|
3440
3553
|
NSString *fontFamily = RCTNSStringFromString(newViewProps.nativeTabBarFontFamily);
|
|
3441
3554
|
[_nativeTabBarView
|
|
3442
3555
|
updateStyleWithHeight:_nativeTabBarHeight
|
|
3556
|
+
variant:RCTNSStringFromString(newViewProps.nativeTabBarVariant)
|
|
3443
3557
|
contentPaddingHorizontal:MAX(0, newViewProps.nativeTabBarContentPaddingHorizontal)
|
|
3558
|
+
contentPaddingVertical:MAX(0, newViewProps.nativeTabBarContentPaddingVertical)
|
|
3444
3559
|
itemSpacing:MAX(0, newViewProps.nativeTabBarItemSpacing)
|
|
3445
3560
|
fontSize:newViewProps.nativeTabBarFontSize > 0 ? newViewProps.nativeTabBarFontSize : 16
|
|
3446
3561
|
fontFamily:fontFamily
|
|
@@ -3474,6 +3589,7 @@ static void RNCLogNativeTabScrollBoundary(NSString *owner,
|
|
|
3474
3589
|
if (!_nativeSubHeaderView.hidden) {
|
|
3475
3590
|
[_nativeSubHeaderView.superview bringSubviewToFront:_nativeSubHeaderView];
|
|
3476
3591
|
}
|
|
3592
|
+
[self bringReservedStickyControlToFront];
|
|
3477
3593
|
[_sharedHeaderHostView.superview bringSubviewToFront:_sharedHeaderHostView];
|
|
3478
3594
|
if (_stickyHeaderIsPinned) {
|
|
3479
3595
|
[_pinnedStickyHostView.superview bringSubviewToFront:_pinnedStickyHostView];
|
|
@@ -3501,12 +3617,105 @@ static void RNCLogNativeTabScrollBoundary(NSString *owner,
|
|
|
3501
3617
|
|
|
3502
3618
|
- (UIScrollView *)verticalScrollViewForPageAtIndex:(NSInteger)pageIndex
|
|
3503
3619
|
{
|
|
3504
|
-
|
|
3505
|
-
|
|
3506
|
-
|
|
3507
|
-
|
|
3508
|
-
|
|
3509
|
-
|
|
3620
|
+
return [self resolveScrollCandidateForPageAtIndex:pageIndex].scrollView;
|
|
3621
|
+
}
|
|
3622
|
+
|
|
3623
|
+
- (RNCScrollCandidateResolution)resolveScrollCandidateForPageAtIndex:(NSInteger)pageIndex
|
|
3624
|
+
{
|
|
3625
|
+
if (pageIndex < 0 || pageIndex >= _pageControllers.count) return {};
|
|
3626
|
+
return [self resolveScrollCandidateInView:_pageControllers[pageIndex].view];
|
|
3627
|
+
}
|
|
3628
|
+
|
|
3629
|
+
// Single-pass tiered resolution replaces three separate subtree walks while
|
|
3630
|
+
// distinguishing genuinely static pages from pages with unready scroll hosts.
|
|
3631
|
+
- (RNCScrollCandidateResolution)resolveScrollCandidateInView:(UIView *)view
|
|
3632
|
+
{
|
|
3633
|
+
RNCScrollCandidateResolution resolution;
|
|
3634
|
+
if (view == nil || view == _sharedHeaderHostView) return resolution;
|
|
3635
|
+
if (view != self &&
|
|
3636
|
+
[view isKindOfClass:RNCCollapsiblePagerViewComponentView.class]) {
|
|
3637
|
+
UIScrollView *nested = [(RNCCollapsiblePagerViewComponentView *)view
|
|
3638
|
+
currentVerticalScrollViewForParentPager];
|
|
3639
|
+
if (nested != nil) {
|
|
3640
|
+
resolution.scrollView = nested;
|
|
3641
|
+
resolution.tier = RNCScrollCandidateTierExplicitScroller;
|
|
3642
|
+
} else {
|
|
3643
|
+
resolution.hasUnreadyScrollHost = YES;
|
|
3644
|
+
}
|
|
3645
|
+
return resolution;
|
|
3646
|
+
}
|
|
3647
|
+
|
|
3648
|
+
Class nativeListClass = NSClassFromString(@"HybridNativeListComponent");
|
|
3649
|
+
if (nativeListClass != Nil && [view isKindOfClass:nativeListClass]) {
|
|
3650
|
+
resolution.hasUnreadyScrollHost = YES;
|
|
3651
|
+
}
|
|
3652
|
+
|
|
3653
|
+
if ([view isKindOfClass:RNCNativeScrollerComponentView.class]) {
|
|
3654
|
+
UIScrollView *scrollView = ((RNCNativeScrollerComponentView *)view).scrollView;
|
|
3655
|
+
if (![_mountingRemovedScrollViews containsObject:scrollView]) {
|
|
3656
|
+
resolution.scrollView = scrollView;
|
|
3657
|
+
resolution.tier = RNCScrollCandidateTierExplicitScroller;
|
|
3658
|
+
return resolution;
|
|
3659
|
+
}
|
|
3660
|
+
} else if ([view isKindOfClass:RCTScrollViewComponentView.class]) {
|
|
3661
|
+
RCTScrollViewComponentView *componentView = (RCTScrollViewComponentView *)view;
|
|
3662
|
+
UIScrollView *scrollView = componentView.scrollView;
|
|
3663
|
+
if (![_mountingRemovedScrollViews containsObject:scrollView]) {
|
|
3664
|
+
if ([componentView.nativeId hasPrefix:RNCCollapsiblePagerNativeScrollerIDPrefix]) {
|
|
3665
|
+
resolution.scrollView = scrollView;
|
|
3666
|
+
resolution.tier = RNCScrollCandidateTierExplicitScroller;
|
|
3667
|
+
return resolution;
|
|
3668
|
+
}
|
|
3669
|
+
if (!scrollView.alwaysBounceHorizontal) {
|
|
3670
|
+
resolution.scrollView = scrollView;
|
|
3671
|
+
resolution.tier = RNCScrollCandidateTierFabricScrollView;
|
|
3672
|
+
}
|
|
3673
|
+
}
|
|
3674
|
+
} else if ([view isKindOfClass:UICollectionView.class]) {
|
|
3675
|
+
UICollectionView *collectionView = (UICollectionView *)view;
|
|
3676
|
+
if (![_mountingRemovedScrollViews containsObject:collectionView]) {
|
|
3677
|
+
UICollectionViewLayout *layout = collectionView.collectionViewLayout;
|
|
3678
|
+
BOOL isVerticalLayout = ![layout isKindOfClass:UICollectionViewFlowLayout.class] ||
|
|
3679
|
+
((UICollectionViewFlowLayout *)layout).scrollDirection == UICollectionViewScrollDirectionVertical;
|
|
3680
|
+
if (isVerticalLayout) {
|
|
3681
|
+
BOOL hasNativeListHost = RNCNativeListComponentForScrollView(collectionView) != nil;
|
|
3682
|
+
BOOL isMountedNativeList = hasNativeListHost && RNCIsMountedNativeListScrollView(collectionView);
|
|
3683
|
+
BOOL hasUsableBounds = CGRectGetWidth(collectionView.bounds) > 0 &&
|
|
3684
|
+
CGRectGetHeight(collectionView.bounds) > 0;
|
|
3685
|
+
if (hasNativeListHost && !isMountedNativeList) {
|
|
3686
|
+
resolution.hasUnreadyScrollHost = YES;
|
|
3687
|
+
} else if (!hasUsableBounds) {
|
|
3688
|
+
resolution.hasUnreadyScrollHost = YES;
|
|
3689
|
+
} else {
|
|
3690
|
+
resolution.scrollView = collectionView;
|
|
3691
|
+
resolution.tier = isMountedNativeList
|
|
3692
|
+
? RNCScrollCandidateTierVerifiedNativeList
|
|
3693
|
+
: RNCScrollCandidateTierGenericFallback;
|
|
3694
|
+
}
|
|
3695
|
+
}
|
|
3696
|
+
}
|
|
3697
|
+
} else if ([view isKindOfClass:UIScrollView.class]) {
|
|
3698
|
+
UIScrollView *scrollView = (UIScrollView *)view;
|
|
3699
|
+
if (![_mountingRemovedScrollViews containsObject:scrollView] &&
|
|
3700
|
+
!scrollView.alwaysBounceHorizontal &&
|
|
3701
|
+
scrollView.contentSize.width <= scrollView.bounds.size.width + 1) {
|
|
3702
|
+
resolution.scrollView = scrollView;
|
|
3703
|
+
resolution.tier = RNCScrollCandidateTierGenericFallback;
|
|
3704
|
+
}
|
|
3705
|
+
}
|
|
3706
|
+
|
|
3707
|
+
for (UIView *subview in view.subviews) {
|
|
3708
|
+
RNCScrollCandidateResolution child = [self resolveScrollCandidateInView:subview];
|
|
3709
|
+
resolution.hasUnreadyScrollHost |= child.hasUnreadyScrollHost;
|
|
3710
|
+
if (child.tier > resolution.tier) {
|
|
3711
|
+
resolution.scrollView = child.scrollView;
|
|
3712
|
+
resolution.tier = child.tier;
|
|
3713
|
+
if (resolution.tier == RNCScrollCandidateTierExplicitScroller) {
|
|
3714
|
+
return resolution;
|
|
3715
|
+
}
|
|
3716
|
+
}
|
|
3717
|
+
}
|
|
3718
|
+
return resolution;
|
|
3510
3719
|
}
|
|
3511
3720
|
|
|
3512
3721
|
- (UIScrollView *)findExplicitNativeScrollerInView:(UIView *)view
|
|
@@ -3602,6 +3811,19 @@ static void RNCLogNativeTabScrollBoundary(NSString *owner,
|
|
|
3602
3811
|
return nil;
|
|
3603
3812
|
}
|
|
3604
3813
|
|
|
3814
|
+
- (void)scheduleCoalescedScrollReconcile
|
|
3815
|
+
{
|
|
3816
|
+
if (_isBeingRecycled || _scrollReconcileScheduled) return;
|
|
3817
|
+
_scrollReconcileScheduled = YES;
|
|
3818
|
+
NSUInteger generation = _generation;
|
|
3819
|
+
dispatch_async(dispatch_get_main_queue(), ^{
|
|
3820
|
+
self->_scrollReconcileScheduled = NO;
|
|
3821
|
+
if (self->_isBeingRecycled || self->_generation != generation) return;
|
|
3822
|
+
[self prepareAdjacentPageInsets];
|
|
3823
|
+
[self attachScrollObserverForCurrentPage];
|
|
3824
|
+
});
|
|
3825
|
+
}
|
|
3826
|
+
|
|
3605
3827
|
- (void)scheduleScrollObserverRetryForCurrentPage
|
|
3606
3828
|
{
|
|
3607
3829
|
if (_scrollResolveRetryScheduled || _scrollResolveRetryAttempt >= 12 ||
|
|
@@ -3654,29 +3876,35 @@ static void RNCLogNativeTabScrollBoundary(NSString *owner,
|
|
|
3654
3876
|
_pendingFallbackScrollView = nil;
|
|
3655
3877
|
_pendingFallbackScrollViewDetectedAt = 0;
|
|
3656
3878
|
}
|
|
3657
|
-
|
|
3879
|
+
RNCScrollCandidateResolution resolution = [self resolveScrollCandidateForPageAtIndex:_currentIndex];
|
|
3880
|
+
UIScrollView *candidate = resolution.scrollView;
|
|
3658
3881
|
if (_nativeSmoothHeaderScrollEnabled && _currentIndex >= 0 && _currentIndex < _pageControllers.count) {
|
|
3659
3882
|
RNCGuardNestedHorizontalPans(_pageControllers[_currentIndex].view, _verticalPagerGesture);
|
|
3660
3883
|
}
|
|
3661
3884
|
if (candidate == nil) {
|
|
3662
3885
|
[self detachScrollObserver];
|
|
3663
3886
|
[self restoreSharedHeadersToContainer];
|
|
3664
|
-
|
|
3665
|
-
|
|
3666
|
-
|
|
3667
|
-
|
|
3887
|
+
_needsScrollObserverReattachAfterMount = NO;
|
|
3888
|
+
_pendingFallbackScrollView = nil;
|
|
3889
|
+
_pendingFallbackScrollViewDetectedAt = 0;
|
|
3890
|
+
_awaitingScrollOwnerForCurrentPage = YES;
|
|
3891
|
+
// Only schedule bounded retry when the page has an unready scroll host in
|
|
3892
|
+
// its subtree or a released scroll owner awaiting replacement. Static pages
|
|
3893
|
+
// without a scroll host do not spin retry timers, and late replacements on
|
|
3894
|
+
// any page also attach deterministically via readiness notifications.
|
|
3895
|
+
BOOL hasReleasedOwnerAwaitingReplacement = _releasedPageScrollStates[self.currentPageKey] != nil;
|
|
3896
|
+
if (resolution.hasUnreadyScrollHost || hasReleasedOwnerAwaitingReplacement) {
|
|
3897
|
+
[self scheduleScrollObserverRetryForCurrentPage];
|
|
3898
|
+
} else {
|
|
3668
3899
|
_scrollResolveRetryToken += 1;
|
|
3669
3900
|
_scrollResolveRetryScheduled = NO;
|
|
3670
3901
|
_scrollResolveRetryAttempt = 0;
|
|
3671
|
-
_pendingFallbackScrollView = nil;
|
|
3672
|
-
_pendingFallbackScrollViewDetectedAt = 0;
|
|
3673
|
-
} else {
|
|
3674
|
-
[self scheduleScrollObserverRetryForCurrentPage];
|
|
3675
3902
|
}
|
|
3676
3903
|
return;
|
|
3677
3904
|
}
|
|
3678
3905
|
if ([candidate isKindOfClass:UICollectionView.class] &&
|
|
3679
3906
|
candidate != _observedScrollView && !RNCIsMountedNativeListScrollView(candidate)) {
|
|
3907
|
+
_awaitingScrollOwnerForCurrentPage = YES;
|
|
3680
3908
|
if (_pendingFallbackScrollView != candidate) {
|
|
3681
3909
|
_pendingFallbackScrollView = candidate;
|
|
3682
3910
|
_pendingFallbackScrollViewDetectedAt = CACurrentMediaTime();
|
|
@@ -3688,6 +3916,7 @@ static void RNCLogNativeTabScrollBoundary(NSString *owner,
|
|
|
3688
3916
|
return;
|
|
3689
3917
|
}
|
|
3690
3918
|
}
|
|
3919
|
+
_awaitingScrollOwnerForCurrentPage = NO;
|
|
3691
3920
|
_scrollResolveRetryAttempt = 0;
|
|
3692
3921
|
_scrollResolveRetryPageIndex = _currentIndex;
|
|
3693
3922
|
_scrollResolveRetryToken += 1;
|
|
@@ -4438,8 +4667,9 @@ static void RNCLogNativeTabScrollBoundary(NSString *owner,
|
|
|
4438
4667
|
|
|
4439
4668
|
- (void)updateNativeScrollerViewport:(UIScrollView *)scrollView stickyHeight:(CGFloat)height
|
|
4440
4669
|
{
|
|
4441
|
-
|
|
4442
|
-
|
|
4670
|
+
id host = scrollView.superview;
|
|
4671
|
+
if ([host respondsToSelector:@selector(setPagerStickyHeight:forOwner:)]) {
|
|
4672
|
+
[host setPagerStickyHeight:height forOwner:self];
|
|
4443
4673
|
}
|
|
4444
4674
|
}
|
|
4445
4675
|
|
|
@@ -4511,6 +4741,66 @@ static void RNCLogNativeTabScrollBoundary(NSString *owner,
|
|
|
4511
4741
|
}
|
|
4512
4742
|
|
|
4513
4743
|
|
|
4744
|
+
- (void)nativeScrollViewDidBecomeReadyNotification:(NSNotification *)notification
|
|
4745
|
+
{
|
|
4746
|
+
if ([notification.object isKindOfClass:UIScrollView.class]) {
|
|
4747
|
+
[self nativeScrollViewDidBecomeReady:(UIScrollView *)notification.object];
|
|
4748
|
+
}
|
|
4749
|
+
}
|
|
4750
|
+
|
|
4751
|
+
- (void)nativeScrollViewDidBecomeReady:(UIScrollView *)scrollView
|
|
4752
|
+
{
|
|
4753
|
+
if (_isBeingRecycled || self.window == nil || scrollView == nil ||
|
|
4754
|
+
[_mountingRemovedScrollViews containsObject:scrollView]) return;
|
|
4755
|
+
for (UIView *ancestor = scrollView.superview;
|
|
4756
|
+
ancestor != nil && ancestor != self;
|
|
4757
|
+
ancestor = ancestor.superview) {
|
|
4758
|
+
if ([ancestor isKindOfClass:RNCCollapsiblePagerViewComponentView.class]) {
|
|
4759
|
+
RNCCollapsiblePagerViewComponentView *nestedPager =
|
|
4760
|
+
(RNCCollapsiblePagerViewComponentView *)ancestor;
|
|
4761
|
+
if ([nestedPager currentVerticalScrollViewForParentPager] != scrollView) return;
|
|
4762
|
+
break;
|
|
4763
|
+
}
|
|
4764
|
+
}
|
|
4765
|
+
NSInteger pageIndex = NSNotFound;
|
|
4766
|
+
for (NSInteger index = 0; index < _pageControllers.count; index++) {
|
|
4767
|
+
if ([scrollView isDescendantOfView:_pageControllers[index].view]) {
|
|
4768
|
+
pageIndex = index;
|
|
4769
|
+
break;
|
|
4770
|
+
}
|
|
4771
|
+
}
|
|
4772
|
+
if (pageIndex == NSNotFound) return;
|
|
4773
|
+
|
|
4774
|
+
NSString *pageKey = [self pageKeyForIndex:pageIndex];
|
|
4775
|
+
BOOL hasReleasedStateForPage = _releasedPageScrollStates[pageKey] != nil;
|
|
4776
|
+
BOOL currentPageNeedsOwner = pageIndex == _currentIndex &&
|
|
4777
|
+
(_awaitingScrollOwnerForCurrentPage || _needsScrollObserverReattachAfterMount ||
|
|
4778
|
+
hasReleasedStateForPage ||
|
|
4779
|
+
(_observedScrollView != nil &&
|
|
4780
|
+
[_observedScrollView isKindOfClass:UICollectionView.class] &&
|
|
4781
|
+
!RNCIsMountedNativeListScrollView(_observedScrollView) &&
|
|
4782
|
+
_observedScrollView != scrollView));
|
|
4783
|
+
|
|
4784
|
+
if (!hasReleasedStateForPage && !currentPageNeedsOwner &&
|
|
4785
|
+
!_needsScrollObserverReattachAfterMount) return;
|
|
4786
|
+
|
|
4787
|
+
if (_nativeSmoothHeaderScrollEnabled) {
|
|
4788
|
+
NSInteger first = MAX(0, _currentIndex - 1);
|
|
4789
|
+
NSInteger last = MIN((NSInteger)_pageControllers.count - 1, _currentIndex + 1);
|
|
4790
|
+
BOOL isOwnedScroller = [scrollView.superview isKindOfClass:RNCNativeScrollerComponentView.class] &&
|
|
4791
|
+
((RNCNativeScrollerComponentView *)scrollView.superview).scrollView == scrollView;
|
|
4792
|
+
if ((pageIndex >= first && pageIndex <= last || pageIndex == _destinationIndex) &&
|
|
4793
|
+
(RNCIsMountedNativeListScrollView(scrollView) || isOwnedScroller) &&
|
|
4794
|
+
[_originalInsets objectForKey:scrollView] == nil) {
|
|
4795
|
+
[self applyInsetsToScrollView:scrollView pageIndex:pageIndex restore:YES];
|
|
4796
|
+
}
|
|
4797
|
+
}
|
|
4798
|
+
|
|
4799
|
+
if (currentPageNeedsOwner && !_transitioning && !_isPagerDragging) {
|
|
4800
|
+
[self attachScrollObserverForCurrentPage];
|
|
4801
|
+
}
|
|
4802
|
+
}
|
|
4803
|
+
|
|
4514
4804
|
- (void)nativeScroller:(RNCNativeScrollerComponentView *)scroller
|
|
4515
4805
|
callerInsetChangedFrom:(UIEdgeInsets)previous to:(UIEdgeInsets)next
|
|
4516
4806
|
{
|
|
@@ -5233,6 +5523,13 @@ static void RNCLogNativeTabScrollBoundary(NSString *owner,
|
|
|
5233
5523
|
{
|
|
5234
5524
|
UIScrollView *scrollView = _pagerTopScrollView;
|
|
5235
5525
|
if (_dispatchingPagerTop || ![self matchesPagerTop:scrollView]) return;
|
|
5526
|
+
CGFloat clampedTarget = MIN(MAX(_pagerTopLogicalTarget, 0), _headerHeight);
|
|
5527
|
+
if (clampedTarget != _pagerTopLogicalTarget) {
|
|
5528
|
+
_pagerTopLogicalTarget = clampedTarget;
|
|
5529
|
+
CGFloat physicalTarget = RNCLimitRestoredScrollOffset(clampedTarget - scrollView.contentInset.top,
|
|
5530
|
+
scrollView.contentSize.height, scrollView.bounds.size.height, scrollView.contentInset.top, scrollView.contentInset.bottom);
|
|
5531
|
+
[scrollView setContentOffset:CGPointMake(scrollView.contentOffset.x, physicalTarget) animated:NO];
|
|
5532
|
+
}
|
|
5236
5533
|
CGFloat logical = scrollView.contentOffset.y + scrollView.contentInset.top;
|
|
5237
5534
|
if (fabs(logical - _pagerTopLogicalTarget) > 0.5) return;
|
|
5238
5535
|
_pageOffsets[_pagerTopPageKey] = @(_nativeSmoothHeaderScrollEnabled ? 0 : _pagerTopLogicalTarget);
|
|
@@ -5244,11 +5541,29 @@ static void RNCLogNativeTabScrollBoundary(NSString *owner,
|
|
|
5244
5541
|
}
|
|
5245
5542
|
|
|
5246
5543
|
- (void)scrollToTop:(NSInteger)target animated:(BOOL)animated
|
|
5544
|
+
{
|
|
5545
|
+
if (target != 0 && target != 1) return;
|
|
5546
|
+
[self scrollHeaderToOffset:(target == 1 ? _headerHeight : 0) animated:animated];
|
|
5547
|
+
}
|
|
5548
|
+
|
|
5549
|
+
- (void)scrollHeaderBy:(double)delta
|
|
5550
|
+
{
|
|
5551
|
+
if (!std::isfinite(delta)) return;
|
|
5552
|
+
[self scrollHeaderToOffset:MIN(MAX(_headerOffset + delta, 0), _headerHeight) animated:NO];
|
|
5553
|
+
}
|
|
5554
|
+
|
|
5555
|
+
- (void)scrollHeaderToOffset:(double)offset
|
|
5556
|
+
{
|
|
5557
|
+
if (!std::isfinite(offset)) return;
|
|
5558
|
+
[self scrollHeaderToOffset:MIN(MAX(offset, 0), _headerHeight) animated:NO];
|
|
5559
|
+
}
|
|
5560
|
+
|
|
5561
|
+
- (void)scrollHeaderToOffset:(CGFloat)logicalTarget animated:(BOOL)animated
|
|
5247
5562
|
{
|
|
5248
5563
|
[self cancelTopInsetReboundCheck];
|
|
5249
5564
|
UIScrollView *scrollView = _observedScrollView;
|
|
5250
5565
|
NSString *key = _observedPageKey;
|
|
5251
|
-
if (
|
|
5566
|
+
if (_isBeingRecycled || _transitioning || _isPagerDragging ||
|
|
5252
5567
|
_transitionPageOffsets != nil || _syntheticPageRestore || scrollView == nil || scrollView.window == nil ||
|
|
5253
5568
|
key == nil || ![key isEqualToString:self.currentPageKey] || _observedPageIndex != _currentIndex ||
|
|
5254
5569
|
_observedPageGeneration != _generation || self.window == nil) return;
|
|
@@ -5264,7 +5579,7 @@ static void RNCLogNativeTabScrollBoundary(NSString *owner,
|
|
|
5264
5579
|
[_alignedBodyKeys removeObject:key];
|
|
5265
5580
|
[_suspendedBodyKeys removeObject:key];
|
|
5266
5581
|
[_displayBodyOverrides removeObjectForKey:key];
|
|
5267
|
-
|
|
5582
|
+
logicalTarget = MIN(MAX(logicalTarget, 0), _headerHeight);
|
|
5268
5583
|
_pageOffsets[key] = @(_nativeSmoothHeaderScrollEnabled ? 0 : logicalTarget);
|
|
5269
5584
|
_pagerTopScrollView = scrollView;
|
|
5270
5585
|
_pagerTopPageKey = [key copy];
|