@onekeyfe/react-native-pager-view 3.0.122 → 3.0.124
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 +233 -55
- package/android/src/main/java/com/reactnativepagerview/CollapsiblePagerViewManager.kt +15 -0
- package/ios/RNCCollapsiblePagerViewComponentView.mm +218 -13
- package/lib/module/CollapsiblePagerView.js +30 -0
- package/lib/module/NativeScroller.js +26 -0
- package/lib/module/NativeScroller.web.js +25 -0
- package/lib/module/index.js +1 -0
- package/lib/module/index.web.js +1 -0
- package/lib/typescript/src/CollapsiblePagerView.d.ts +4 -0
- package/lib/typescript/src/NativeScroller.d.ts +12 -0
- package/lib/typescript/src/NativeScroller.web.d.ts +5 -0
- package/lib/typescript/src/index.d.ts +1 -0
- package/lib/typescript/src/index.web.d.ts +1 -0
- package/package.json +2 -2
- package/src/CollapsiblePagerView.tsx +50 -0
- package/src/NativeScroller.tsx +35 -0
- package/src/NativeScroller.web.tsx +31 -0
- package/src/index.tsx +1 -0
- package/src/index.web.tsx +1 -0
|
@@ -6,12 +6,16 @@
|
|
|
6
6
|
#import <react/renderer/components/pagerview/RCTComponentViewHelpers.h>
|
|
7
7
|
|
|
8
8
|
#import "React/RCTConversions.h"
|
|
9
|
+
#import "React/RCTMountingTransactionObserving.h"
|
|
10
|
+
#import "React/RCTScrollViewComponentView.h"
|
|
9
11
|
#import "React/RCTSurfaceTouchHandler.h"
|
|
10
12
|
#import "React/RCTTouchHandler.h"
|
|
11
13
|
|
|
12
14
|
using namespace facebook::react;
|
|
13
15
|
|
|
14
16
|
static void *RNCCollapsiblePagerContentOffsetContext = &RNCCollapsiblePagerContentOffsetContext;
|
|
17
|
+
static NSString *const RNCCollapsiblePagerNativeScrollerIDPrefix =
|
|
18
|
+
@"rnc-collapsible-pager-native-scroller:";
|
|
15
19
|
|
|
16
20
|
typedef void (^RNCCollapsiblePagerNativeTabPressHandler)(NSInteger index, NSString *key);
|
|
17
21
|
|
|
@@ -825,6 +829,22 @@ static void RNCLogNativeTabScrollBoundary(NSString *owner,
|
|
|
825
829
|
|
|
826
830
|
- (BOOL)gestureRecognizerShouldBegin:(UIGestureRecognizer *)gestureRecognizer
|
|
827
831
|
{
|
|
832
|
+
if (gestureRecognizer == self.panGestureRecognizer) {
|
|
833
|
+
UIPanGestureRecognizer *pan = self.panGestureRecognizer;
|
|
834
|
+
CGPoint translation = [pan translationInView:self];
|
|
835
|
+
CGPoint velocity = [pan velocityInView:self];
|
|
836
|
+
CGPoint intent = fabs(translation.x) + fabs(translation.y) >= 1
|
|
837
|
+
? translation
|
|
838
|
+
: velocity;
|
|
839
|
+
BOOL hasMotion = MAX(fabs(intent.x), fabs(intent.y)) >= 1;
|
|
840
|
+
if (hasMotion && fabs(intent.y) > fabs(intent.x)) {
|
|
841
|
+
RNCCollapsiblePagerLog([NSString stringWithFormat:
|
|
842
|
+
@"pager-axis dx=%.2f dy=%.2f result=vertical-rejected",
|
|
843
|
+
intent.x,
|
|
844
|
+
intent.y]);
|
|
845
|
+
return NO;
|
|
846
|
+
}
|
|
847
|
+
}
|
|
828
848
|
if (gestureRecognizer == self.panGestureRecognizer && self.excludedHeaderView != nil) {
|
|
829
849
|
CGPoint point = [gestureRecognizer locationInView:self.excludedHeaderView];
|
|
830
850
|
if ([self.excludedHeaderView hitTest:point withEvent:nil] != nil) {
|
|
@@ -895,7 +915,8 @@ static void RNCLogNativeTabScrollBoundary(NSString *owner,
|
|
|
895
915
|
UIPageViewControllerDataSource,
|
|
896
916
|
UIPageViewControllerDelegate,
|
|
897
917
|
UIScrollViewDelegate,
|
|
898
|
-
UIGestureRecognizerDelegate
|
|
918
|
+
UIGestureRecognizerDelegate,
|
|
919
|
+
RCTMountingTransactionObserving
|
|
899
920
|
>
|
|
900
921
|
- (void)finishPagerScrollEmittingSelection:(BOOL)emitSelection;
|
|
901
922
|
- (void)completeTransitionOnNextRunLoopForGeneration:(NSUInteger)generation
|
|
@@ -905,6 +926,12 @@ static void RNCLogNativeTabScrollBoundary(NSString *owner,
|
|
|
905
926
|
- (void)liftSharedHeadersForPagerTransition:(NSString *)reason;
|
|
906
927
|
- (void)restoreSharedHeadersToContainer;
|
|
907
928
|
- (void)layoutSharedHeaders;
|
|
929
|
+
- (UIScrollView *)currentVerticalScrollViewForParentPager;
|
|
930
|
+
- (UIScrollView *)verticalScrollViewForPageAtIndex:(NSInteger)pageIndex;
|
|
931
|
+
- (UIScrollView *)findExplicitNativeScrollerInView:(UIView *)view;
|
|
932
|
+
- (UIScrollView *)findFabricScrollViewInView:(UIView *)view;
|
|
933
|
+
- (UIScrollView *)findVerticalScrollViewInView:(UIView *)view;
|
|
934
|
+
- (void)scheduleScrollObserverRetryForCurrentPage;
|
|
908
935
|
- (void)preparePageForHorizontalTransitionAtIndex:(NSInteger)pageIndex;
|
|
909
936
|
- (void)updateSharedHeaderPressCancellationGesture;
|
|
910
937
|
- (void)detachSharedHeaderPressCancellationGesture;
|
|
@@ -964,12 +991,18 @@ static void RNCLogNativeTabScrollBoundary(NSString *owner,
|
|
|
964
991
|
NSMapTable<UIScrollView *, NSNumber *> *_originalInsetAdjustmentBehavior;
|
|
965
992
|
__weak UIScrollView *_observedScrollView;
|
|
966
993
|
__weak UIScrollView *_sharedHeaderScrollView;
|
|
994
|
+
__weak UIScrollView *_pendingFallbackScrollView;
|
|
967
995
|
__weak UIView *_sharedHeaderPressCancellationGestureHost;
|
|
968
996
|
__weak UIGestureRecognizer *_reactTouchHandler;
|
|
969
997
|
UIPanGestureRecognizer *_sharedHeaderPressCancellationGesture;
|
|
970
998
|
RNCCollapsiblePagerOuterPagerPanGestureRecognizer *_sharedHeaderOuterPagerGesture;
|
|
971
999
|
UIPanGestureRecognizer *_verticalPagerGesture;
|
|
972
1000
|
BOOL _observingContentOffset;
|
|
1001
|
+
BOOL _scrollResolveRetryScheduled;
|
|
1002
|
+
CFTimeInterval _pendingFallbackScrollViewDetectedAt;
|
|
1003
|
+
NSInteger _scrollResolveRetryPageIndex;
|
|
1004
|
+
NSInteger _scrollResolveRetryAttempt;
|
|
1005
|
+
NSUInteger _scrollResolveRetryToken;
|
|
973
1006
|
CGFloat _currentLogicalOffset;
|
|
974
1007
|
CGFloat _observedListPanStartLogicalOffset;
|
|
975
1008
|
BOOL _sharedHeadersLiftedForPagerTransition;
|
|
@@ -1010,6 +1043,7 @@ static void RNCLogNativeTabScrollBoundary(NSString *owner,
|
|
|
1010
1043
|
_hasPendingDirectNativePagerChange = NO;
|
|
1011
1044
|
_pendingGoToIndex = -1;
|
|
1012
1045
|
_pendingGoToAnimated = YES;
|
|
1046
|
+
_scrollResolveRetryPageIndex = NSNotFound;
|
|
1013
1047
|
_hasAppliedInitialPage = NO;
|
|
1014
1048
|
_needsPropsReapply = YES;
|
|
1015
1049
|
_layoutDirection = @"ltr";
|
|
@@ -1067,6 +1101,18 @@ static void RNCLogNativeTabScrollBoundary(NSString *owner,
|
|
|
1067
1101
|
return self;
|
|
1068
1102
|
}
|
|
1069
1103
|
|
|
1104
|
+
- (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event
|
|
1105
|
+
{
|
|
1106
|
+
if (_nativeSmoothHeaderScrollEnabled && !_isBeingRecycled &&
|
|
1107
|
+
_sharedHeaderHostView.superview != _containerView) {
|
|
1108
|
+
CGPoint headerPoint = [_sharedHeaderHostView convertPoint:point fromView:self];
|
|
1109
|
+
UIView *headerHitView =
|
|
1110
|
+
[_sharedHeaderHostView hitTest:headerPoint withEvent:event];
|
|
1111
|
+
if (headerHitView != nil) return headerHitView;
|
|
1112
|
+
}
|
|
1113
|
+
return [super hitTest:point withEvent:event];
|
|
1114
|
+
}
|
|
1115
|
+
|
|
1070
1116
|
- (void)willMoveToSuperview:(UIView *)newSuperview
|
|
1071
1117
|
{
|
|
1072
1118
|
[super willMoveToSuperview:newSuperview];
|
|
@@ -1224,6 +1270,14 @@ static void RNCLogNativeTabScrollBoundary(NSString *owner,
|
|
|
1224
1270
|
{
|
|
1225
1271
|
if (!_nativeSmoothHeaderScrollEnabled || _transitioning || _isPagerDragging ||
|
|
1226
1272
|
scrollView == nil || _isBeingRecycled) return;
|
|
1273
|
+
if ((UIView *)scrollView == _sharedHeaderHostView ||
|
|
1274
|
+
[scrollView isDescendantOfView:_sharedHeaderHostView]) {
|
|
1275
|
+
[self restoreSharedHeadersToContainer];
|
|
1276
|
+
RNCCollapsiblePagerLog([NSString stringWithFormat:
|
|
1277
|
+
@"header-owner=pager page=%ld reason=cycle-guard",
|
|
1278
|
+
(long)_currentIndex]);
|
|
1279
|
+
return;
|
|
1280
|
+
}
|
|
1227
1281
|
if (_sharedHeaderScrollView == scrollView &&
|
|
1228
1282
|
_sharedHeaderHostView.superview == scrollView) {
|
|
1229
1283
|
[self layoutSharedHeaders];
|
|
@@ -1240,8 +1294,12 @@ static void RNCLogNativeTabScrollBoundary(NSString *owner,
|
|
|
1240
1294
|
[_nativeSubHeaderView updateAncestorGesturePrecedence];
|
|
1241
1295
|
_currentLogicalOffset = scrollView.contentOffset.y + scrollView.contentInset.top;
|
|
1242
1296
|
[self layoutSharedHeaders];
|
|
1297
|
+
NSString *scrollKind = [scrollView isKindOfClass:UICollectionView.class]
|
|
1298
|
+
? @"list"
|
|
1299
|
+
: @"scroller";
|
|
1243
1300
|
RNCCollapsiblePagerLog([NSString stringWithFormat:
|
|
1244
|
-
@"header-owner
|
|
1301
|
+
@"header-owner=%@ page=%ld offset=%.2f",
|
|
1302
|
+
scrollKind,
|
|
1245
1303
|
(long)_currentIndex,
|
|
1246
1304
|
_currentLogicalOffset]);
|
|
1247
1305
|
}
|
|
@@ -1282,13 +1340,15 @@ static void RNCLogNativeTabScrollBoundary(NSString *owner,
|
|
|
1282
1340
|
CGFloat stickyY = _headerHeight;
|
|
1283
1341
|
_headerView.frame = CGRectMake(0, 0, width, _headerHeight);
|
|
1284
1342
|
_stickyHeaderView.frame = CGRectMake(0, stickyY, width, _stickyHeaderHeight);
|
|
1343
|
+
CGFloat nativeTabBarVisibleHeight = _nativeTabBarView.hidden
|
|
1344
|
+
? 0
|
|
1345
|
+
: MIN(_stickyHeaderHeight, _nativeTabBarHeight);
|
|
1285
1346
|
_nativeTabBarView.frame = CGRectMake(
|
|
1286
1347
|
0,
|
|
1287
1348
|
stickyY,
|
|
1288
1349
|
width,
|
|
1289
|
-
|
|
1350
|
+
nativeTabBarVisibleHeight
|
|
1290
1351
|
);
|
|
1291
|
-
CGFloat nativeTabBarVisibleHeight = CGRectGetHeight(_nativeTabBarView.frame);
|
|
1292
1352
|
_nativeSubHeaderView.frame = CGRectMake(
|
|
1293
1353
|
0,
|
|
1294
1354
|
stickyY + nativeTabBarVisibleHeight,
|
|
@@ -1307,7 +1367,7 @@ static void RNCLogNativeTabScrollBoundary(NSString *owner,
|
|
|
1307
1367
|
pageIndex < 0 || pageIndex >= _pageControllers.count) return;
|
|
1308
1368
|
|
|
1309
1369
|
_pageOffsets[[self pageKeyForIndex:pageIndex]] = @(_headerOffset);
|
|
1310
|
-
UIScrollView *scrollView = [self
|
|
1370
|
+
UIScrollView *scrollView = [self verticalScrollViewForPageAtIndex:pageIndex];
|
|
1311
1371
|
if (scrollView != nil && scrollView != _observedScrollView) {
|
|
1312
1372
|
[self applyInsetsToScrollView:scrollView pageIndex:pageIndex restore:YES];
|
|
1313
1373
|
}
|
|
@@ -1315,6 +1375,25 @@ static void RNCLogNativeTabScrollBoundary(NSString *owner,
|
|
|
1315
1375
|
|
|
1316
1376
|
#pragma mark - React mounting
|
|
1317
1377
|
|
|
1378
|
+
- (void)mountingTransactionDidMount:(const MountingTransaction &)transaction
|
|
1379
|
+
withSurfaceTelemetry:(const SurfaceTelemetry &)surfaceTelemetry
|
|
1380
|
+
{
|
|
1381
|
+
if (!_nativeSmoothHeaderScrollEnabled || _transitioning ||
|
|
1382
|
+
_isPagerDragging || _isBeingRecycled || self.window == nil ||
|
|
1383
|
+
_currentIndex < 0 || _currentIndex >= _pageControllers.count) return;
|
|
1384
|
+
|
|
1385
|
+
UIView *pageView = _pageControllers[_currentIndex].view;
|
|
1386
|
+
BOOL shouldResolve = _observedScrollView == nil ||
|
|
1387
|
+
![_observedScrollView isDescendantOfView:pageView];
|
|
1388
|
+
if (!shouldResolve &&
|
|
1389
|
+
[_observedScrollView isKindOfClass:UICollectionView.class]) {
|
|
1390
|
+
UIScrollView *preferred = [self findExplicitNativeScrollerInView:pageView];
|
|
1391
|
+
if (preferred == nil) preferred = [self findFabricScrollViewInView:pageView];
|
|
1392
|
+
shouldResolve = preferred != nil && preferred != _observedScrollView;
|
|
1393
|
+
}
|
|
1394
|
+
if (shouldResolve) [self attachScrollObserverForCurrentPage];
|
|
1395
|
+
}
|
|
1396
|
+
|
|
1318
1397
|
- (void)mountChildComponentView:(UIView<RCTComponentViewProtocol> *)childComponentView
|
|
1319
1398
|
index:(NSInteger)index
|
|
1320
1399
|
{
|
|
@@ -1738,17 +1817,89 @@ static void RNCLogNativeTabScrollBoundary(NSString *owner,
|
|
|
1738
1817
|
return [NSString stringWithFormat:@"page-%ld", (long)index];
|
|
1739
1818
|
}
|
|
1740
1819
|
|
|
1820
|
+
- (UIScrollView *)currentVerticalScrollViewForParentPager
|
|
1821
|
+
{
|
|
1822
|
+
return [self verticalScrollViewForPageAtIndex:_currentIndex];
|
|
1823
|
+
}
|
|
1824
|
+
|
|
1825
|
+
- (UIScrollView *)verticalScrollViewForPageAtIndex:(NSInteger)pageIndex
|
|
1826
|
+
{
|
|
1827
|
+
if (pageIndex < 0 || pageIndex >= _pageControllers.count) return nil;
|
|
1828
|
+
UIView *pageView = _pageControllers[pageIndex].view;
|
|
1829
|
+
UIScrollView *explicitScroller = [self findExplicitNativeScrollerInView:pageView];
|
|
1830
|
+
if (explicitScroller != nil) return explicitScroller;
|
|
1831
|
+
UIScrollView *fabricScrollView = [self findFabricScrollViewInView:pageView];
|
|
1832
|
+
return fabricScrollView ?: [self findVerticalScrollViewInView:pageView];
|
|
1833
|
+
}
|
|
1834
|
+
|
|
1835
|
+
- (UIScrollView *)findExplicitNativeScrollerInView:(UIView *)view
|
|
1836
|
+
{
|
|
1837
|
+
if (view == _sharedHeaderHostView) return nil;
|
|
1838
|
+
if (view != self &&
|
|
1839
|
+
[view isKindOfClass:RNCCollapsiblePagerViewComponentView.class]) {
|
|
1840
|
+
return [(RNCCollapsiblePagerViewComponentView *)view
|
|
1841
|
+
currentVerticalScrollViewForParentPager];
|
|
1842
|
+
}
|
|
1843
|
+
if ([view isKindOfClass:RCTScrollViewComponentView.class]) {
|
|
1844
|
+
RCTScrollViewComponentView *componentView =
|
|
1845
|
+
(RCTScrollViewComponentView *)view;
|
|
1846
|
+
if ([componentView.nativeId hasPrefix:RNCCollapsiblePagerNativeScrollerIDPrefix]) {
|
|
1847
|
+
return componentView.scrollView;
|
|
1848
|
+
}
|
|
1849
|
+
}
|
|
1850
|
+
for (UIView *subview in view.subviews) {
|
|
1851
|
+
UIScrollView *candidate = [self findExplicitNativeScrollerInView:subview];
|
|
1852
|
+
if (candidate != nil) return candidate;
|
|
1853
|
+
}
|
|
1854
|
+
return nil;
|
|
1855
|
+
}
|
|
1856
|
+
|
|
1857
|
+
- (UIScrollView *)findFabricScrollViewInView:(UIView *)view
|
|
1858
|
+
{
|
|
1859
|
+
if (view == _sharedHeaderHostView) return nil;
|
|
1860
|
+
if (view != self &&
|
|
1861
|
+
[view isKindOfClass:RNCCollapsiblePagerViewComponentView.class]) {
|
|
1862
|
+
return [(RNCCollapsiblePagerViewComponentView *)view
|
|
1863
|
+
currentVerticalScrollViewForParentPager];
|
|
1864
|
+
}
|
|
1865
|
+
if ([view isKindOfClass:RCTScrollViewComponentView.class]) {
|
|
1866
|
+
UIScrollView *scrollView =
|
|
1867
|
+
((RCTScrollViewComponentView *)view).scrollView;
|
|
1868
|
+
if (!scrollView.alwaysBounceHorizontal) {
|
|
1869
|
+
return scrollView;
|
|
1870
|
+
}
|
|
1871
|
+
}
|
|
1872
|
+
for (UIView *subview in view.subviews) {
|
|
1873
|
+
UIScrollView *candidate = [self findFabricScrollViewInView:subview];
|
|
1874
|
+
if (candidate != nil) return candidate;
|
|
1875
|
+
}
|
|
1876
|
+
return nil;
|
|
1877
|
+
}
|
|
1878
|
+
|
|
1741
1879
|
- (UIScrollView *)findVerticalScrollViewInView:(UIView *)view
|
|
1742
1880
|
{
|
|
1881
|
+
if (view == _sharedHeaderHostView) return nil;
|
|
1882
|
+
// A parent pager must follow the nested pager's active page instead of the
|
|
1883
|
+
// first retained page found by recursive subview order.
|
|
1884
|
+
if (view != self &&
|
|
1885
|
+
[view isKindOfClass:RNCCollapsiblePagerViewComponentView.class]) {
|
|
1886
|
+
UIScrollView *nestedScrollView =
|
|
1887
|
+
[(RNCCollapsiblePagerViewComponentView *)view
|
|
1888
|
+
currentVerticalScrollViewForParentPager];
|
|
1889
|
+
if (nestedScrollView != nil) return nestedScrollView;
|
|
1890
|
+
}
|
|
1743
1891
|
if ([view isKindOfClass:UICollectionView.class]) {
|
|
1744
1892
|
UICollectionView *collectionView = (UICollectionView *)view;
|
|
1745
1893
|
UICollectionViewLayout *layout = collectionView.collectionViewLayout;
|
|
1746
|
-
|
|
1747
|
-
|
|
1894
|
+
BOOL hasUsableBounds = CGRectGetWidth(collectionView.bounds) > 0 &&
|
|
1895
|
+
CGRectGetHeight(collectionView.bounds) > 0;
|
|
1896
|
+
if (hasUsableBounds &&
|
|
1897
|
+
(![layout isKindOfClass:UICollectionViewFlowLayout.class] ||
|
|
1898
|
+
((UICollectionViewFlowLayout *)layout).scrollDirection == UICollectionViewScrollDirectionVertical)) {
|
|
1748
1899
|
return collectionView;
|
|
1749
1900
|
}
|
|
1750
1901
|
}
|
|
1751
|
-
//
|
|
1902
|
+
// Preserve compatibility with non-Fabric or custom vertical scroll views.
|
|
1752
1903
|
if ([view isKindOfClass:UIScrollView.class] &&
|
|
1753
1904
|
![view isKindOfClass:UICollectionView.class]) {
|
|
1754
1905
|
UIScrollView *scrollView = (UIScrollView *)view;
|
|
@@ -1764,12 +1915,66 @@ static void RNCLogNativeTabScrollBoundary(NSString *owner,
|
|
|
1764
1915
|
return nil;
|
|
1765
1916
|
}
|
|
1766
1917
|
|
|
1918
|
+
- (void)scheduleScrollObserverRetryForCurrentPage
|
|
1919
|
+
{
|
|
1920
|
+
if (_scrollResolveRetryScheduled || _scrollResolveRetryAttempt >= 12 ||
|
|
1921
|
+
_isBeingRecycled) return;
|
|
1922
|
+
_scrollResolveRetryScheduled = YES;
|
|
1923
|
+
_scrollResolveRetryPageIndex = _currentIndex;
|
|
1924
|
+
_scrollResolveRetryAttempt += 1;
|
|
1925
|
+
NSUInteger token = _scrollResolveRetryToken;
|
|
1926
|
+
NSUInteger generation = _generation;
|
|
1927
|
+
NSInteger pageIndex = _currentIndex;
|
|
1928
|
+
dispatch_after(
|
|
1929
|
+
// Fabric can mount a recycled child's native view before attaching its
|
|
1930
|
+
// replacement ScrollView component. Let that transaction settle before
|
|
1931
|
+
// accepting an automatically discovered UICollectionView fallback.
|
|
1932
|
+
dispatch_time(DISPATCH_TIME_NOW, (int64_t)(100 * NSEC_PER_MSEC)),
|
|
1933
|
+
dispatch_get_main_queue(),
|
|
1934
|
+
^{
|
|
1935
|
+
if (self->_scrollResolveRetryToken != token) return;
|
|
1936
|
+
self->_scrollResolveRetryScheduled = NO;
|
|
1937
|
+
if (self->_isBeingRecycled || self->_generation != generation ||
|
|
1938
|
+
self->_currentIndex != pageIndex) return;
|
|
1939
|
+
[self attachScrollObserverForCurrentPage];
|
|
1940
|
+
}
|
|
1941
|
+
);
|
|
1942
|
+
}
|
|
1943
|
+
|
|
1767
1944
|
- (void)attachScrollObserverForCurrentPage
|
|
1768
1945
|
{
|
|
1769
1946
|
[self restoreDetachedScrollInsets];
|
|
1770
|
-
if (
|
|
1771
|
-
|
|
1772
|
-
|
|
1947
|
+
if (_scrollResolveRetryPageIndex != _currentIndex) {
|
|
1948
|
+
_scrollResolveRetryToken += 1;
|
|
1949
|
+
_scrollResolveRetryScheduled = NO;
|
|
1950
|
+
_scrollResolveRetryAttempt = 0;
|
|
1951
|
+
_scrollResolveRetryPageIndex = _currentIndex;
|
|
1952
|
+
_pendingFallbackScrollView = nil;
|
|
1953
|
+
_pendingFallbackScrollViewDetectedAt = 0;
|
|
1954
|
+
}
|
|
1955
|
+
UIScrollView *candidate = [self verticalScrollViewForPageAtIndex:_currentIndex];
|
|
1956
|
+
if (candidate == nil) {
|
|
1957
|
+
[self scheduleScrollObserverRetryForCurrentPage];
|
|
1958
|
+
return;
|
|
1959
|
+
}
|
|
1960
|
+
if ([candidate isKindOfClass:UICollectionView.class] &&
|
|
1961
|
+
candidate != _observedScrollView) {
|
|
1962
|
+
if (_pendingFallbackScrollView != candidate) {
|
|
1963
|
+
_pendingFallbackScrollView = candidate;
|
|
1964
|
+
_pendingFallbackScrollViewDetectedAt = CACurrentMediaTime();
|
|
1965
|
+
_scrollResolveRetryAttempt = 0;
|
|
1966
|
+
}
|
|
1967
|
+
if (CACurrentMediaTime() - _pendingFallbackScrollViewDetectedAt < 0.5) {
|
|
1968
|
+
[self scheduleScrollObserverRetryForCurrentPage];
|
|
1969
|
+
return;
|
|
1970
|
+
}
|
|
1971
|
+
}
|
|
1972
|
+
_scrollResolveRetryAttempt = 0;
|
|
1973
|
+
_scrollResolveRetryPageIndex = _currentIndex;
|
|
1974
|
+
_scrollResolveRetryToken += 1;
|
|
1975
|
+
_scrollResolveRetryScheduled = NO;
|
|
1976
|
+
_pendingFallbackScrollView = nil;
|
|
1977
|
+
_pendingFallbackScrollViewDetectedAt = 0;
|
|
1773
1978
|
// Legacy mode keeps the historical pager-first dependency. Smooth mode
|
|
1774
1979
|
// arbitrates header touches by axis so the vertical list can begin directly.
|
|
1775
1980
|
if (_pagerScrollView != nil && !_nativeSmoothHeaderScrollEnabled && !_needsPropsReapply) {
|
|
@@ -2153,7 +2358,7 @@ static void RNCLogNativeTabScrollBoundary(NSString *owner,
|
|
|
2153
2358
|
NSInteger last = MIN((NSInteger)_pageControllers.count - 1, _currentIndex + 1);
|
|
2154
2359
|
if (last < first) return;
|
|
2155
2360
|
for (NSInteger index = first; index <= last; index++) {
|
|
2156
|
-
UIScrollView *scrollView = [self
|
|
2361
|
+
UIScrollView *scrollView = [self verticalScrollViewForPageAtIndex:index];
|
|
2157
2362
|
if (scrollView != nil && scrollView != _observedScrollView) {
|
|
2158
2363
|
[self applyInsetsToScrollView:scrollView pageIndex:index restore:YES];
|
|
2159
2364
|
}
|
|
@@ -2356,7 +2561,7 @@ static void RNCLogNativeTabScrollBoundary(NSString *owner,
|
|
|
2356
2561
|
if (index == NSNotFound) return nil;
|
|
2357
2562
|
NSInteger target = index + delta;
|
|
2358
2563
|
if (target < 0 || target >= _pageControllers.count) return nil;
|
|
2359
|
-
UIScrollView *scrollView = [self
|
|
2564
|
+
UIScrollView *scrollView = [self verticalScrollViewForPageAtIndex:target];
|
|
2360
2565
|
if (scrollView != nil) {
|
|
2361
2566
|
[self applyInsetsToScrollView:scrollView pageIndex:target restore:YES];
|
|
2362
2567
|
}
|
|
@@ -30,6 +30,9 @@ export class CollapsiblePagerView extends React.PureComponent {
|
|
|
30
30
|
lastMountSignature = null;
|
|
31
31
|
nativeTabCommandId = 0;
|
|
32
32
|
latestNativeTabTarget = null;
|
|
33
|
+
latestNativeSelectedPage = this.state.selectedPage;
|
|
34
|
+
nativePagerScrollState = "idle";
|
|
35
|
+
nativeTabCommandQueuedDuringScroll = false;
|
|
33
36
|
componentDidMount() {
|
|
34
37
|
this.notifyMountedPagesChanged();
|
|
35
38
|
}
|
|
@@ -77,6 +80,7 @@ export class CollapsiblePagerView extends React.PureComponent {
|
|
|
77
80
|
}
|
|
78
81
|
dispatchNativeTabPageCommand(position, animated) {
|
|
79
82
|
const commandId = ++this.nativeTabCommandId;
|
|
83
|
+
this.nativeTabCommandQueuedDuringScroll = this.nativePagerScrollState !== "idle";
|
|
80
84
|
this.latestNativeTabTarget = position;
|
|
81
85
|
this.setState(state => ({
|
|
82
86
|
transientRetainedPages: state.transientRetainedPages.includes(position) ? state.transientRetainedPages : [...state.transientRetainedPages, position]
|
|
@@ -126,11 +130,13 @@ export class CollapsiblePagerView extends React.PureComponent {
|
|
|
126
130
|
};
|
|
127
131
|
onPageSelected = event => {
|
|
128
132
|
const position = clampedPageIndex(event.nativeEvent.position, this.pages().length);
|
|
133
|
+
this.latestNativeSelectedPage = position;
|
|
129
134
|
if (position !== this.state.selectedPage || this.state.transientRetainedPages.length > 0) {
|
|
130
135
|
const pendingTarget = this.latestNativeTabTarget;
|
|
131
136
|
const transitionComplete = pendingTarget === position;
|
|
132
137
|
if (transitionComplete) {
|
|
133
138
|
this.latestNativeTabTarget = null;
|
|
139
|
+
this.nativeTabCommandQueuedDuringScroll = false;
|
|
134
140
|
}
|
|
135
141
|
this.setState({
|
|
136
142
|
selectedPage: position,
|
|
@@ -139,7 +145,29 @@ export class CollapsiblePagerView extends React.PureComponent {
|
|
|
139
145
|
}
|
|
140
146
|
this.props.onPageSelected?.(event);
|
|
141
147
|
};
|
|
148
|
+
onPageScrollStateChanged = event => {
|
|
149
|
+
const scrollState = event.nativeEvent.pageScrollState;
|
|
150
|
+
const queuedDuringPreviousScroll = this.nativeTabCommandQueuedDuringScroll;
|
|
151
|
+
this.nativePagerScrollState = scrollState;
|
|
152
|
+
// Native drains tab commands queued during an active drag after reporting
|
|
153
|
+
// that drag as idle. Preserve the newer target through that first idle.
|
|
154
|
+
if (scrollState === "idle" && this.latestNativeTabTarget !== null && this.latestNativeTabTarget !== this.latestNativeSelectedPage && !queuedDuringPreviousScroll) {
|
|
155
|
+
++this.nativeTabCommandId;
|
|
156
|
+
this.latestNativeTabTarget = null;
|
|
157
|
+
this.setState({
|
|
158
|
+
transientRetainedPages: []
|
|
159
|
+
}, this.notifyMountedPagesChanged);
|
|
160
|
+
}
|
|
161
|
+
if (scrollState === "idle") {
|
|
162
|
+
this.nativeTabCommandQueuedDuringScroll = false;
|
|
163
|
+
}
|
|
164
|
+
this.props.onPageScrollStateChanged?.(event);
|
|
165
|
+
};
|
|
142
166
|
onNativeTabPress = event => {
|
|
167
|
+
const position = pageIndex(event.nativeEvent.position);
|
|
168
|
+
if (position !== null && position >= 0 && position < this.pages().length && (position !== this.state.selectedPage || this.latestNativeTabTarget !== null)) {
|
|
169
|
+
this.dispatchNativeTabPageCommand(position, true);
|
|
170
|
+
}
|
|
143
171
|
this.props.onNativeTabPress?.(event);
|
|
144
172
|
};
|
|
145
173
|
onNativeSubHeaderPress = event => {
|
|
@@ -156,6 +184,7 @@ export class CollapsiblePagerView extends React.PureComponent {
|
|
|
156
184
|
pageRetentionDistance: _pageRetentionDistance,
|
|
157
185
|
onMountedPagesChanged: _onMountedPagesChanged,
|
|
158
186
|
onPageSelected: _onPageSelected,
|
|
187
|
+
onPageScrollStateChanged: _onPageScrollStateChanged,
|
|
159
188
|
nativeTabBar,
|
|
160
189
|
onNativeTabPress: _onNativeTabPress,
|
|
161
190
|
nativeSubHeader,
|
|
@@ -194,6 +223,7 @@ export class CollapsiblePagerView extends React.PureComponent {
|
|
|
194
223
|
pageKeys: JSON.stringify(pageKeys),
|
|
195
224
|
retainedPages: JSON.stringify([...retained]),
|
|
196
225
|
onPageSelected: this.onPageSelected,
|
|
226
|
+
onPageScrollStateChanged: this.onPageScrollStateChanged,
|
|
197
227
|
nativeTabBarItems: nativeTabBarEnabled ? JSON.stringify(nativeTabBar.items) : undefined,
|
|
198
228
|
nativeTabBarHeight: nativeTabBarEnabled ? nativeTabBarStyle?.height ?? 44 : undefined,
|
|
199
229
|
nativeTabBarContentPaddingHorizontal: nativeTabBarEnabled ? nativeTabBarStyle?.contentPaddingHorizontal ?? 20 : undefined,
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
import * as React from "react";
|
|
4
|
+
import { ScrollView } from "react-native";
|
|
5
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
6
|
+
export const NATIVE_SCROLLER_NATIVE_ID_PREFIX = "rnc-collapsible-pager-native-scroller";
|
|
7
|
+
/**
|
|
8
|
+
* Primary non-virtualized vertical scroller for a CollapsiblePagerView page.
|
|
9
|
+
*/
|
|
10
|
+
export const NativeScroller = /*#__PURE__*/React.forwardRef(function NativeScroller({
|
|
11
|
+
nativeID,
|
|
12
|
+
nestedScrollEnabled = true,
|
|
13
|
+
pagerScrollKey,
|
|
14
|
+
...props
|
|
15
|
+
}, ref) {
|
|
16
|
+
const generatedId = React.useId();
|
|
17
|
+
const scrollKey = pagerScrollKey ?? nativeID ?? generatedId;
|
|
18
|
+
return /*#__PURE__*/_jsx(ScrollView, {
|
|
19
|
+
...props,
|
|
20
|
+
ref: ref,
|
|
21
|
+
nativeID: `${NATIVE_SCROLLER_NATIVE_ID_PREFIX}:${scrollKey}`,
|
|
22
|
+
nestedScrollEnabled: nestedScrollEnabled
|
|
23
|
+
});
|
|
24
|
+
});
|
|
25
|
+
NativeScroller.displayName = "NativeScroller";
|
|
26
|
+
//# sourceMappingURL=NativeScroller.js.map
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
import * as React from "react";
|
|
4
|
+
import { ScrollView } from "react-native";
|
|
5
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
6
|
+
export const NativeScroller = /*#__PURE__*/React.forwardRef(function NativeScroller(inputProps, ref) {
|
|
7
|
+
const {
|
|
8
|
+
dataSet,
|
|
9
|
+
pagerScrollKey: _pagerScrollKey,
|
|
10
|
+
...props
|
|
11
|
+
} = inputProps;
|
|
12
|
+
const webDataProps = {
|
|
13
|
+
dataSet: {
|
|
14
|
+
...dataSet,
|
|
15
|
+
collapsiblePagerScroll: "true"
|
|
16
|
+
}
|
|
17
|
+
};
|
|
18
|
+
return /*#__PURE__*/_jsx(ScrollView, {
|
|
19
|
+
...props,
|
|
20
|
+
ref: ref,
|
|
21
|
+
...webDataProps
|
|
22
|
+
});
|
|
23
|
+
});
|
|
24
|
+
NativeScroller.displayName = "NativeScroller";
|
|
25
|
+
//# sourceMappingURL=NativeScroller.web.js.map
|
package/lib/module/index.js
CHANGED
package/lib/module/index.web.js
CHANGED
|
@@ -100,6 +100,9 @@ export declare class CollapsiblePagerView extends React.PureComponent<Collapsibl
|
|
|
100
100
|
private lastMountSignature;
|
|
101
101
|
private nativeTabCommandId;
|
|
102
102
|
private latestNativeTabTarget;
|
|
103
|
+
private latestNativeSelectedPage;
|
|
104
|
+
private nativePagerScrollState;
|
|
105
|
+
private nativeTabCommandQueuedDuringScroll;
|
|
103
106
|
componentDidMount(): void;
|
|
104
107
|
componentDidUpdate(): void;
|
|
105
108
|
setPage: (selectedPage: number) => void;
|
|
@@ -112,6 +115,7 @@ export declare class CollapsiblePagerView extends React.PureComponent<Collapsibl
|
|
|
112
115
|
private mountedPages;
|
|
113
116
|
private notifyMountedPagesChanged;
|
|
114
117
|
private onPageSelected;
|
|
118
|
+
private onPageScrollStateChanged;
|
|
115
119
|
private onNativeTabPress;
|
|
116
120
|
private onNativeSubHeaderPress;
|
|
117
121
|
render(): import("react/jsx-runtime").JSX.Element;
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import * as React from "react";
|
|
2
|
+
import { type ScrollViewProps } from "react-native";
|
|
3
|
+
export declare const NATIVE_SCROLLER_NATIVE_ID_PREFIX = "rnc-collapsible-pager-native-scroller";
|
|
4
|
+
export interface NativeScrollerProps extends ScrollViewProps {
|
|
5
|
+
/** Stable identity used when a page replaces or remounts its primary scroller. */
|
|
6
|
+
pagerScrollKey?: string;
|
|
7
|
+
}
|
|
8
|
+
/**
|
|
9
|
+
* Primary non-virtualized vertical scroller for a CollapsiblePagerView page.
|
|
10
|
+
*/
|
|
11
|
+
export declare const NativeScroller: React.ForwardRefExoticComponent<NativeScrollerProps & React.RefAttributes<import("react-native/types_generated/Libraries/Components/ScrollView/ScrollView").PublicScrollViewInstance>>;
|
|
12
|
+
//# sourceMappingURL=NativeScroller.d.ts.map
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import * as React from "react";
|
|
2
|
+
import type { NativeScrollerProps } from "./NativeScroller";
|
|
3
|
+
export declare const NativeScroller: React.ForwardRefExoticComponent<NativeScrollerProps & React.RefAttributes<import("react-native/types_generated/Libraries/Components/ScrollView/ScrollView").PublicScrollViewInstance>>;
|
|
4
|
+
export type { NativeScrollerProps } from "./NativeScroller";
|
|
5
|
+
//# sourceMappingURL=NativeScroller.web.d.ts.map
|
|
@@ -3,6 +3,7 @@ import { PagerView } from './PagerView';
|
|
|
3
3
|
export default PagerView;
|
|
4
4
|
export * from './usePagerView';
|
|
5
5
|
export * from './CollapsiblePagerView';
|
|
6
|
+
export * from './NativeScroller';
|
|
6
7
|
import type { OnPageScrollEventData as PagerViewOnPageScrollEventData, OnPageSelectedEventData as PagerViewOnPageSelectedEventData, OnPageScrollStateChangedEventData as PageScrollStateChangedNativeEventData, NativeProps } from './PagerViewNativeComponent';
|
|
7
8
|
export type { PagerViewOnPageScrollEventData, PagerViewOnPageSelectedEventData, PageScrollStateChangedNativeEventData, NativeProps as PagerViewProps, };
|
|
8
9
|
export type PagerViewOnPageScrollEvent = ReactNative.NativeSyntheticEvent<PagerViewOnPageScrollEventData>;
|
|
@@ -2,4 +2,5 @@ export { PagerView as default, PagerView } from "./PagerView.web";
|
|
|
2
2
|
export type { PagerViewProps, PagerViewOnPageScrollEvent, PagerViewOnPageScrollEventData, PagerViewOnPageSelectedEvent, PagerViewOnPageSelectedEventData, PageScrollStateChangedNativeEvent, PageScrollStateChangedNativeEventData, } from "./PagerView.web";
|
|
3
3
|
export * from "./usePagerView";
|
|
4
4
|
export * from "./CollapsiblePagerView.web";
|
|
5
|
+
export * from "./NativeScroller.web";
|
|
5
6
|
//# sourceMappingURL=index.web.d.ts.map
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@onekeyfe/react-native-pager-view",
|
|
3
|
-
"version": "3.0.
|
|
3
|
+
"version": "3.0.124",
|
|
4
4
|
"description": "React Native wrapper for Android and iOS ViewPager",
|
|
5
5
|
"source": "./src/index.tsx",
|
|
6
6
|
"main": "./lib/module/index.js",
|
|
@@ -67,7 +67,7 @@
|
|
|
67
67
|
"typescript": "^5.9.2"
|
|
68
68
|
},
|
|
69
69
|
"peerDependencies": {
|
|
70
|
-
"@onekeyfe/react-native-native-logger": "3.0.
|
|
70
|
+
"@onekeyfe/react-native-native-logger": "3.0.124",
|
|
71
71
|
"react": "*",
|
|
72
72
|
"react-native": "*"
|
|
73
73
|
},
|