@onekeyfe/react-native-pager-view 3.0.171 → 3.0.173

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.
@@ -1437,9 +1437,6 @@ static void RNCLogNativeTabScrollBoundary(NSString *owner,
1437
1437
  @end
1438
1438
 
1439
1439
  @implementation RNCCollapsiblePagerViewComponentView {
1440
- #if DEBUG
1441
- NSUInteger _offsetDiagSequence;
1442
- #endif
1443
1440
  UIView *_containerView;
1444
1441
  RNCCollapsiblePagerSharedHeaderView *_sharedHeaderHostView;
1445
1442
  UIPageViewController *_pageViewController;
@@ -1494,18 +1491,6 @@ static void RNCLogNativeTabScrollBoundary(NSString *owner,
1494
1491
  BOOL _needsScrollObserverReattachAfterMount;
1495
1492
  NSHashTable<UIScrollView *> *_mountingRemovedScrollViews;
1496
1493
  __weak UIScrollView *_observedScrollView;
1497
- NSString *_observedPageKey;
1498
- NSInteger _observedPageIndex;
1499
- NSUInteger _observedPageGeneration;
1500
- NSDictionary<NSString *, NSNumber *> *_transitionPageOffsets;
1501
- NSMutableIndexSet *_transitionCompensatedPages;
1502
- #if DEBUG
1503
- NSInteger _transitionDiagBucket;
1504
- #endif
1505
- NSInteger _transitionSourceIndex;
1506
- BOOL _syntheticPageRestore;
1507
- BOOL _finishingPageStateTransition;
1508
- NSMutableSet<NSString *> *_pendingPageRestoreKeys;
1509
1494
  __weak UIScrollView *_sharedHeaderScrollView;
1510
1495
  __weak UIScrollView *_pendingFallbackScrollView;
1511
1496
  __weak UIView *_sharedHeaderPressCancellationGestureHost;
@@ -1540,7 +1525,6 @@ static void RNCLogNativeTabScrollBoundary(NSString *owner,
1540
1525
  _logicalChildren = [NSMutableArray new];
1541
1526
  _pageControllers = [NSMutableArray new];
1542
1527
  _pageOffsets = [NSMutableDictionary new];
1543
- _pendingPageRestoreKeys = [NSMutableSet new];
1544
1528
  _releasedPageScrollStates = [NSMutableDictionary new];
1545
1529
  _mountingRemovedScrollViews = [NSHashTable weakObjectsHashTable];
1546
1530
  _originalInsets = [NSMapTable weakToStrongObjectsMapTable];
@@ -1915,123 +1899,18 @@ static void RNCLogNativeTabScrollBoundary(NSString *owner,
1915
1899
  [self applyHeaderOffset];
1916
1900
  }
1917
1901
 
1918
- - (void)offsetDiag:(NSString *)reason page:(NSInteger)index scroll:(UIScrollView *)scroll
1919
- {
1920
- #if DEBUG
1921
- NSString *key = index >= 0 && index < _pageControllers.count ? [self pageKeyForIndex:index] : @"none";
1922
- if (![@[@"portfolio", @"perps", @"defi", @"nft", @"history"] containsObject:key]) key = @"other";
1923
- NSNumber *saved = index >= 0 && index < _pageControllers.count ? _pageOffsets[[self pageKeyForIndex:index]] : nil;
1924
- UIView *component = scroll == nil ? nil : RNCScrollComponentView(scroll);
1925
- RNCCollapsiblePagerLog([NSString stringWithFormat:
1926
- @"[HOME-OFFSET-DIAG] pager phase=%@ seq=%lu wallMs=%.0f mono=%.6f host=%p generation=%lu transitionId=%lu page=%ld key=%@ current=%ld destination=%ld transition=%d dragging=%d scroll=%p tag=%ld component=%p componentTag=%ld observed=%p ownerIndex=%ld ownerGeneration=%lu synthetic=%d cacheExists=%d cache=%.4f header=%.4f headerHeight=%ld physicalY=%.4f insetTop=%.4f insetBottom=%.4f logicalY=%.4f contentHeight=%.4f boundsHeight=%.4f",
1927
- reason, (unsigned long)++_offsetDiagSequence, NSDate.date.timeIntervalSince1970 * 1000, CACurrentMediaTime(),
1928
- (__bridge void *)self, (unsigned long)_generation, (unsigned long)_transitionId, (long)index, key,
1929
- (long)_currentIndex, (long)_destinationIndex, _transitioning, _isPagerDragging,
1930
- (__bridge void *)scroll, (long)scroll.tag, (__bridge void *)component, (long)component.tag,
1931
- (__bridge void *)_observedScrollView, (long)_observedPageIndex, (unsigned long)_observedPageGeneration, _syntheticPageRestore, saved != nil, saved.doubleValue, _headerOffset, (long)_headerHeight,
1932
- scroll.contentOffset.y, scroll.contentInset.top, scroll.contentInset.bottom,
1933
- scroll.contentOffset.y + scroll.contentInset.top, scroll.contentSize.height, scroll.bounds.size.height]);
1934
- #endif
1935
- }
1936
-
1937
1902
  - (void)preparePageForHorizontalTransitionAtIndex:(NSInteger)pageIndex
1938
1903
  {
1939
- [self offsetDiag:@"prepare-check" page:pageIndex scroll:nil];
1940
- if (!_nativeSmoothHeaderScrollEnabled ||
1904
+ if (!_nativeSmoothHeaderScrollEnabled || _headerOffset >= _headerHeight ||
1941
1905
  pageIndex < 0 || pageIndex >= _pageControllers.count) return;
1906
+
1907
+ _pageOffsets[[self pageKeyForIndex:pageIndex]] = @(_headerOffset);
1942
1908
  UIScrollView *scrollView = [self verticalScrollViewForPageAtIndex:pageIndex];
1943
1909
  if (scrollView != nil && scrollView != _observedScrollView) {
1944
1910
  [self applyInsetsToScrollView:scrollView pageIndex:pageIndex restore:YES];
1945
1911
  }
1946
1912
  }
1947
1913
 
1948
- - (void)beginPageStateTransition
1949
- {
1950
- if (!_nativeSmoothHeaderScrollEnabled || _headerHeight <= 0 || _transitionPageOffsets != nil) return;
1951
- [self detachScrollObserver];
1952
- _transitionSourceIndex = _currentIndex;
1953
- _transitionPageOffsets = [_pageOffsets copy];
1954
- _transitionCompensatedPages = [NSMutableIndexSet new];
1955
- #if DEBUG
1956
- _transitionDiagBucket = -1;
1957
- [self offsetDiag:[NSString stringWithFormat:@"screen-begin-source=%ld-savedQ=%.4f", (long)_transitionSourceIndex,
1958
- [_transitionPageOffsets[self.currentPageKey] doubleValue]] page:_currentIndex scroll:nil];
1959
- #endif
1960
- }
1961
-
1962
- - (void)updatePageStateTransitionProgress:(CGFloat)progress
1963
- {
1964
- if (_transitionPageOffsets == nil || _finishingPageStateTransition) return;
1965
- NSInteger first = MAX(0, MIN((NSInteger)floor(progress), (NSInteger)_pageControllers.count - 1));
1966
- NSInteger second = MIN(first + 1, (NSInteger)_pageControllers.count - 1);
1967
- CGFloat fraction = RNCClamp(progress - first, 0, 1);
1968
- if (!_isPagerDragging && _destinationIndex != _transitionSourceIndex) {
1969
- first = _transitionSourceIndex;
1970
- second = _destinationIndex;
1971
- fraction = RNCClamp((progress - first) / (second - first), 0, 1);
1972
- }
1973
- CGFloat firstQ = [_transitionPageOffsets[[self pageKeyForIndex:first]] doubleValue];
1974
- CGFloat secondQ = [_transitionPageOffsets[[self pageKeyForIndex:second]] doubleValue];
1975
- CGFloat firstH = RNCClamp(firstQ, 0, _headerHeight);
1976
- CGFloat secondH = RNCClamp(secondQ, 0, _headerHeight);
1977
- _headerOffset = firstH + (secondH - firstH) * fraction;
1978
- #if DEBUG
1979
- NSInteger bucket = (NSInteger)floor(fraction * 4);
1980
- if (_transitionDiagBucket != bucket) {
1981
- _transitionDiagBucket = bucket;
1982
- [self offsetDiag:[NSString stringWithFormat:
1983
- @"screen-progress-kind=%@-source=%ld-target=%ld-sourceQ=%.4f-targetQ=%.4f-position=%.4f-fraction=%.4f",
1984
- _isPagerDragging ? @"interactive" : @"programmatic-endpoint", (long)first, (long)second,
1985
- firstQ, secondQ, progress, fraction] page:_currentIndex scroll:nil];
1986
- }
1987
- #endif
1988
- _syntheticPageRestore = YES;
1989
- NSInteger visibleFirst = MAX(0, MIN((NSInteger)floor(progress), (NSInteger)_pageControllers.count - 1));
1990
- NSInteger visibleLast = MIN(visibleFirst + 1, (NSInteger)_pageControllers.count - 1);
1991
- NSMutableIndexSet *displayPages = [NSMutableIndexSet indexSetWithIndexesInRange:
1992
- NSMakeRange(visibleFirst, visibleLast - visibleFirst + 1)];
1993
- if (!_isPagerDragging) {
1994
- // UIView tap animation reports its endpoint once while the source exits.
1995
- [displayPages addIndex:_transitionSourceIndex];
1996
- [displayPages addIndex:_destinationIndex];
1997
- }
1998
- for (NSUInteger index = displayPages.firstIndex; index != NSNotFound;
1999
- index = [displayPages indexGreaterThanIndex:index]) {
2000
- UIScrollView *scroll = [self verticalScrollViewForPageAtIndex:index];
2001
- if (scroll != nil) [self applyInsetsToScrollView:scroll pageIndex:index restore:YES];
2002
- }
2003
- _syntheticPageRestore = NO;
2004
- [self layoutSharedHeaders];
2005
- }
2006
-
2007
- - (void)finishPageStateTransition
2008
- {
2009
- if (_transitionPageOffsets == nil) return;
2010
- _finishingPageStateTransition = YES;
2011
- _headerOffset = RNCClamp([_transitionPageOffsets[self.currentPageKey] doubleValue], 0, _headerHeight);
2012
- _syntheticPageRestore = YES;
2013
- // Both completion and cancellation undo every temporary viewport offset.
2014
- for (NSUInteger index = _transitionCompensatedPages.firstIndex; index != NSNotFound;
2015
- index = [_transitionCompensatedPages indexGreaterThanIndex:index]) {
2016
- UIScrollView *scroll = [self verticalScrollViewForPageAtIndex:index];
2017
- if (scroll == nil) continue;
2018
- [self applyInsetsToScrollView:scroll pageIndex:index restore:YES];
2019
- NSString *key = [self pageKeyForIndex:index];
2020
- if (![_pendingPageRestoreKeys containsObject:key]) {
2021
- _pageOffsets[key] = @(scroll.contentOffset.y + scroll.contentInset.top);
2022
- }
2023
- }
2024
- _syntheticPageRestore = NO;
2025
- _finishingPageStateTransition = NO;
2026
- _transitionPageOffsets = nil;
2027
- _transitionCompensatedPages = nil;
2028
- [self layoutSharedHeaders];
2029
- #if DEBUG
2030
- [self offsetDiag:[NSString stringWithFormat:@"screen-finish-source=%ld-cancelled=%d", (long)_transitionSourceIndex,
2031
- _currentIndex == _transitionSourceIndex] page:_currentIndex scroll:nil];
2032
- #endif
2033
- }
2034
-
2035
1914
  #pragma mark - React mounting
2036
1915
 
2037
1916
  // OneKey patch: Fabric can recycle a removed list as a descendant of our header
@@ -2079,16 +1958,8 @@ static void RNCLogNativeTabScrollBoundary(NSString *owner,
2079
1958
  _releasedPageScrollStates[pageKey] = state;
2080
1959
  // Retained pages may be visually aligned to the expanded header while
2081
1960
  // their saved offsets still hold the user's independent list position.
2082
- BOOL ownsObservedPage = scrollView == _observedScrollView &&
2083
- (!_nativeSmoothHeaderScrollEnabled ||
2084
- (_observedPageGeneration == _generation && _observedPageIndex == index &&
2085
- [_observedPageKey isEqualToString:pageKey]));
2086
- if (_transitionPageOffsets == nil && !_syntheticPageRestore &&
2087
- (!_nativeSmoothHeaderScrollEnabled || ![_pendingPageRestoreKeys containsObject:pageKey]) &&
2088
- (ownsObservedPage || _pageOffsets[pageKey] == nil)) {
2089
- [self offsetDiag:@"mount-release-save-before" page:index scroll:scrollView];
1961
+ if (scrollView == _observedScrollView || _pageOffsets[pageKey] == nil) {
2090
1962
  _pageOffsets[pageKey] = @(scrollView.contentOffset.y + scrollView.contentInset.top);
2091
- [self offsetDiag:@"mount-release-save-after" page:index scroll:scrollView];
2092
1963
  }
2093
1964
  break;
2094
1965
  }
@@ -2372,9 +2243,7 @@ static void RNCLogNativeTabScrollBoundary(NSString *owner,
2372
2243
  if (appliedTop != nil && scrollView.refreshControl != nil) {
2373
2244
  original.top += MAX(0, scrollView.contentInset.top - appliedTop.doubleValue);
2374
2245
  }
2375
- [self offsetDiag:@"release-original-inset-before" page:_currentIndex scroll:scrollView];
2376
- scrollView.contentInset = original;
2377
- [self offsetDiag:@"release-original-inset-after" page:_currentIndex scroll:scrollView];
2246
+ scrollView.contentInset = original;
2378
2247
  }
2379
2248
  NSValue *indicatorValue = [_originalIndicatorInsets objectForKey:scrollView];
2380
2249
  if (indicatorValue != nil) {
@@ -2426,11 +2295,6 @@ static void RNCLogNativeTabScrollBoundary(NSString *owner,
2426
2295
  _pagerScrollView = nil;
2427
2296
  [super prepareForRecycle];
2428
2297
  [_pageOffsets removeAllObjects];
2429
- [_pendingPageRestoreKeys removeAllObjects];
2430
- _transitionPageOffsets = nil;
2431
- _transitionCompensatedPages = nil;
2432
- _syntheticPageRestore = NO;
2433
- _finishingPageStateTransition = NO;
2434
2298
  _pageKeys = @[];
2435
2299
  _retainedPages = @"[]";
2436
2300
  _currentIndex = 0;
@@ -2763,9 +2627,6 @@ static void RNCLogNativeTabScrollBoundary(NSString *owner,
2763
2627
  - (void)attachScrollObserverForCurrentPageAfterTransition:(BOOL)selectionSettled
2764
2628
  {
2765
2629
  if (_isBeingRecycled) return;
2766
- if (_nativeSmoothHeaderScrollEnabled &&
2767
- (_transitioning || _isPagerDragging || _transitionPageOffsets != nil) && !selectionSettled) return;
2768
- if (selectionSettled) [self finishPageStateTransition];
2769
2630
  if (_needsScrollObserverReattachAfterMount) {
2770
2631
  if (self.window == nil || ((_transitioning || _isPagerDragging) && !selectionSettled)) return;
2771
2632
  [self prepareAdjacentPageInsets];
@@ -2824,34 +2685,20 @@ static void RNCLogNativeTabScrollBoundary(NSString *owner,
2824
2685
  if (_pagerScrollView != nil && !_nativeSmoothHeaderScrollEnabled && !_needsPropsReapply) {
2825
2686
  [candidate.panGestureRecognizer requireGestureRecognizerToFail:_pagerScrollView.panGestureRecognizer];
2826
2687
  }
2827
- if (candidate == _observedScrollView &&
2828
- (!_nativeSmoothHeaderScrollEnabled ||
2829
- ([_observedPageKey isEqualToString:self.currentPageKey] &&
2830
- _observedPageIndex == _currentIndex && _observedPageGeneration == _generation))) {
2688
+ if (candidate == _observedScrollView) {
2831
2689
  _needsScrollObserverReattachAfterMount = NO;
2832
- if ([_pendingPageRestoreKeys containsObject:self.currentPageKey]) {
2833
- [self applyInsetsToScrollView:candidate pageIndex:_currentIndex restore:YES];
2834
- }
2835
2690
  [self attachSharedHeadersToScrollView:candidate];
2836
2691
  [self updateSharedHeaderPressCancellationGesture];
2837
2692
  return;
2838
2693
  }
2839
2694
 
2840
- [self offsetDiag:@"observer-candidate" page:_currentIndex scroll:candidate];
2841
- BOOL replacingCurrentScrollView = _observingContentOffset &&
2842
- (!_nativeSmoothHeaderScrollEnabled || [_observedPageKey isEqualToString:self.currentPageKey]);
2695
+ BOOL replacingCurrentScrollView = _observingContentOffset;
2843
2696
  [self detachScrollObserver];
2844
2697
  if (replacingCurrentScrollView) {
2845
- // Legacy replacement discards body state; smooth replacement waits for layout.
2846
- [self offsetDiag:@"observer-replacement-cache-before" page:_currentIndex scroll:candidate];
2847
- if (!_nativeSmoothHeaderScrollEnabled) _pageOffsets[self.currentPageKey] = @(_headerOffset);
2848
- [self offsetDiag:@"observer-replacement-cache-after" page:_currentIndex scroll:candidate];
2698
+ // A list replaced by an empty RN view keeps collapse, not the old row offset.
2699
+ _pageOffsets[self.currentPageKey] = @(_headerOffset);
2849
2700
  }
2850
2701
  _observedScrollView = candidate;
2851
- _observedPageKey = [self.currentPageKey copy];
2852
- _observedPageIndex = _currentIndex;
2853
- _observedPageGeneration = _generation;
2854
- [self offsetDiag:@"observer-attached-before-restore" page:_currentIndex scroll:candidate];
2855
2702
  [self applyInsetsToScrollView:candidate pageIndex:_currentIndex restore:YES];
2856
2703
  [candidate addObserver:self
2857
2704
  forKeyPath:@"contentOffset"
@@ -2878,17 +2725,7 @@ static void RNCLogNativeTabScrollBoundary(NSString *owner,
2878
2725
  UIScrollView *scrollView = _observedScrollView;
2879
2726
  if (scrollView != nil) {
2880
2727
  [scrollView.panGestureRecognizer removeTarget:self action:@selector(observedListPanChanged:)];
2881
- [self offsetDiag:@"detach-save-before" page:_currentIndex scroll:scrollView];
2882
- NSString *ownerKey = _nativeSmoothHeaderScrollEnabled ? _observedPageKey : self.currentPageKey;
2883
- BOOL ownerKeyExists = ownerKey != nil && ([_pageKeys containsObject:ownerKey] ||
2884
- (_observedPageIndex >= 0 && _observedPageIndex < _pageControllers.count &&
2885
- [[self pageKeyForIndex:_observedPageIndex] isEqualToString:ownerKey]));
2886
- if (ownerKey != nil && (!_nativeSmoothHeaderScrollEnabled ||
2887
- (ownerKeyExists && _observedPageGeneration == _generation && _transitionPageOffsets == nil &&
2888
- !_syntheticPageRestore && ![_pendingPageRestoreKeys containsObject:ownerKey]))) {
2889
- _pageOffsets[ownerKey] = @(scrollView.contentOffset.y + scrollView.contentInset.top);
2890
- }
2891
- [self offsetDiag:@"detach-save-after" page:_currentIndex scroll:scrollView];
2728
+ _pageOffsets[self.currentPageKey] = @(scrollView.contentOffset.y + scrollView.contentInset.top);
2892
2729
  if (_observingContentOffset) {
2893
2730
  [scrollView removeObserver:self
2894
2731
  forKeyPath:@"contentOffset"
@@ -2903,8 +2740,6 @@ static void RNCLogNativeTabScrollBoundary(NSString *owner,
2903
2740
  }
2904
2741
  _observingContentOffset = NO;
2905
2742
  _observedScrollView = nil;
2906
- _observedPageKey = nil;
2907
- _observedPageIndex = NSNotFound;
2908
2743
  if ([scrollView.superview isKindOfClass:RNCNativeScrollerComponentView.class]) {
2909
2744
  [(RNCNativeScrollerComponentView *)scrollView.superview stopScrolling];
2910
2745
  }
@@ -3175,9 +3010,7 @@ static void RNCLogNativeTabScrollBoundary(NSString *owner,
3175
3010
  [self releaseRefreshControlForScrollView:scrollView];
3176
3011
  if (scrollView == _observedScrollView) {
3177
3012
  [self detachScrollObserver];
3178
- [self offsetDiag:resetSavedOffset ? @"release-reset-before" : @"release-retain-before" page:_currentIndex scroll:scrollView];
3179
- if (resetSavedOffset && !_nativeSmoothHeaderScrollEnabled) _pageOffsets[self.currentPageKey] = @(_headerOffset);
3180
- [self offsetDiag:@"release-reset-after" page:_currentIndex scroll:scrollView];
3013
+ if (resetSavedOffset) _pageOffsets[self.currentPageKey] = @(_headerOffset);
3181
3014
  }
3182
3015
  if (scrollView == _sharedHeaderScrollView) {
3183
3016
  [self restoreSharedHeadersToContainer];
@@ -3197,10 +3030,8 @@ static void RNCLogNativeTabScrollBoundary(NSString *owner,
3197
3030
  [_originalDirectionalLockEnabled objectForKey:scrollView].boolValue;
3198
3031
  scrollView.contentInsetAdjustmentBehavior = (UIScrollViewContentInsetAdjustmentBehavior)
3199
3032
  [_originalInsetAdjustmentBehavior objectForKey:scrollView].integerValue;
3200
- [self offsetDiag:@"release-original-offset-before" page:_currentIndex scroll:scrollView];
3201
3033
  [scrollView setContentOffset:CGPointMake(scrollView.contentOffset.x, logicalOffset - original.top)
3202
3034
  animated:NO];
3203
- [self offsetDiag:@"release-original-offset-after" page:_currentIndex scroll:scrollView];
3204
3035
  [_originalInsets removeObjectForKey:scrollView];
3205
3036
  [_appliedTopInsets removeObjectForKey:scrollView];
3206
3037
  [_originalIndicatorInsets removeObjectForKey:scrollView];
@@ -3229,9 +3060,8 @@ static void RNCLogNativeTabScrollBoundary(NSString *owner,
3229
3060
  pageIndex:(NSInteger)pageIndex
3230
3061
  restore:(BOOL)restore
3231
3062
  {
3232
- // Smooth pages retain their complete offset while replacement identity and
3233
- // layout settle. Legacy pages retain the historical header-only policy.
3234
- [self offsetDiag:restore ? @"restore-enter" : @"insets-enter" page:pageIndex scroll:scrollView];
3063
+ // OneKey patch: a surviving list keeps its full offset. A replacement keeps
3064
+ // only header collapse, even if Fabric reused the same native scroll object.
3235
3065
  NSString *pageKey = [self pageKeyForIndex:pageIndex];
3236
3066
  RNCCollapsiblePagerReleasedScrollState *released = _releasedPageScrollStates[pageKey];
3237
3067
  BOOL deferredReleasedIdentity = NO;
@@ -3277,13 +3107,8 @@ static void RNCLogNativeTabScrollBoundary(NSString *owner,
3277
3107
  deferredReleasedIdentity = now - released.pendingFallbackDetectedAt <
3278
3108
  RNCCollapsiblePagerFallbackDebounceInterval;
3279
3109
  }
3280
- #if DEBUG
3281
- [self offsetDiag:[NSString stringWithFormat:@"released-identity-match=%d-deferred=%d-oldTag=%ld-oldScroll=%p", sameList, deferredReleasedIdentity, (long)released.componentTag, (__bridge void *)released.scrollView] page:pageIndex scroll:scrollView];
3282
- #endif
3283
3110
  if (!deferredReleasedIdentity) {
3284
- [self offsetDiag:@"released-identity-cache-before" page:pageIndex scroll:scrollView];
3285
- if (!sameList && !_nativeSmoothHeaderScrollEnabled) _pageOffsets[pageKey] = @(_headerOffset);
3286
- [self offsetDiag:@"released-identity-cache-after" page:pageIndex scroll:scrollView];
3111
+ if (!sameList) _pageOffsets[pageKey] = @(_headerOffset);
3287
3112
  [_releasedPageScrollStates removeObjectForKey:pageKey];
3288
3113
  }
3289
3114
  }
@@ -3331,9 +3156,7 @@ static void RNCLogNativeTabScrollBoundary(NSString *owner,
3331
3156
  if (pageIndex == _currentIndex) [self updateHeaderForScrollView:scrollView];
3332
3157
  return;
3333
3158
  }
3334
- [self offsetDiag:@"inset-assignment-before" page:pageIndex scroll:scrollView];
3335
3159
  scrollView.contentInset = next;
3336
- [self offsetDiag:@"inset-assignment-after" page:pageIndex scroll:scrollView];
3337
3160
  UIEdgeInsets indicatorInsets = scrollView.verticalScrollIndicatorInsets;
3338
3161
  indicatorInsets.top = pagerTopInset;
3339
3162
  scrollView.verticalScrollIndicatorInsets = indicatorInsets;
@@ -3341,37 +3164,21 @@ static void RNCLogNativeTabScrollBoundary(NSString *owner,
3341
3164
 
3342
3165
  CGFloat targetOffset = previousLogicalOffset - next.top;
3343
3166
  if (restore) {
3344
- NSNumber *saved = _transitionPageOffsets != nil
3345
- ? _transitionPageOffsets[pageKey] : _pageOffsets[pageKey];
3167
+ NSNumber *saved = _pageOffsets[[self pageKeyForIndex:pageIndex]];
3346
3168
  // The sticky slot can change height between pages. Cache offsets relative
3347
3169
  // to content start so a round trip does not add that height difference.
3348
- CGFloat restoredLogicalOffset;
3349
- if (_nativeSmoothHeaderScrollEnabled && _headerHeight > 0) {
3350
- restoredLogicalOffset = saved.doubleValue;
3351
- if (_transitionPageOffsets != nil && !_finishingPageStateTransition) {
3352
- [_transitionCompensatedPages addIndex:pageIndex];
3353
- restoredLogicalOffset = MAX(restoredLogicalOffset - _headerHeight, 0) + _headerOffset;
3354
- }
3355
- if (deferredReleasedIdentity || scrollView.bounds.size.height <= 0 || scrollView.contentSize.height <= 0) {
3356
- [_pendingPageRestoreKeys addObject:pageKey];
3357
- return;
3358
- }
3359
- [_pendingPageRestoreKeys removeObject:pageKey];
3360
- } else {
3361
- restoredLogicalOffset = deferredReleasedIdentity || saved == nil ? _headerOffset : saved.doubleValue;
3170
+ CGFloat restoredLogicalOffset = deferredReleasedIdentity || saved == nil
3171
+ ? _headerOffset
3172
+ : saved.doubleValue;
3173
+ // While the shared header is visible, retained pages must agree on its
3174
+ // collapse position. Deep offsets remain independent after full collapse.
3175
+ if (_nativeSmoothHeaderScrollEnabled && _headerOffset < _headerHeight) {
3176
+ restoredLogicalOffset = _headerOffset;
3362
3177
  }
3363
- #if DEBUG
3364
- [self offsetDiag:[NSString stringWithFormat:@"restore-candidate-saved=%.4f-headerAlignedLogical=%.4f", saved.doubleValue, restoredLogicalOffset] page:pageIndex scroll:scrollView];
3365
- #endif
3366
3178
  targetOffset = restoredLogicalOffset - next.top;
3367
- if (!_nativeSmoothHeaderScrollEnabled || _headerHeight <= 0) {
3368
- targetOffset = MAX(targetOffset, -next.top + _headerOffset);
3369
- }
3179
+ targetOffset = MAX(targetOffset, -next.top + _headerOffset);
3370
3180
  // An inactive list may shrink after its offset observer was detached.
3371
3181
  // Do not overwrite its corrected offset with a now-unreachable cached one.
3372
- #if DEBUG
3373
- [self offsetDiag:[NSString stringWithFormat:@"restore-clamp-before-candidate=%.4f-max=%.4f", targetOffset, MAX(-next.top, scrollView.contentSize.height - scrollView.bounds.size.height + next.bottom)] page:pageIndex scroll:scrollView];
3374
- #endif
3375
3182
  targetOffset = RNCLimitRestoredScrollOffset(
3376
3183
  targetOffset,
3377
3184
  scrollView.contentSize.height,
@@ -3380,15 +3187,11 @@ static void RNCLogNativeTabScrollBoundary(NSString *owner,
3380
3187
  next.bottom
3381
3188
  );
3382
3189
  }
3383
- #if DEBUG
3384
- [self offsetDiag:[NSString stringWithFormat:@"restore-final-target=%.4f-restore=%d", targetOffset, restore] page:pageIndex scroll:scrollView];
3385
- #endif
3386
3190
  // A bottom-inset change must not cancel UIKit's refresh or bounce settlement.
3387
3191
  if (restore || previousTopInset != next.top) {
3388
3192
  [scrollView setContentOffset:CGPointMake(scrollView.contentOffset.x, targetOffset) animated:NO];
3389
3193
  }
3390
3194
  if (pageIndex == _currentIndex) [self updateHeaderForScrollView:scrollView];
3391
- [self offsetDiag:@"restore-post" page:pageIndex scroll:scrollView];
3392
3195
  }
3393
3196
 
3394
3197
  - (void)updateNativeScrollerViewport:(UIScrollView *)scrollView stickyHeight:(CGFloat)height
@@ -3449,24 +3252,10 @@ static void RNCLogNativeTabScrollBoundary(NSString *owner,
3449
3252
  if (context == RNCScrollRefreshControlContext) {
3450
3253
  UIScrollView *scrollView = (UIScrollView *)object;
3451
3254
  [self updateRefreshControlForScrollView:scrollView];
3452
- if (scrollView == _observedScrollView && !_syntheticPageRestore &&
3453
- (!_nativeSmoothHeaderScrollEnabled || (!_transitioning && _transitionPageOffsets == nil))) {
3454
- [self updateHeaderForScrollView:scrollView];
3455
- }
3255
+ if (scrollView == _observedScrollView) [self updateHeaderForScrollView:scrollView];
3456
3256
  return;
3457
3257
  }
3458
3258
  if (context == RNCCollapsiblePagerContentOffsetContext && object == _observedScrollView) {
3459
- if (_nativeSmoothHeaderScrollEnabled &&
3460
- (_observedPageGeneration != _generation || _observedPageKey == nil ||
3461
- _observedPageIndex != _currentIndex || ![_observedPageKey isEqualToString:self.currentPageKey] ||
3462
- _transitioning || _isPagerDragging ||
3463
- _transitionPageOffsets != nil || _syntheticPageRestore)) return;
3464
- if (_nativeSmoothHeaderScrollEnabled && [_pendingPageRestoreKeys containsObject:_observedPageKey]) {
3465
- if ([keyPath isEqualToString:@"contentSize"]) {
3466
- [self applyInsetsToScrollView:_observedScrollView pageIndex:_observedPageIndex restore:YES];
3467
- }
3468
- return;
3469
- }
3470
3259
  if ([keyPath isEqualToString:@"contentInset"]) {
3471
3260
  [self updateHeaderForScrollView:(UIScrollView *)object];
3472
3261
  return;
@@ -3481,14 +3270,7 @@ static void RNCLogNativeTabScrollBoundary(NSString *owner,
3481
3270
  }
3482
3271
  UIScrollView *scrollView = (UIScrollView *)object;
3483
3272
  _currentLogicalOffset = scrollView.contentOffset.y + scrollView.contentInset.top;
3484
- #if DEBUG
3485
- BOOL offsetDiagChanged = _pageOffsets[self.currentPageKey] == nil || _pageOffsets[self.currentPageKey].doubleValue != _currentLogicalOffset;
3486
- if (offsetDiagChanged) [self offsetDiag:@"kvo-cache-before" page:_currentIndex scroll:scrollView];
3487
- #endif
3488
- _pageOffsets[_nativeSmoothHeaderScrollEnabled ? _observedPageKey : self.currentPageKey] = @(_currentLogicalOffset);
3489
- #if DEBUG
3490
- if (offsetDiagChanged) [self offsetDiag:@"kvo-cache-after" page:_currentIndex scroll:scrollView];
3491
- #endif
3273
+ _pageOffsets[self.currentPageKey] = @(_currentLogicalOffset);
3492
3274
  [self updateHeaderForScrollView:scrollView];
3493
3275
  return;
3494
3276
  }
@@ -3497,8 +3279,6 @@ static void RNCLogNativeTabScrollBoundary(NSString *owner,
3497
3279
 
3498
3280
  - (void)updateHeaderForScrollView:(UIScrollView *)scrollView
3499
3281
  {
3500
- if (_nativeSmoothHeaderScrollEnabled &&
3501
- (_syntheticPageRestore || _transitionPageOffsets != nil)) return;
3502
3282
  CGFloat logicalOffset = scrollView.contentOffset.y + scrollView.contentInset.top;
3503
3283
  _currentLogicalOffset = logicalOffset;
3504
3284
  _headerOffset = MIN(MAX(logicalOffset, 0), _headerHeight);
@@ -3542,7 +3322,6 @@ static void RNCLogNativeTabScrollBoundary(NSString *owner,
3542
3322
 
3543
3323
  - (void)goTo:(NSInteger)index animated:(BOOL)animated
3544
3324
  {
3545
- [self offsetDiag:@"go-to" page:index scroll:_observedScrollView];
3546
3325
  if (_isBeingRecycled || index < 0 || index >= _pageControllers.count) return;
3547
3326
  _hasReceivedPageCommand = YES;
3548
3327
  _hasAppliedInitialPage = YES;
@@ -3568,7 +3347,6 @@ static void RNCLogNativeTabScrollBoundary(NSString *owner,
3568
3347
  return;
3569
3348
  }
3570
3349
 
3571
- [self beginPageStateTransition];
3572
3350
  [self preparePageForHorizontalTransitionAtIndex:index];
3573
3351
  _destinationIndex = index;
3574
3352
  [self liftSharedHeadersForPagerTransition:@"programmatic"];
@@ -3588,7 +3366,6 @@ static void RNCLogNativeTabScrollBoundary(NSString *owner,
3588
3366
  void (^animations)(void) = ^{
3589
3367
  [self->_pagerScrollView setContentOffset:CGPointMake(targetOffset, 0)];
3590
3368
  [self->_nativeTabBarView setProgress:index];
3591
- [self updatePageStateTransitionProgress:index];
3592
3369
  };
3593
3370
  void (^completion)(BOOL) = ^(BOOL finished) {
3594
3371
  __strong __typeof__(weakSelf) self = weakSelf;
@@ -3596,7 +3373,6 @@ static void RNCLogNativeTabScrollBoundary(NSString *owner,
3596
3373
  self->_transitionId != capturedTransition || self->_isBeingRecycled) return;
3597
3374
  self->_pagerScrollView.scrollEnabled = self->_scrollEnabled;
3598
3375
  if (finished) {
3599
- [self detachScrollObserver];
3600
3376
  self->_currentIndex = index;
3601
3377
  self->_destinationIndex = index;
3602
3378
  [self->_nativeTabBarView setProgress:index];
@@ -3634,7 +3410,6 @@ static void RNCLogNativeTabScrollBoundary(NSString *owner,
3634
3410
  if (self == nil || self->_generation != capturedGeneration ||
3635
3411
  self->_transitionId != capturedTransition || self->_isBeingRecycled) return;
3636
3412
  if (finished) {
3637
- [self detachScrollObserver];
3638
3413
  self->_currentIndex = index;
3639
3414
  self->_destinationIndex = index;
3640
3415
  [self->_nativeTabBarView setProgress:index];
@@ -3659,7 +3434,6 @@ static void RNCLogNativeTabScrollBoundary(NSString *owner,
3659
3434
  dispatch_async(dispatch_get_main_queue(), ^{
3660
3435
  if (self->_generation != generation || self->_transitionId != transition ||
3661
3436
  self->_isBeingRecycled) return;
3662
- [self finishPageStateTransition];
3663
3437
  self->_transitioning = NO;
3664
3438
  if (self->_hasPendingDirectNativePagerChange) {
3665
3439
  BOOL enabled = self->_pendingDirectNativePagerEnabled;
@@ -3723,11 +3497,9 @@ static void RNCLogNativeTabScrollBoundary(NSString *owner,
3723
3497
 
3724
3498
  - (void)scrollViewWillBeginDragging:(UIScrollView *)scrollView
3725
3499
  {
3726
- [self offsetDiag:@"pager-drag-begin" page:_currentIndex scroll:_observedScrollView];
3727
3500
  if (_nativeSmoothHeaderScrollEnabled && scrollView == _pagerScrollView) {
3728
3501
  [_contentPressCancellationGesture cancelPressForPan:scrollView.panGestureRecognizer];
3729
3502
  }
3730
- [self beginPageStateTransition];
3731
3503
  if (_directNativePagerEnabled) {
3732
3504
  [self preparePageForHorizontalTransitionAtIndex:_currentIndex - 1];
3733
3505
  [self preparePageForHorizontalTransitionAtIndex:_currentIndex + 1];
@@ -3879,7 +3651,6 @@ static void RNCLogNativeTabScrollBoundary(NSString *owner,
3879
3651
  NSInteger position = (NSInteger)floor(progress);
3880
3652
  CGFloat offset = progress - position;
3881
3653
  position = MAX(0, MIN(position, (NSInteger)_pageControllers.count - 1));
3882
- [self updatePageStateTransitionProgress:progress];
3883
3654
  [_nativeTabBarView setProgress:progress];
3884
3655
  const auto emitter = [self eventEmitter];
3885
3656
  if (emitter) {
@@ -3897,7 +3668,6 @@ static void RNCLogNativeTabScrollBoundary(NSString *owner,
3897
3668
  CGFloat transitionProgress = RNCClamp(fabs(rawOffset), 0, 1);
3898
3669
  tabProgress = _currentIndex + (_destinationIndex - _currentIndex) * transitionProgress;
3899
3670
  }
3900
- [self updatePageStateTransitionProgress:tabProgress];
3901
3671
  [_nativeTabBarView setProgress:tabProgress];
3902
3672
  const auto emitter = [self eventEmitter];
3903
3673
  if (emitter) {
@@ -3915,7 +3685,6 @@ static void RNCLogNativeTabScrollBoundary(NSString *owner,
3915
3685
 
3916
3686
  - (void)emitPageSelected:(NSInteger)position
3917
3687
  {
3918
- [self offsetDiag:@"selection-complete" page:position scroll:_observedScrollView];
3919
3688
  const auto emitter = [self eventEmitter];
3920
3689
  if (emitter) emitter->onPageSelected({.position = (double)position});
3921
3690
  }
@@ -33,9 +33,6 @@ static Event RNCScrollerMetrics(UIScrollView *scroll, CGPoint velocity, CGPoint
33
33
  @end
34
34
 
35
35
  @implementation RNCNativeScrollerComponentView {
36
- #if DEBUG
37
- NSUInteger _offsetDiagSequence;
38
- #endif
39
36
  RNCNativeScrollerShadowNode::ConcreteState::Shared _state;
40
37
  RNCNativeVerticalScrollView *_scrollView;
41
38
  UIView<RCTComponentViewProtocol> *_reactContent;
@@ -54,24 +51,6 @@ static Event RNCScrollerMetrics(UIScrollView *scroll, CGPoint velocity, CGPoint
54
51
  NSNumber *_lastContentViewportHeight;
55
52
  }
56
53
 
57
- - (void)offsetDiag:(NSString *)reason
58
- {
59
- #if DEBUG
60
- Class logClass = NSClassFromString(@"ReactNativeNativeLogger.OneKeyLog") ?: NSClassFromString(@"OneKeyLog");
61
- SEL selector = NSSelectorFromString(@"debug::");
62
- if (logClass == nil || ![logClass respondsToSelector:selector]) return;
63
- NSString *message = [NSString stringWithFormat:
64
- @"[HOME-OFFSET-DIAG] scroller phase=%@ seq=%lu wallMs=%.0f mono=%.6f host=%p tag=%ld scroll=%p generation=%lu physicalY=%.4f insetTop=%.4f logicalY=%.4f contentHeight=%.4f boundsHeight=%.4f adjustedBottom=%.4f needsClamp=%d drag=%d decel=%d refresh=%d",
65
- reason, (unsigned long)++_offsetDiagSequence, NSDate.date.timeIntervalSince1970 * 1000, CACurrentMediaTime(),
66
- (__bridge void *)self, (long)self.tag, (__bridge void *)_scrollView, (unsigned long)_generation,
67
- _scrollView.contentOffset.y, _scrollView.contentInset.top, _scrollView.contentOffset.y + _scrollView.contentInset.top,
68
- _scrollView.contentSize.height, _scrollView.bounds.size.height, _scrollView.adjustedContentInset.bottom,
69
- _needsContentClamp, _scrollView.dragging, _scrollView.decelerating, _refreshControl.refreshing];
70
- typedef void (*LogFunction)(id, SEL, NSString *, NSString *);
71
- ((LogFunction)[logClass methodForSelector:selector])(logClass, selector, @"NativeScroller", message);
72
- #endif
73
- }
74
-
75
54
  + (ComponentDescriptorProvider)componentDescriptorProvider
76
55
  {
77
56
  return concreteComponentDescriptorProvider<RNCNativeScrollerComponentDescriptor>();
@@ -200,9 +179,7 @@ static Event RNCScrollerMetrics(UIScrollView *scroll, CGPoint velocity, CGPoint
200
179
  _needsContentClamp |= size.height < _scrollView.contentSize.height;
201
180
  CGPoint offset = _scrollView.contentOffset;
202
181
  BOOL wasPulling = offset.y < -_scrollView.adjustedContentInset.top;
203
- [self offsetDiag:@"content-size-before"];
204
182
  _scrollView.contentSize = size;
205
- [self offsetDiag:@"content-size-after"];
206
183
  // UIKit can synchronously discard a pull when content becomes empty.
207
184
  // Upper-range shrink correction remains owned by the deferred clamp.
208
185
  if (wasPulling && _scrollView.contentOffset.y != offset.y) {
@@ -220,12 +197,10 @@ static Event RNCScrollerMetrics(UIScrollView *scroll, CGPoint velocity, CGPoint
220
197
  - (void)updateLayoutMetrics:(const LayoutMetrics &)layoutMetrics
221
198
  oldLayoutMetrics:(const LayoutMetrics &)oldLayoutMetrics
222
199
  {
223
- [self offsetDiag:@"layout-before"];
224
200
  CGSize previous = _scrollView.bounds.size;
225
201
  [super updateLayoutMetrics:layoutMetrics oldLayoutMetrics:oldLayoutMetrics];
226
202
  [self updateFabricContentOrigin];
227
203
  [self emitContentViewportChangeIfNeeded];
228
- [self offsetDiag:@"layout-after"];
229
204
  if (!CGSizeEqualToSize(previous, _scrollView.bounds.size)) {
230
205
  _needsContentClamp = YES;
231
206
  [self scheduleContentClamp];
@@ -288,7 +263,6 @@ static Event RNCScrollerMetrics(UIScrollView *scroll, CGPoint velocity, CGPoint
288
263
  - (void)scheduleContentClamp
289
264
  {
290
265
  if (!_needsContentClamp) return;
291
- [self offsetDiag:@"clamp-scheduled"];
292
266
  NSUInteger generation = _generation;
293
267
  __weak __typeof__(self) weakSelf = self;
294
268
  dispatch_async(dispatch_get_main_queue(), ^{
@@ -300,19 +274,13 @@ static Event RNCScrollerMetrics(UIScrollView *scroll, CGPoint velocity, CGPoint
300
274
 
301
275
  - (void)clampContentOffsetIfNeeded
302
276
  {
303
- [self offsetDiag:@"clamp-enter-or-deferred"];
304
277
  if (!_needsContentClamp || _scrollView.dragging || _scrollView.decelerating ||
305
278
  _refreshControl.refreshing || _scrollView.bounds.size.height <= 0) return;
306
279
  _needsContentClamp = NO;
307
280
  CGFloat maximum = MAX(-_scrollView.adjustedContentInset.top,
308
281
  _scrollView.contentSize.height - _scrollView.bounds.size.height + _scrollView.adjustedContentInset.bottom);
309
- #if DEBUG
310
- [self offsetDiag:[NSString stringWithFormat:@"clamp-candidate-max=%.4f", maximum]];
311
- #endif
312
282
  if (_scrollView.contentOffset.y > maximum) {
313
- [self offsetDiag:@"clamp-applied-before"];
314
283
  [_scrollView setContentOffset:CGPointMake(_scrollView.contentOffset.x, maximum) animated:NO];
315
- [self offsetDiag:@"clamp-applied-after"];
316
284
  }
317
285
  }
318
286
 
@@ -351,7 +319,6 @@ static Event RNCScrollerMetrics(UIScrollView *scroll, CGPoint velocity, CGPoint
351
319
  - (void)stopScrolling
352
320
  {
353
321
  if (_stopping) return;
354
- [self offsetDiag:@"stop-before"];
355
322
  _stopping = YES;
356
323
  [_scrollView setContentOffset:_scrollView.contentOffset animated:NO];
357
324
  if (_dragActive) {
@@ -363,7 +330,6 @@ static Event RNCScrollerMetrics(UIScrollView *scroll, CGPoint velocity, CGPoint
363
330
  }
364
331
  [self finishMomentum];
365
332
  _stopping = NO;
366
- [self offsetDiag:@"stop-after"];
367
333
  }
368
334
 
369
335
  - (void)scrollViewWillBeginDragging:(UIScrollView *)scrollView