@onekeyfe/react-native-pager-view 3.0.169 → 3.0.171
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/android/src/main/java/com/reactnativepagerview/CollapsiblePagerHost.kt +222 -19
- package/android/src/main/java/com/reactnativepagerview/CollapsiblePagerViewManager.kt +8 -0
- package/android/src/main/java/com/reactnativepagerview/NativeScrollerView.kt +2 -0
- package/android/src/test/java/com/reactnativepagerview/NativeScrollerPendingRestoreTest.kt +11 -0
- package/docs/SPEC.md +42 -3
- package/ios/RNCCollapsiblePagerViewComponentView.mm +257 -28
- package/ios/RNCNativeScrollerComponentView.mm +34 -0
- package/ios/tests/RNCCollapsiblePagerFirstFrameTests.mm +173 -0
- package/ios/tests/RNCCollapsiblePagerPressCancellationTests.mm +31 -0
- package/package.json +2 -2
|
@@ -1437,6 +1437,9 @@ static void RNCLogNativeTabScrollBoundary(NSString *owner,
|
|
|
1437
1437
|
@end
|
|
1438
1438
|
|
|
1439
1439
|
@implementation RNCCollapsiblePagerViewComponentView {
|
|
1440
|
+
#if DEBUG
|
|
1441
|
+
NSUInteger _offsetDiagSequence;
|
|
1442
|
+
#endif
|
|
1440
1443
|
UIView *_containerView;
|
|
1441
1444
|
RNCCollapsiblePagerSharedHeaderView *_sharedHeaderHostView;
|
|
1442
1445
|
UIPageViewController *_pageViewController;
|
|
@@ -1491,6 +1494,18 @@ static void RNCLogNativeTabScrollBoundary(NSString *owner,
|
|
|
1491
1494
|
BOOL _needsScrollObserverReattachAfterMount;
|
|
1492
1495
|
NSHashTable<UIScrollView *> *_mountingRemovedScrollViews;
|
|
1493
1496
|
__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;
|
|
1494
1509
|
__weak UIScrollView *_sharedHeaderScrollView;
|
|
1495
1510
|
__weak UIScrollView *_pendingFallbackScrollView;
|
|
1496
1511
|
__weak UIView *_sharedHeaderPressCancellationGestureHost;
|
|
@@ -1525,6 +1540,7 @@ static void RNCLogNativeTabScrollBoundary(NSString *owner,
|
|
|
1525
1540
|
_logicalChildren = [NSMutableArray new];
|
|
1526
1541
|
_pageControllers = [NSMutableArray new];
|
|
1527
1542
|
_pageOffsets = [NSMutableDictionary new];
|
|
1543
|
+
_pendingPageRestoreKeys = [NSMutableSet new];
|
|
1528
1544
|
_releasedPageScrollStates = [NSMutableDictionary new];
|
|
1529
1545
|
_mountingRemovedScrollViews = [NSHashTable weakObjectsHashTable];
|
|
1530
1546
|
_originalInsets = [NSMapTable weakToStrongObjectsMapTable];
|
|
@@ -1899,18 +1915,123 @@ static void RNCLogNativeTabScrollBoundary(NSString *owner,
|
|
|
1899
1915
|
[self applyHeaderOffset];
|
|
1900
1916
|
}
|
|
1901
1917
|
|
|
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
|
+
|
|
1902
1937
|
- (void)preparePageForHorizontalTransitionAtIndex:(NSInteger)pageIndex
|
|
1903
1938
|
{
|
|
1904
|
-
|
|
1939
|
+
[self offsetDiag:@"prepare-check" page:pageIndex scroll:nil];
|
|
1940
|
+
if (!_nativeSmoothHeaderScrollEnabled ||
|
|
1905
1941
|
pageIndex < 0 || pageIndex >= _pageControllers.count) return;
|
|
1906
|
-
|
|
1907
|
-
_pageOffsets[[self pageKeyForIndex:pageIndex]] = @(_headerOffset);
|
|
1908
1942
|
UIScrollView *scrollView = [self verticalScrollViewForPageAtIndex:pageIndex];
|
|
1909
1943
|
if (scrollView != nil && scrollView != _observedScrollView) {
|
|
1910
1944
|
[self applyInsetsToScrollView:scrollView pageIndex:pageIndex restore:YES];
|
|
1911
1945
|
}
|
|
1912
1946
|
}
|
|
1913
1947
|
|
|
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
|
+
|
|
1914
2035
|
#pragma mark - React mounting
|
|
1915
2036
|
|
|
1916
2037
|
// OneKey patch: Fabric can recycle a removed list as a descendant of our header
|
|
@@ -1958,8 +2079,16 @@ static void RNCLogNativeTabScrollBoundary(NSString *owner,
|
|
|
1958
2079
|
_releasedPageScrollStates[pageKey] = state;
|
|
1959
2080
|
// Retained pages may be visually aligned to the expanded header while
|
|
1960
2081
|
// their saved offsets still hold the user's independent list position.
|
|
1961
|
-
|
|
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];
|
|
1962
2090
|
_pageOffsets[pageKey] = @(scrollView.contentOffset.y + scrollView.contentInset.top);
|
|
2091
|
+
[self offsetDiag:@"mount-release-save-after" page:index scroll:scrollView];
|
|
1963
2092
|
}
|
|
1964
2093
|
break;
|
|
1965
2094
|
}
|
|
@@ -2243,7 +2372,9 @@ static void RNCLogNativeTabScrollBoundary(NSString *owner,
|
|
|
2243
2372
|
if (appliedTop != nil && scrollView.refreshControl != nil) {
|
|
2244
2373
|
original.top += MAX(0, scrollView.contentInset.top - appliedTop.doubleValue);
|
|
2245
2374
|
}
|
|
2246
|
-
|
|
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];
|
|
2247
2378
|
}
|
|
2248
2379
|
NSValue *indicatorValue = [_originalIndicatorInsets objectForKey:scrollView];
|
|
2249
2380
|
if (indicatorValue != nil) {
|
|
@@ -2295,6 +2426,11 @@ static void RNCLogNativeTabScrollBoundary(NSString *owner,
|
|
|
2295
2426
|
_pagerScrollView = nil;
|
|
2296
2427
|
[super prepareForRecycle];
|
|
2297
2428
|
[_pageOffsets removeAllObjects];
|
|
2429
|
+
[_pendingPageRestoreKeys removeAllObjects];
|
|
2430
|
+
_transitionPageOffsets = nil;
|
|
2431
|
+
_transitionCompensatedPages = nil;
|
|
2432
|
+
_syntheticPageRestore = NO;
|
|
2433
|
+
_finishingPageStateTransition = NO;
|
|
2298
2434
|
_pageKeys = @[];
|
|
2299
2435
|
_retainedPages = @"[]";
|
|
2300
2436
|
_currentIndex = 0;
|
|
@@ -2627,6 +2763,9 @@ static void RNCLogNativeTabScrollBoundary(NSString *owner,
|
|
|
2627
2763
|
- (void)attachScrollObserverForCurrentPageAfterTransition:(BOOL)selectionSettled
|
|
2628
2764
|
{
|
|
2629
2765
|
if (_isBeingRecycled) return;
|
|
2766
|
+
if (_nativeSmoothHeaderScrollEnabled &&
|
|
2767
|
+
(_transitioning || _isPagerDragging || _transitionPageOffsets != nil) && !selectionSettled) return;
|
|
2768
|
+
if (selectionSettled) [self finishPageStateTransition];
|
|
2630
2769
|
if (_needsScrollObserverReattachAfterMount) {
|
|
2631
2770
|
if (self.window == nil || ((_transitioning || _isPagerDragging) && !selectionSettled)) return;
|
|
2632
2771
|
[self prepareAdjacentPageInsets];
|
|
@@ -2685,20 +2824,34 @@ static void RNCLogNativeTabScrollBoundary(NSString *owner,
|
|
|
2685
2824
|
if (_pagerScrollView != nil && !_nativeSmoothHeaderScrollEnabled && !_needsPropsReapply) {
|
|
2686
2825
|
[candidate.panGestureRecognizer requireGestureRecognizerToFail:_pagerScrollView.panGestureRecognizer];
|
|
2687
2826
|
}
|
|
2688
|
-
if (candidate == _observedScrollView
|
|
2827
|
+
if (candidate == _observedScrollView &&
|
|
2828
|
+
(!_nativeSmoothHeaderScrollEnabled ||
|
|
2829
|
+
([_observedPageKey isEqualToString:self.currentPageKey] &&
|
|
2830
|
+
_observedPageIndex == _currentIndex && _observedPageGeneration == _generation))) {
|
|
2689
2831
|
_needsScrollObserverReattachAfterMount = NO;
|
|
2832
|
+
if ([_pendingPageRestoreKeys containsObject:self.currentPageKey]) {
|
|
2833
|
+
[self applyInsetsToScrollView:candidate pageIndex:_currentIndex restore:YES];
|
|
2834
|
+
}
|
|
2690
2835
|
[self attachSharedHeadersToScrollView:candidate];
|
|
2691
2836
|
[self updateSharedHeaderPressCancellationGesture];
|
|
2692
2837
|
return;
|
|
2693
2838
|
}
|
|
2694
2839
|
|
|
2695
|
-
|
|
2840
|
+
[self offsetDiag:@"observer-candidate" page:_currentIndex scroll:candidate];
|
|
2841
|
+
BOOL replacingCurrentScrollView = _observingContentOffset &&
|
|
2842
|
+
(!_nativeSmoothHeaderScrollEnabled || [_observedPageKey isEqualToString:self.currentPageKey]);
|
|
2696
2843
|
[self detachScrollObserver];
|
|
2697
2844
|
if (replacingCurrentScrollView) {
|
|
2698
|
-
//
|
|
2699
|
-
|
|
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];
|
|
2700
2849
|
}
|
|
2701
2850
|
_observedScrollView = candidate;
|
|
2851
|
+
_observedPageKey = [self.currentPageKey copy];
|
|
2852
|
+
_observedPageIndex = _currentIndex;
|
|
2853
|
+
_observedPageGeneration = _generation;
|
|
2854
|
+
[self offsetDiag:@"observer-attached-before-restore" page:_currentIndex scroll:candidate];
|
|
2702
2855
|
[self applyInsetsToScrollView:candidate pageIndex:_currentIndex restore:YES];
|
|
2703
2856
|
[candidate addObserver:self
|
|
2704
2857
|
forKeyPath:@"contentOffset"
|
|
@@ -2725,7 +2878,17 @@ static void RNCLogNativeTabScrollBoundary(NSString *owner,
|
|
|
2725
2878
|
UIScrollView *scrollView = _observedScrollView;
|
|
2726
2879
|
if (scrollView != nil) {
|
|
2727
2880
|
[scrollView.panGestureRecognizer removeTarget:self action:@selector(observedListPanChanged:)];
|
|
2728
|
-
|
|
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];
|
|
2729
2892
|
if (_observingContentOffset) {
|
|
2730
2893
|
[scrollView removeObserver:self
|
|
2731
2894
|
forKeyPath:@"contentOffset"
|
|
@@ -2740,6 +2903,8 @@ static void RNCLogNativeTabScrollBoundary(NSString *owner,
|
|
|
2740
2903
|
}
|
|
2741
2904
|
_observingContentOffset = NO;
|
|
2742
2905
|
_observedScrollView = nil;
|
|
2906
|
+
_observedPageKey = nil;
|
|
2907
|
+
_observedPageIndex = NSNotFound;
|
|
2743
2908
|
if ([scrollView.superview isKindOfClass:RNCNativeScrollerComponentView.class]) {
|
|
2744
2909
|
[(RNCNativeScrollerComponentView *)scrollView.superview stopScrolling];
|
|
2745
2910
|
}
|
|
@@ -2770,9 +2935,7 @@ static void RNCLogNativeTabScrollBoundary(NSString *owner,
|
|
|
2770
2935
|
{
|
|
2771
2936
|
if (_pagerScrollView != nil && _verticalPagerGesture != nil) {
|
|
2772
2937
|
_verticalPagerGesture.pagerPan = _pagerScrollView.panGestureRecognizer;
|
|
2773
|
-
|
|
2774
|
-
[gesture requireGestureRecognizerToFail:_verticalPagerGesture];
|
|
2775
|
-
}
|
|
2938
|
+
[_pagerScrollView.panGestureRecognizer requireGestureRecognizerToFail:_verticalPagerGesture];
|
|
2776
2939
|
}
|
|
2777
2940
|
}
|
|
2778
2941
|
|
|
@@ -3012,7 +3175,9 @@ static void RNCLogNativeTabScrollBoundary(NSString *owner,
|
|
|
3012
3175
|
[self releaseRefreshControlForScrollView:scrollView];
|
|
3013
3176
|
if (scrollView == _observedScrollView) {
|
|
3014
3177
|
[self detachScrollObserver];
|
|
3015
|
-
|
|
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];
|
|
3016
3181
|
}
|
|
3017
3182
|
if (scrollView == _sharedHeaderScrollView) {
|
|
3018
3183
|
[self restoreSharedHeadersToContainer];
|
|
@@ -3032,8 +3197,10 @@ static void RNCLogNativeTabScrollBoundary(NSString *owner,
|
|
|
3032
3197
|
[_originalDirectionalLockEnabled objectForKey:scrollView].boolValue;
|
|
3033
3198
|
scrollView.contentInsetAdjustmentBehavior = (UIScrollViewContentInsetAdjustmentBehavior)
|
|
3034
3199
|
[_originalInsetAdjustmentBehavior objectForKey:scrollView].integerValue;
|
|
3200
|
+
[self offsetDiag:@"release-original-offset-before" page:_currentIndex scroll:scrollView];
|
|
3035
3201
|
[scrollView setContentOffset:CGPointMake(scrollView.contentOffset.x, logicalOffset - original.top)
|
|
3036
3202
|
animated:NO];
|
|
3203
|
+
[self offsetDiag:@"release-original-offset-after" page:_currentIndex scroll:scrollView];
|
|
3037
3204
|
[_originalInsets removeObjectForKey:scrollView];
|
|
3038
3205
|
[_appliedTopInsets removeObjectForKey:scrollView];
|
|
3039
3206
|
[_originalIndicatorInsets removeObjectForKey:scrollView];
|
|
@@ -3062,8 +3229,9 @@ static void RNCLogNativeTabScrollBoundary(NSString *owner,
|
|
|
3062
3229
|
pageIndex:(NSInteger)pageIndex
|
|
3063
3230
|
restore:(BOOL)restore
|
|
3064
3231
|
{
|
|
3065
|
-
//
|
|
3066
|
-
//
|
|
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];
|
|
3067
3235
|
NSString *pageKey = [self pageKeyForIndex:pageIndex];
|
|
3068
3236
|
RNCCollapsiblePagerReleasedScrollState *released = _releasedPageScrollStates[pageKey];
|
|
3069
3237
|
BOOL deferredReleasedIdentity = NO;
|
|
@@ -3109,8 +3277,13 @@ static void RNCLogNativeTabScrollBoundary(NSString *owner,
|
|
|
3109
3277
|
deferredReleasedIdentity = now - released.pendingFallbackDetectedAt <
|
|
3110
3278
|
RNCCollapsiblePagerFallbackDebounceInterval;
|
|
3111
3279
|
}
|
|
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
|
|
3112
3283
|
if (!deferredReleasedIdentity) {
|
|
3113
|
-
|
|
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];
|
|
3114
3287
|
[_releasedPageScrollStates removeObjectForKey:pageKey];
|
|
3115
3288
|
}
|
|
3116
3289
|
}
|
|
@@ -3158,7 +3331,9 @@ static void RNCLogNativeTabScrollBoundary(NSString *owner,
|
|
|
3158
3331
|
if (pageIndex == _currentIndex) [self updateHeaderForScrollView:scrollView];
|
|
3159
3332
|
return;
|
|
3160
3333
|
}
|
|
3334
|
+
[self offsetDiag:@"inset-assignment-before" page:pageIndex scroll:scrollView];
|
|
3161
3335
|
scrollView.contentInset = next;
|
|
3336
|
+
[self offsetDiag:@"inset-assignment-after" page:pageIndex scroll:scrollView];
|
|
3162
3337
|
UIEdgeInsets indicatorInsets = scrollView.verticalScrollIndicatorInsets;
|
|
3163
3338
|
indicatorInsets.top = pagerTopInset;
|
|
3164
3339
|
scrollView.verticalScrollIndicatorInsets = indicatorInsets;
|
|
@@ -3166,21 +3341,37 @@ static void RNCLogNativeTabScrollBoundary(NSString *owner,
|
|
|
3166
3341
|
|
|
3167
3342
|
CGFloat targetOffset = previousLogicalOffset - next.top;
|
|
3168
3343
|
if (restore) {
|
|
3169
|
-
NSNumber *saved =
|
|
3344
|
+
NSNumber *saved = _transitionPageOffsets != nil
|
|
3345
|
+
? _transitionPageOffsets[pageKey] : _pageOffsets[pageKey];
|
|
3170
3346
|
// The sticky slot can change height between pages. Cache offsets relative
|
|
3171
3347
|
// to content start so a round trip does not add that height difference.
|
|
3172
|
-
CGFloat restoredLogicalOffset
|
|
3173
|
-
|
|
3174
|
-
|
|
3175
|
-
|
|
3176
|
-
|
|
3177
|
-
|
|
3178
|
-
|
|
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;
|
|
3179
3362
|
}
|
|
3363
|
+
#if DEBUG
|
|
3364
|
+
[self offsetDiag:[NSString stringWithFormat:@"restore-candidate-saved=%.4f-headerAlignedLogical=%.4f", saved.doubleValue, restoredLogicalOffset] page:pageIndex scroll:scrollView];
|
|
3365
|
+
#endif
|
|
3180
3366
|
targetOffset = restoredLogicalOffset - next.top;
|
|
3181
|
-
|
|
3367
|
+
if (!_nativeSmoothHeaderScrollEnabled || _headerHeight <= 0) {
|
|
3368
|
+
targetOffset = MAX(targetOffset, -next.top + _headerOffset);
|
|
3369
|
+
}
|
|
3182
3370
|
// An inactive list may shrink after its offset observer was detached.
|
|
3183
3371
|
// 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
|
|
3184
3375
|
targetOffset = RNCLimitRestoredScrollOffset(
|
|
3185
3376
|
targetOffset,
|
|
3186
3377
|
scrollView.contentSize.height,
|
|
@@ -3189,11 +3380,15 @@ static void RNCLogNativeTabScrollBoundary(NSString *owner,
|
|
|
3189
3380
|
next.bottom
|
|
3190
3381
|
);
|
|
3191
3382
|
}
|
|
3383
|
+
#if DEBUG
|
|
3384
|
+
[self offsetDiag:[NSString stringWithFormat:@"restore-final-target=%.4f-restore=%d", targetOffset, restore] page:pageIndex scroll:scrollView];
|
|
3385
|
+
#endif
|
|
3192
3386
|
// A bottom-inset change must not cancel UIKit's refresh or bounce settlement.
|
|
3193
3387
|
if (restore || previousTopInset != next.top) {
|
|
3194
3388
|
[scrollView setContentOffset:CGPointMake(scrollView.contentOffset.x, targetOffset) animated:NO];
|
|
3195
3389
|
}
|
|
3196
3390
|
if (pageIndex == _currentIndex) [self updateHeaderForScrollView:scrollView];
|
|
3391
|
+
[self offsetDiag:@"restore-post" page:pageIndex scroll:scrollView];
|
|
3197
3392
|
}
|
|
3198
3393
|
|
|
3199
3394
|
- (void)updateNativeScrollerViewport:(UIScrollView *)scrollView stickyHeight:(CGFloat)height
|
|
@@ -3254,10 +3449,24 @@ static void RNCLogNativeTabScrollBoundary(NSString *owner,
|
|
|
3254
3449
|
if (context == RNCScrollRefreshControlContext) {
|
|
3255
3450
|
UIScrollView *scrollView = (UIScrollView *)object;
|
|
3256
3451
|
[self updateRefreshControlForScrollView:scrollView];
|
|
3257
|
-
if (scrollView == _observedScrollView
|
|
3452
|
+
if (scrollView == _observedScrollView && !_syntheticPageRestore &&
|
|
3453
|
+
(!_nativeSmoothHeaderScrollEnabled || (!_transitioning && _transitionPageOffsets == nil))) {
|
|
3454
|
+
[self updateHeaderForScrollView:scrollView];
|
|
3455
|
+
}
|
|
3258
3456
|
return;
|
|
3259
3457
|
}
|
|
3260
3458
|
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
|
+
}
|
|
3261
3470
|
if ([keyPath isEqualToString:@"contentInset"]) {
|
|
3262
3471
|
[self updateHeaderForScrollView:(UIScrollView *)object];
|
|
3263
3472
|
return;
|
|
@@ -3272,7 +3481,14 @@ static void RNCLogNativeTabScrollBoundary(NSString *owner,
|
|
|
3272
3481
|
}
|
|
3273
3482
|
UIScrollView *scrollView = (UIScrollView *)object;
|
|
3274
3483
|
_currentLogicalOffset = scrollView.contentOffset.y + scrollView.contentInset.top;
|
|
3275
|
-
|
|
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
|
|
3276
3492
|
[self updateHeaderForScrollView:scrollView];
|
|
3277
3493
|
return;
|
|
3278
3494
|
}
|
|
@@ -3281,6 +3497,8 @@ static void RNCLogNativeTabScrollBoundary(NSString *owner,
|
|
|
3281
3497
|
|
|
3282
3498
|
- (void)updateHeaderForScrollView:(UIScrollView *)scrollView
|
|
3283
3499
|
{
|
|
3500
|
+
if (_nativeSmoothHeaderScrollEnabled &&
|
|
3501
|
+
(_syntheticPageRestore || _transitionPageOffsets != nil)) return;
|
|
3284
3502
|
CGFloat logicalOffset = scrollView.contentOffset.y + scrollView.contentInset.top;
|
|
3285
3503
|
_currentLogicalOffset = logicalOffset;
|
|
3286
3504
|
_headerOffset = MIN(MAX(logicalOffset, 0), _headerHeight);
|
|
@@ -3324,6 +3542,7 @@ static void RNCLogNativeTabScrollBoundary(NSString *owner,
|
|
|
3324
3542
|
|
|
3325
3543
|
- (void)goTo:(NSInteger)index animated:(BOOL)animated
|
|
3326
3544
|
{
|
|
3545
|
+
[self offsetDiag:@"go-to" page:index scroll:_observedScrollView];
|
|
3327
3546
|
if (_isBeingRecycled || index < 0 || index >= _pageControllers.count) return;
|
|
3328
3547
|
_hasReceivedPageCommand = YES;
|
|
3329
3548
|
_hasAppliedInitialPage = YES;
|
|
@@ -3349,6 +3568,7 @@ static void RNCLogNativeTabScrollBoundary(NSString *owner,
|
|
|
3349
3568
|
return;
|
|
3350
3569
|
}
|
|
3351
3570
|
|
|
3571
|
+
[self beginPageStateTransition];
|
|
3352
3572
|
[self preparePageForHorizontalTransitionAtIndex:index];
|
|
3353
3573
|
_destinationIndex = index;
|
|
3354
3574
|
[self liftSharedHeadersForPagerTransition:@"programmatic"];
|
|
@@ -3368,6 +3588,7 @@ static void RNCLogNativeTabScrollBoundary(NSString *owner,
|
|
|
3368
3588
|
void (^animations)(void) = ^{
|
|
3369
3589
|
[self->_pagerScrollView setContentOffset:CGPointMake(targetOffset, 0)];
|
|
3370
3590
|
[self->_nativeTabBarView setProgress:index];
|
|
3591
|
+
[self updatePageStateTransitionProgress:index];
|
|
3371
3592
|
};
|
|
3372
3593
|
void (^completion)(BOOL) = ^(BOOL finished) {
|
|
3373
3594
|
__strong __typeof__(weakSelf) self = weakSelf;
|
|
@@ -3375,6 +3596,7 @@ static void RNCLogNativeTabScrollBoundary(NSString *owner,
|
|
|
3375
3596
|
self->_transitionId != capturedTransition || self->_isBeingRecycled) return;
|
|
3376
3597
|
self->_pagerScrollView.scrollEnabled = self->_scrollEnabled;
|
|
3377
3598
|
if (finished) {
|
|
3599
|
+
[self detachScrollObserver];
|
|
3378
3600
|
self->_currentIndex = index;
|
|
3379
3601
|
self->_destinationIndex = index;
|
|
3380
3602
|
[self->_nativeTabBarView setProgress:index];
|
|
@@ -3412,6 +3634,7 @@ static void RNCLogNativeTabScrollBoundary(NSString *owner,
|
|
|
3412
3634
|
if (self == nil || self->_generation != capturedGeneration ||
|
|
3413
3635
|
self->_transitionId != capturedTransition || self->_isBeingRecycled) return;
|
|
3414
3636
|
if (finished) {
|
|
3637
|
+
[self detachScrollObserver];
|
|
3415
3638
|
self->_currentIndex = index;
|
|
3416
3639
|
self->_destinationIndex = index;
|
|
3417
3640
|
[self->_nativeTabBarView setProgress:index];
|
|
@@ -3436,6 +3659,7 @@ static void RNCLogNativeTabScrollBoundary(NSString *owner,
|
|
|
3436
3659
|
dispatch_async(dispatch_get_main_queue(), ^{
|
|
3437
3660
|
if (self->_generation != generation || self->_transitionId != transition ||
|
|
3438
3661
|
self->_isBeingRecycled) return;
|
|
3662
|
+
[self finishPageStateTransition];
|
|
3439
3663
|
self->_transitioning = NO;
|
|
3440
3664
|
if (self->_hasPendingDirectNativePagerChange) {
|
|
3441
3665
|
BOOL enabled = self->_pendingDirectNativePagerEnabled;
|
|
@@ -3499,9 +3723,11 @@ static void RNCLogNativeTabScrollBoundary(NSString *owner,
|
|
|
3499
3723
|
|
|
3500
3724
|
- (void)scrollViewWillBeginDragging:(UIScrollView *)scrollView
|
|
3501
3725
|
{
|
|
3726
|
+
[self offsetDiag:@"pager-drag-begin" page:_currentIndex scroll:_observedScrollView];
|
|
3502
3727
|
if (_nativeSmoothHeaderScrollEnabled && scrollView == _pagerScrollView) {
|
|
3503
3728
|
[_contentPressCancellationGesture cancelPressForPan:scrollView.panGestureRecognizer];
|
|
3504
3729
|
}
|
|
3730
|
+
[self beginPageStateTransition];
|
|
3505
3731
|
if (_directNativePagerEnabled) {
|
|
3506
3732
|
[self preparePageForHorizontalTransitionAtIndex:_currentIndex - 1];
|
|
3507
3733
|
[self preparePageForHorizontalTransitionAtIndex:_currentIndex + 1];
|
|
@@ -3653,6 +3879,7 @@ static void RNCLogNativeTabScrollBoundary(NSString *owner,
|
|
|
3653
3879
|
NSInteger position = (NSInteger)floor(progress);
|
|
3654
3880
|
CGFloat offset = progress - position;
|
|
3655
3881
|
position = MAX(0, MIN(position, (NSInteger)_pageControllers.count - 1));
|
|
3882
|
+
[self updatePageStateTransitionProgress:progress];
|
|
3656
3883
|
[_nativeTabBarView setProgress:progress];
|
|
3657
3884
|
const auto emitter = [self eventEmitter];
|
|
3658
3885
|
if (emitter) {
|
|
@@ -3670,6 +3897,7 @@ static void RNCLogNativeTabScrollBoundary(NSString *owner,
|
|
|
3670
3897
|
CGFloat transitionProgress = RNCClamp(fabs(rawOffset), 0, 1);
|
|
3671
3898
|
tabProgress = _currentIndex + (_destinationIndex - _currentIndex) * transitionProgress;
|
|
3672
3899
|
}
|
|
3900
|
+
[self updatePageStateTransitionProgress:tabProgress];
|
|
3673
3901
|
[_nativeTabBarView setProgress:tabProgress];
|
|
3674
3902
|
const auto emitter = [self eventEmitter];
|
|
3675
3903
|
if (emitter) {
|
|
@@ -3687,6 +3915,7 @@ static void RNCLogNativeTabScrollBoundary(NSString *owner,
|
|
|
3687
3915
|
|
|
3688
3916
|
- (void)emitPageSelected:(NSInteger)position
|
|
3689
3917
|
{
|
|
3918
|
+
[self offsetDiag:@"selection-complete" page:position scroll:_observedScrollView];
|
|
3690
3919
|
const auto emitter = [self eventEmitter];
|
|
3691
3920
|
if (emitter) emitter->onPageSelected({.position = (double)position});
|
|
3692
3921
|
}
|
|
@@ -33,6 +33,9 @@ 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
|
|
36
39
|
RNCNativeScrollerShadowNode::ConcreteState::Shared _state;
|
|
37
40
|
RNCNativeVerticalScrollView *_scrollView;
|
|
38
41
|
UIView<RCTComponentViewProtocol> *_reactContent;
|
|
@@ -51,6 +54,24 @@ static Event RNCScrollerMetrics(UIScrollView *scroll, CGPoint velocity, CGPoint
|
|
|
51
54
|
NSNumber *_lastContentViewportHeight;
|
|
52
55
|
}
|
|
53
56
|
|
|
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
|
+
|
|
54
75
|
+ (ComponentDescriptorProvider)componentDescriptorProvider
|
|
55
76
|
{
|
|
56
77
|
return concreteComponentDescriptorProvider<RNCNativeScrollerComponentDescriptor>();
|
|
@@ -179,7 +200,9 @@ static Event RNCScrollerMetrics(UIScrollView *scroll, CGPoint velocity, CGPoint
|
|
|
179
200
|
_needsContentClamp |= size.height < _scrollView.contentSize.height;
|
|
180
201
|
CGPoint offset = _scrollView.contentOffset;
|
|
181
202
|
BOOL wasPulling = offset.y < -_scrollView.adjustedContentInset.top;
|
|
203
|
+
[self offsetDiag:@"content-size-before"];
|
|
182
204
|
_scrollView.contentSize = size;
|
|
205
|
+
[self offsetDiag:@"content-size-after"];
|
|
183
206
|
// UIKit can synchronously discard a pull when content becomes empty.
|
|
184
207
|
// Upper-range shrink correction remains owned by the deferred clamp.
|
|
185
208
|
if (wasPulling && _scrollView.contentOffset.y != offset.y) {
|
|
@@ -197,10 +220,12 @@ static Event RNCScrollerMetrics(UIScrollView *scroll, CGPoint velocity, CGPoint
|
|
|
197
220
|
- (void)updateLayoutMetrics:(const LayoutMetrics &)layoutMetrics
|
|
198
221
|
oldLayoutMetrics:(const LayoutMetrics &)oldLayoutMetrics
|
|
199
222
|
{
|
|
223
|
+
[self offsetDiag:@"layout-before"];
|
|
200
224
|
CGSize previous = _scrollView.bounds.size;
|
|
201
225
|
[super updateLayoutMetrics:layoutMetrics oldLayoutMetrics:oldLayoutMetrics];
|
|
202
226
|
[self updateFabricContentOrigin];
|
|
203
227
|
[self emitContentViewportChangeIfNeeded];
|
|
228
|
+
[self offsetDiag:@"layout-after"];
|
|
204
229
|
if (!CGSizeEqualToSize(previous, _scrollView.bounds.size)) {
|
|
205
230
|
_needsContentClamp = YES;
|
|
206
231
|
[self scheduleContentClamp];
|
|
@@ -263,6 +288,7 @@ static Event RNCScrollerMetrics(UIScrollView *scroll, CGPoint velocity, CGPoint
|
|
|
263
288
|
- (void)scheduleContentClamp
|
|
264
289
|
{
|
|
265
290
|
if (!_needsContentClamp) return;
|
|
291
|
+
[self offsetDiag:@"clamp-scheduled"];
|
|
266
292
|
NSUInteger generation = _generation;
|
|
267
293
|
__weak __typeof__(self) weakSelf = self;
|
|
268
294
|
dispatch_async(dispatch_get_main_queue(), ^{
|
|
@@ -274,13 +300,19 @@ static Event RNCScrollerMetrics(UIScrollView *scroll, CGPoint velocity, CGPoint
|
|
|
274
300
|
|
|
275
301
|
- (void)clampContentOffsetIfNeeded
|
|
276
302
|
{
|
|
303
|
+
[self offsetDiag:@"clamp-enter-or-deferred"];
|
|
277
304
|
if (!_needsContentClamp || _scrollView.dragging || _scrollView.decelerating ||
|
|
278
305
|
_refreshControl.refreshing || _scrollView.bounds.size.height <= 0) return;
|
|
279
306
|
_needsContentClamp = NO;
|
|
280
307
|
CGFloat maximum = MAX(-_scrollView.adjustedContentInset.top,
|
|
281
308
|
_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
|
|
282
312
|
if (_scrollView.contentOffset.y > maximum) {
|
|
313
|
+
[self offsetDiag:@"clamp-applied-before"];
|
|
283
314
|
[_scrollView setContentOffset:CGPointMake(_scrollView.contentOffset.x, maximum) animated:NO];
|
|
315
|
+
[self offsetDiag:@"clamp-applied-after"];
|
|
284
316
|
}
|
|
285
317
|
}
|
|
286
318
|
|
|
@@ -319,6 +351,7 @@ static Event RNCScrollerMetrics(UIScrollView *scroll, CGPoint velocity, CGPoint
|
|
|
319
351
|
- (void)stopScrolling
|
|
320
352
|
{
|
|
321
353
|
if (_stopping) return;
|
|
354
|
+
[self offsetDiag:@"stop-before"];
|
|
322
355
|
_stopping = YES;
|
|
323
356
|
[_scrollView setContentOffset:_scrollView.contentOffset animated:NO];
|
|
324
357
|
if (_dragActive) {
|
|
@@ -330,6 +363,7 @@ static Event RNCScrollerMetrics(UIScrollView *scroll, CGPoint velocity, CGPoint
|
|
|
330
363
|
}
|
|
331
364
|
[self finishMomentum];
|
|
332
365
|
_stopping = NO;
|
|
366
|
+
[self offsetDiag:@"stop-after"];
|
|
333
367
|
}
|
|
334
368
|
|
|
335
369
|
- (void)scrollViewWillBeginDragging:(UIScrollView *)scrollView
|