@onekeyfe/react-native-pager-view 6.7.0-alpha.399 → 6.7.0-alpha.400

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.
@@ -591,9 +591,29 @@ class CollapsiblePagerHost(context: Context) : NestedScrollableHost(context), Ne
591
591
  cancelPagerTop()
592
592
  if (adapter.itemCount == 0 || !nativeSmoothHeaderScrollEnabled || headerHeightPx <= 0) return
593
593
  if (transitionHeaderOffsets == null) {
594
- transitionSourceDisplayBody = primaryScrollableForPage(selectedPage)?.let(::verticalScrollOffset) ?: 0
595
- transitionSourceRecyclerAnchor = (primaryScrollableForPage(selectedPage) as? RecyclerView)?.let(::captureRecyclerAnchor)
596
- pageHeaderOffsets[currentPageKey()] = headerOffsetPx
594
+ val sourceKey = currentPageKey()
595
+ val sourceView = primaryScrollableForPage(selectedPage)
596
+ val topInset = headerHeightPx + stickyHeaderHeightPx
597
+ val sourceRestored = sourceKey !in pendingPageRestores && when (sourceView) {
598
+ is RecyclerView -> restoredRecyclerKeys[sourceView] == sourceKey &&
599
+ originalRecyclerPadding[sourceView]?.appliedTopInset == topInset
600
+ is ScrollView -> restoredScrollerKeys[sourceView] == sourceKey &&
601
+ originalScrollerPadding[sourceView]?.appliedTopInset == topInset
602
+ is NativeScrollerViewport -> ownedScrollerKeys[sourceView] == sourceKey
603
+ else -> false
604
+ }
605
+ transitionSourceDisplayBody = if (sourceRestored && sourceView != null) {
606
+ verticalScrollOffset(sourceView)
607
+ } else {
608
+ displayBodyOverrides[sourceKey] ?: pageOffsets[sourceKey] ?: 0
609
+ }
610
+ transitionSourceRecyclerAnchor = if (sourceRestored && sourceView is RecyclerView) {
611
+ captureRecyclerAnchor(sourceView)
612
+ } else {
613
+ (displayRecyclerAnchors[sourceKey] ?: recyclerReadingAnchors[sourceKey])
614
+ ?.takeIf { sourceView !is RecyclerView || (it.view.get() === sourceView && it.adapter === sourceView.adapter) }
615
+ }
616
+ pageHeaderOffsets[sourceKey] = headerOffsetPx
597
617
  detachPrimaryScrollObserver()
598
618
  transitionSourcePage = selectedPage
599
619
  transitionHeaderOffsets = pageHeaderOffsets.toMap()
@@ -1684,6 +1704,7 @@ class CollapsiblePagerHost(context: Context) : NestedScrollableHost(context), Ne
1684
1704
  )
1685
1705
  }
1686
1706
  updateRecyclerPaddingOwnership(recycler, original)
1707
+ val key = pageKey(pageIndex)
1687
1708
  val topInset = headerHeightPx + stickyHeaderHeightPx
1688
1709
  recycler.clipToPadding = false
1689
1710
  val top = original.top + topInset
@@ -1695,12 +1716,23 @@ class CollapsiblePagerHost(context: Context) : NestedScrollableHost(context), Ne
1695
1716
  // OneKey patch: LinearLayoutManager otherwise anchors children at their old
1696
1717
  // screen coordinates when a page changes the sticky header height.
1697
1718
  val manager = recycler.layoutManager as? LinearLayoutManager
1698
- val first = manager?.takeIf { it.orientation == RecyclerView.VERTICAL }
1699
- ?.findFirstVisibleItemPosition() ?: RecyclerView.NO_POSITION
1700
- val anchorOffset = if (first != RecyclerView.NO_POSITION) {
1719
+ val savedAnchor = if (nativeSmoothHeaderScrollEnabled && original.appliedTopInset == 0) {
1720
+ if (headerOffsetPx < headerHeightPx) {
1721
+ recycler.adapter?.let { RecyclerReadingAnchor(recycler, it, 0, 0) }
1722
+ } else {
1723
+ (if (transitionPageOffsets != null && pageIndex == transitionSourcePage) transitionSourceRecyclerAnchor
1724
+ else displayRecyclerAnchors[key] ?: recyclerReadingAnchors[key])
1725
+ ?.takeIf { it.view.get() === recycler && it.adapter === recycler.adapter }
1726
+ }
1727
+ } else null
1728
+ val first = savedAnchor?.position
1729
+ ?: manager?.takeIf { it.orientation == RecyclerView.VERTICAL }
1730
+ ?.findFirstVisibleItemPosition()
1731
+ ?: RecyclerView.NO_POSITION
1732
+ val anchorOffset = savedAnchor?.top ?: if (first != RecyclerView.NO_POSITION) {
1701
1733
  manager?.findViewByPosition(first)?.let { manager.getDecoratedTop(it) - recycler.paddingTop }
1702
1734
  } else null
1703
- offsetDiag("recycler-inset-before-nextTop=$top-anchorPosition=$first-anchorOffset=$anchorOffset", recycler, pageKey(pageIndex), pageIndex)
1735
+ offsetDiag("recycler-inset-before-nextTop=$top-anchorPosition=$first-anchorOffset=$anchorOffset", recycler, key, pageIndex)
1704
1736
  recycler.setPadding(original.left, top, original.right, bottom)
1705
1737
  if (anchorOffset != null) manager?.scrollToPositionWithOffset(first, anchorOffset)
1706
1738
  // React Native can stop this nested requestLayout at its React-owned parent.
@@ -1714,9 +1746,8 @@ class CollapsiblePagerHost(context: Context) : NestedScrollableHost(context), Ne
1714
1746
  recycler.layout(recycler.left, recycler.top, recycler.right, recycler.bottom)
1715
1747
  }
1716
1748
  }
1717
- if (original.appliedTopInset != topInset) offsetDiag("recycler-inset-after-old=${original.appliedTopInset}-new=$topInset", recycler, pageKey(pageIndex), pageIndex)
1749
+ if (original.appliedTopInset != topInset) offsetDiag("recycler-inset-after-old=${original.appliedTopInset}-new=$topInset", recycler, key, pageIndex)
1718
1750
  original.appliedTopInset = topInset
1719
- val key = pageKey(pageIndex)
1720
1751
  val geometry = Triple(recycler.computeVerticalScrollRange(), recycler.computeVerticalScrollExtent(), recycler.childCount)
1721
1752
  deferredRecyclerGeometry[recycler]?.let { deferred ->
1722
1753
  if (geometry != deferred) {
@@ -112,6 +112,10 @@ open class NestedScrollableHost : FrameLayout {
112
112
  else -> 0
113
113
  }
114
114
  if (smoothTouchAxis != 0) {
115
+ if (!nestedNativeGestureStarted) {
116
+ NativeGestureUtil.notifyNativeGestureStarted(this, e)
117
+ nestedNativeGestureStarted = true
118
+ }
115
119
  OneKeyLog.debug("CollapsiblePager", "content-direction owner=${if (smoothTouchAxis == 1) "list" else "horizontal"} dx=$dx dy=$dy nested=${nestedHorizontalOwner != null}")
116
120
  }
117
121
  }
@@ -184,8 +188,10 @@ open class NestedScrollableHost : FrameLayout {
184
188
  val scaledDy = dy.absoluteValue * if (isVpHorizontal) 1f else .5f
185
189
 
186
190
  if (scaledDx > touchSlop || scaledDy > touchSlop) {
187
- NativeGestureUtil.notifyNativeGestureStarted(this, e)
188
- nestedNativeGestureStarted = true
191
+ if (!nestedNativeGestureStarted) {
192
+ NativeGestureUtil.notifyNativeGestureStarted(this, e)
193
+ nestedNativeGestureStarted = true
194
+ }
189
195
 
190
196
  if (orientation == null) return
191
197
  if (isVpHorizontal == (scaledDy > scaledDx)) {
package/docs/SPEC.md CHANGED
@@ -435,6 +435,10 @@ controls belongs to the consuming responder implementation; the Pager package
435
435
  does not contain or publish Tamagui helpers. The native application tab bar has
436
436
  a separate contract in react-native-bottom-tabs/docs/SPEC.md.
437
437
 
438
+ On Android, smooth-touch coordination and nested interception share the same
439
+ native-gesture state. Once either path starts the gesture, later MOVE events
440
+ MUST NOT start it again before its end or cancellation clears that state.
441
+
438
442
  The current native implementation confirms horizontal intent after at least
439
443
  32 points on iOS or 32 dp on Android, with horizontal displacement exceeding
440
444
  vertical displacement. Vertical intent uses the native vertical scroll threshold
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@onekeyfe/react-native-pager-view",
3
- "version": "6.7.0-alpha.399",
3
+ "version": "6.7.0-alpha.400",
4
4
  "description": "React Native wrapper for Android and iOS ViewPager",
5
5
  "source": "./src/index.tsx",
6
6
  "main": "./lib/module/index.js",
@@ -73,7 +73,7 @@
73
73
  "typescript": "^5.9.2"
74
74
  },
75
75
  "peerDependencies": {
76
- "@onekeyfe/react-native-native-logger": "6.7.0-alpha.399",
76
+ "@onekeyfe/react-native-native-logger": "6.7.0-alpha.400",
77
77
  "react": "*",
78
78
  "react-native": "*"
79
79
  },