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

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.
@@ -43,6 +43,7 @@ class CollapsiblePagerViewManager : ViewGroupManager<CollapsiblePagerHost>(),
43
43
  )
44
44
  host.pager.registerOnPageChangeCallback(object : ViewPager2.OnPageChangeCallback() {
45
45
  override fun onPageScrolled(position: Int, offset: Float, offsetPixels: Int) {
46
+ host.onPagerScrolled(position, offset)
46
47
  dispatch(reactContext, host, PageScrollEvent(host.id, position, offset))
47
48
  }
48
49
 
@@ -55,6 +56,7 @@ class CollapsiblePagerViewManager : ViewGroupManager<CollapsiblePagerHost>(),
55
56
  }
56
57
 
57
58
  override fun onPageScrollStateChanged(state: Int) {
59
+ host.onPagerScrollStateChanged(state)
58
60
  val value = when (state) {
59
61
  ViewPager2.SCROLL_STATE_IDLE -> "idle"
60
62
  ViewPager2.SCROLL_STATE_DRAGGING -> "dragging"
@@ -322,15 +324,25 @@ class CollapsiblePagerViewManager : ViewGroupManager<CollapsiblePagerHost>(),
322
324
  delegate.receiveCommand(root, commandId, args)
323
325
  }
324
326
 
327
+ override fun scrollToTop(view: CollapsiblePagerHost?, target: Int, animated: Boolean) {
328
+ view?.scrollToTop(target, animated)
329
+ }
330
+
325
331
  override fun setPage(view: CollapsiblePagerHost?, selectedPage: Int) {
326
332
  if (view != null && selectedPage in 0 until view.adapter.itemCount) {
333
+ view.beginPageTransition(selectedPage)
327
334
  view.pager.setCurrentItem(selectedPage, true)
335
+ if (view.pager.scrollState == ViewPager2.SCROLL_STATE_IDLE) {
336
+ view.onPagerScrollStateChanged(ViewPager2.SCROLL_STATE_IDLE)
337
+ }
328
338
  }
329
339
  }
330
340
 
331
341
  override fun setPageWithoutAnimation(view: CollapsiblePagerHost?, selectedPage: Int) {
332
342
  if (view != null && selectedPage in 0 until view.adapter.itemCount) {
343
+ view.beginPageTransition(selectedPage)
333
344
  view.pager.setCurrentItem(selectedPage, false)
345
+ view.onPagerScrollStateChanged(ViewPager2.SCROLL_STATE_IDLE)
334
346
  }
335
347
  }
336
348
 
@@ -255,6 +255,8 @@ class NativeScrollerView(context: Context) : FrameLayout(context) {
255
255
 
256
256
  internal fun cancelPendingScrollRestore() = pendingRestore.cancel()
257
257
 
258
+ internal fun hasPendingScrollRestore(): Boolean = pendingRestore.target != null
259
+
258
260
  internal fun setRefreshOffset(value: Int) {
259
261
  refreshOffset = value
260
262
  applyRefreshOffset()
@@ -293,11 +295,22 @@ class NativeScrollerView(context: Context) : FrameLayout(context) {
293
295
  }
294
296
 
295
297
  internal fun scrollToPosition(x: Int, y: Int, animated: Boolean) {
298
+ notifyScrollCommand(0, y <= 0)
296
299
  viewport.stopMotion()
297
300
  pendingRestore.cancel()
301
+ notifyScrollCommand(1, y <= 0)
298
302
  if (animated) viewport.scrollToAnimated(y)
299
303
  else viewport.scrollTo(0, y.coerceAtLeast(0))
300
304
  emitScroll(force = true)
305
+ if (!viewport.isReadingMotionActive()) notifyScrollCommand(2, y <= 0)
306
+ }
307
+
308
+ internal fun notifyScrollCommand(phase: Int, explicitTop: Boolean = false) {
309
+ var owner = parent
310
+ while (owner is View) {
311
+ if (owner is CollapsiblePagerHost) owner.acceptObservedScrollCommand(viewport, explicitTop, phase)
312
+ owner = owner.parent
313
+ }
301
314
  }
302
315
 
303
316
  internal fun scrollToEnd(animated: Boolean) = scrollToPosition(
@@ -587,6 +600,8 @@ internal class NativeScrollerViewport(context: Context, internal val host: Nativ
587
600
  super.fling(velocityY)
588
601
  }
589
602
 
603
+ internal fun isReadingMotionActive() = dragging || momentum
604
+
590
605
  internal fun scrollToAnimated(y: Int) {
591
606
  val child = getChildAt(0) ?: return
592
607
  val margins = child.layoutParams as FrameLayout.LayoutParams
@@ -637,6 +652,7 @@ internal class NativeScrollerViewport(context: Context, internal val host: Nativ
637
652
  private fun finishMomentum() {
638
653
  if (!momentum) return
639
654
  momentum = false
655
+ host.notifyScrollCommand(2)
640
656
  host.emitScroll(force = true)
641
657
  host.emitLifecycle("topMomentumScrollEnd")
642
658
  }
@@ -2,4 +2,6 @@
2
2
  <item name="onekey_native_scroll_coordinator_consumed_offsets" type="id" />
3
3
  <item name="onekey_native_scroll_coordinator_offset_listener" type="id" />
4
4
  <item name="onekey_native_scroll_coordinator_refresh_inset" type="id" />
5
+ <item name="onekey_native_scroll_coordinator_command_listener" type="id" />
6
+ <item name="onekey_native_scroll_coordinator_command_cancel_listener" type="id" />
5
7
  </resources>
@@ -27,5 +27,16 @@ fun main() {
27
27
  restore.cancel()
28
28
  check(restore.target == null)
29
29
  check(restore.anchor(120) == 120)
30
+ // Cancellation clears the old target without requiring the reached offset to change.
31
+ restore.request(target = 640, reached = 120)
32
+ check(restore.anchor(120) == 640)
33
+ restore.cancel()
34
+ check(restore.target == null)
35
+ check(restore.anchor(120) == 120)
36
+ // A fresh request owns its target after cancellation.
37
+ restore.request(target = 320, reached = 120)
38
+ check(restore.target == 320)
39
+ restore.settle(reached = 320)
40
+ check(restore.target == null)
30
41
  println("Native scroller pending restore: clamp retry, partial growth, settle and cancel passed")
31
42
  }
package/docs/SPEC.md CHANGED
@@ -3,6 +3,60 @@
3
3
  Existing PagerView and CollapsiblePagerView APIs are documented in README.md.
4
4
  The sections below define native coordination boundaries without new React props.
5
5
 
6
+ ## Smooth shared-header and per-page body memory
7
+
8
+ With nativeSmoothHeaderScrollEnabled, the header collapse C is shared across all
9
+ pages and the available collapse distance is D. Each page separately remembers
10
+ its sticky-body reading distance B (unvisited pages default to zero). Outside
11
+ pull overscroll, the rendered whole-page distance is Q = C + effectiveB.
12
+ B denotes the saved reading position. For an owned vertical LinearLayoutManager
13
+ RecyclerView, restoration uses the first visible adapter position and its
14
+ decorated top relative to padding; scrollbar offset estimates MUST NOT decide
15
+ completion of that anchor restoration.
16
+ When C = D, selection restores the destination's saved B. When C < D, effectiveB
17
+ is zero while the previous saved B remains suspended. Horizontal selection by
18
+ tap, swipe or an existing programmatic command MUST preserve C throughout.
19
+
20
+ Alignment, prefetch, replacement, inset changes and pending restoration MUST NOT
21
+ commit new B. Actual consumed vertical scrolling takes over the visible body
22
+ position; reaching full collapse during that gesture MUST NOT resurrect the old
23
+ suspended B. Selecting a page anew at full collapse may restore its saved B.
24
+ Valid explicit native scroll commands, including same-offset commands, cancel
25
+ only their current owned restoration and take over body memory. Invalid commands
26
+ and stale owners do not affect another page. Existing command coordinate systems
27
+ are unchanged; in particular NativeScroller iOS uses physical offsets whereas
28
+ NativeList offset commands exclude the content-start inset.
29
+
30
+ Transitions use immutable destination memory and the source's actual displayed
31
+ position. Cancellation restores that source presentation, even when a cached B
32
+ was temporarily unreachable. Loading or zero geometry preserves pending intent;
33
+ a genuinely short page clamps its display without silently replacing saved B.
34
+ Cancelling a horizontal gesture invalidates queued callbacks, but preserves
35
+ unreachable reading intent until real vertical consumption or a valid command
36
+ takes over; later usable geometry may resume it.
37
+ Late callbacks cannot revive cancelled restoration or erase a newer request.
38
+ Observers and commands must match page key, view identity and generation.
39
+ Removed or recycled owners cannot apply callbacks to another page; recycling
40
+ resets owned memory.
41
+ Legacy mode and pagers without a collapsible header retain their existing
42
+ behavior. Vertical scrolling, refresh, snapping and repeated-current-tab behavior
43
+ are unchanged. This state belongs to native UI instances, with no new React prop
44
+ or per-frame JavaScript synchronization.
45
+
46
+ ## Current-page top commands
47
+
48
+ `scrollToPageTop(options?: Readonly<{ animated?: boolean }>)` restores the current
49
+ page to C = 0 and B = 0. `scrollToStickyTop(options?: Readonly<{ animated?: boolean }>)`
50
+ restores it to C = D and B = 0, including from a partially expanded header.
51
+ Animation defaults to true. Neither command clears another page's memory.
52
+ Both commands require a stable, attached current owner; horizontal transitions
53
+ or missing owners reject them rather than queueing a command for another page.
54
+ Acceptance cancels older owned list commands and pending restoration before the
55
+ new target is established. Same-target commands also take over old reading
56
+ intent. Real vertical consumption, a newer valid command, or owner detachment
57
+ releases the target. Existing NativeList and NativeScroller public coordinates
58
+ are unchanged. The same page-top/sticky-top destinations are available without smooth-header mode.
59
+
6
60
  ## Independent NativeScroller migration
7
61
 
8
62
  Status: implemented in source. Both native builds pass. Android focused emulator
@@ -454,7 +508,8 @@ When restoring a retained page's cached vertical offset, the pager limits only
454
508
  the upper bound to the current content height, viewport and applied insets. A
455
509
  cache captured before rows were removed MUST NOT restore an offset below the new
456
510
  content bottom, including when removal occurs during a page transition. Valid
457
- deep offsets and the existing lower-bound/header alignment rules are unchanged.
511
+ deep offsets and pull-overscroll behavior are preserved; smooth-header selection
512
+ follows the shared-header and per-page body-memory contract above.
458
513
  This check runs only on explicit restoration, not on scroll frames; UIKit pull
459
514
  overscroll and refresh settlement retain their existing ownership. An unmeasured
460
515
  zero-height viewport defers this upper-bound limit to a later restoration.