@onekeyfe/react-native-pager-view 3.0.123 → 3.0.125
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
|
@@ -9,6 +9,7 @@ import android.view.ViewConfiguration
|
|
|
9
9
|
import android.view.ViewGroup
|
|
10
10
|
import android.view.ViewTreeObserver
|
|
11
11
|
import android.widget.HorizontalScrollView
|
|
12
|
+
import android.widget.ScrollView
|
|
12
13
|
// OneKey patch: FrameLayout is inherited through NestedScrollableHost.
|
|
13
14
|
// import android.widget.FrameLayout
|
|
14
15
|
import androidx.core.view.NestedScrollingParent3
|
|
@@ -17,6 +18,7 @@ import androidx.core.view.ViewCompat
|
|
|
17
18
|
import androidx.recyclerview.widget.LinearLayoutManager
|
|
18
19
|
import androidx.recyclerview.widget.RecyclerView
|
|
19
20
|
import androidx.viewpager2.widget.ViewPager2
|
|
21
|
+
import com.facebook.react.R as ReactR
|
|
20
22
|
import com.facebook.react.uimanager.events.NativeGestureUtil
|
|
21
23
|
import com.margelo.nitro.nativelogger.OneKeyLog
|
|
22
24
|
import java.util.WeakHashMap
|
|
@@ -94,6 +96,15 @@ class CollapsiblePagerHost(context: Context) : NestedScrollableHost(context), Ne
|
|
|
94
96
|
var appliedTopInset: Int = 0,
|
|
95
97
|
)
|
|
96
98
|
|
|
99
|
+
private data class ScrollerPadding(
|
|
100
|
+
var left: Int,
|
|
101
|
+
var top: Int,
|
|
102
|
+
var right: Int,
|
|
103
|
+
var bottom: Int,
|
|
104
|
+
var clipToPadding: Boolean,
|
|
105
|
+
var appliedTopInset: Int = 0,
|
|
106
|
+
)
|
|
107
|
+
|
|
97
108
|
val pager = ViewPager2(context)
|
|
98
109
|
internal val adapter = CollapsiblePagerAdapter()
|
|
99
110
|
private val nativeTabBarView = CollapsiblePagerNativeTabBarView(context)
|
|
@@ -102,9 +113,13 @@ class CollapsiblePagerHost(context: Context) : NestedScrollableHost(context), Ne
|
|
|
102
113
|
private val nestedScrollingParentHelper = NestedScrollingParentHelper(this)
|
|
103
114
|
private val originalRecyclerPadding = WeakHashMap<RecyclerView, RecyclerPadding>()
|
|
104
115
|
private val restoredRecyclerKeys = WeakHashMap<RecyclerView, String>()
|
|
116
|
+
private val originalScrollerPadding = WeakHashMap<ScrollView, ScrollerPadding>()
|
|
117
|
+
private val restoredScrollerKeys = WeakHashMap<ScrollView, String>()
|
|
105
118
|
private val pageOffsets = HashMap<String, Int>()
|
|
106
119
|
private var observedRecyclerView: RecyclerView? = null
|
|
107
120
|
private var observedScrollListener: RecyclerView.OnScrollListener? = null
|
|
121
|
+
private var observedNativeScroller: ScrollView? = null
|
|
122
|
+
private var observedNativeScrollerListener: ViewTreeObserver.OnScrollChangedListener? = null
|
|
108
123
|
private var attachmentGeneration = 0
|
|
109
124
|
private val touchSlopPx = ViewConfiguration.get(context).scaledTouchSlop
|
|
110
125
|
private val hostIdentity = System.identityHashCode(this)
|
|
@@ -117,7 +132,7 @@ class CollapsiblePagerHost(context: Context) : NestedScrollableHost(context), Ne
|
|
|
117
132
|
private var headerDownY = 0f
|
|
118
133
|
private var headerDownEvent: MotionEvent? = null
|
|
119
134
|
private var headerHasHorizontalChild = false
|
|
120
|
-
private var
|
|
135
|
+
private var forwardedScrollable: View? = null
|
|
121
136
|
private var nativeGestureStarted = false
|
|
122
137
|
private var pressCancelled = false
|
|
123
138
|
private val pageContentLayoutListener = ViewTreeObserver.OnPreDrawListener {
|
|
@@ -125,7 +140,7 @@ class CollapsiblePagerHost(context: Context) : NestedScrollableHost(context), Ne
|
|
|
125
140
|
// Fabric can mount a retained list without another Android layout pass.
|
|
126
141
|
// Apply its header insets before that list first draws.
|
|
127
142
|
prepareAdjacentPages()
|
|
128
|
-
|
|
143
|
+
attachPrimaryScrollObserver()
|
|
129
144
|
// OneKey patch: a filtered short page can reduce the existing collapse range.
|
|
130
145
|
setHeaderOffset(headerOffsetPx)
|
|
131
146
|
true
|
|
@@ -140,14 +155,14 @@ class CollapsiblePagerHost(context: Context) : NestedScrollableHost(context), Ne
|
|
|
140
155
|
if (field == value) return
|
|
141
156
|
field = max(0, value)
|
|
142
157
|
headerOffsetPx = min(headerOffsetPx, field)
|
|
143
|
-
|
|
158
|
+
reapplyScrollableInsets()
|
|
144
159
|
updateHeaderLayout()
|
|
145
160
|
}
|
|
146
161
|
var stickyHeaderHeightPx = 0
|
|
147
162
|
set(value) {
|
|
148
163
|
if (field == value) return
|
|
149
164
|
field = max(0, value)
|
|
150
|
-
|
|
165
|
+
reapplyScrollableInsets()
|
|
151
166
|
updateHeaderLayout()
|
|
152
167
|
}
|
|
153
168
|
var headerOffsetPx = 0
|
|
@@ -306,7 +321,11 @@ class CollapsiblePagerHost(context: Context) : NestedScrollableHost(context), Ne
|
|
|
306
321
|
stickyHeaderView = null
|
|
307
322
|
}
|
|
308
323
|
else -> {
|
|
309
|
-
|
|
324
|
+
when (val scrollable =
|
|
325
|
+
findExplicitNativeScrollerInView(child) ?: findVerticalScrollableView(child)) {
|
|
326
|
+
is RecyclerView -> restoreRecyclerInsets(scrollable)
|
|
327
|
+
is ScrollView -> restoreNativeScrollerInsets(scrollable)
|
|
328
|
+
}
|
|
310
329
|
adapter.removePage(child)
|
|
311
330
|
log("page-detach slot=${index - PAGE_SLOT_OFFSET} nativePages=${adapter.itemCount}")
|
|
312
331
|
}
|
|
@@ -314,10 +333,13 @@ class CollapsiblePagerHost(context: Context) : NestedScrollableHost(context), Ne
|
|
|
314
333
|
}
|
|
315
334
|
|
|
316
335
|
fun removeAllReactChildren() {
|
|
317
|
-
|
|
336
|
+
detachPrimaryScrollObserver()
|
|
318
337
|
for (recycler in originalRecyclerPadding.keys.toList()) {
|
|
319
338
|
restoreRecyclerInsets(recycler)
|
|
320
339
|
}
|
|
340
|
+
for (scroller in originalScrollerPadding.keys.toList()) {
|
|
341
|
+
restoreNativeScrollerInsets(scroller)
|
|
342
|
+
}
|
|
321
343
|
headerView?.let { view -> super.removeView(view) }
|
|
322
344
|
stickyHeaderView?.let { view -> super.removeView(view) }
|
|
323
345
|
headerView = null
|
|
@@ -334,15 +356,15 @@ class CollapsiblePagerHost(context: Context) : NestedScrollableHost(context), Ne
|
|
|
334
356
|
|
|
335
357
|
fun selectPage(position: Int) {
|
|
336
358
|
if (adapter.itemCount == 0) return
|
|
337
|
-
|
|
359
|
+
detachPrimaryScrollObserver()
|
|
338
360
|
selectedPage = position.coerceIn(0, adapter.itemCount - 1)
|
|
339
361
|
val savedOffset = pageOffsets[currentPageKey()]
|
|
340
|
-
?:
|
|
362
|
+
?: primaryScrollableForPage(selectedPage)?.let(::verticalScrollOffset)
|
|
341
363
|
?: 0
|
|
342
364
|
if (savedOffset > 0) setHeaderOffset(headerHeightPx)
|
|
343
365
|
postForCurrentAttachment {
|
|
344
366
|
prepareAdjacentPages()
|
|
345
|
-
|
|
367
|
+
attachPrimaryScrollObserver()
|
|
346
368
|
}
|
|
347
369
|
}
|
|
348
370
|
|
|
@@ -367,7 +389,8 @@ class CollapsiblePagerHost(context: Context) : NestedScrollableHost(context), Ne
|
|
|
367
389
|
|
|
368
390
|
fun attachedPageCount(): Int = (pager.getChildAt(0) as? RecyclerView)?.childCount ?: 0
|
|
369
391
|
|
|
370
|
-
fun observedScrollableCount(): Int =
|
|
392
|
+
fun observedScrollableCount(): Int =
|
|
393
|
+
originalRecyclerPadding.size + originalScrollerPadding.size
|
|
371
394
|
|
|
372
395
|
private fun layoutPagerIfRequested() {
|
|
373
396
|
val recycler = pager.getChildAt(0) as? RecyclerView ?: return
|
|
@@ -458,13 +481,17 @@ class CollapsiblePagerHost(context: Context) : NestedScrollableHost(context), Ne
|
|
|
458
481
|
applyHeaderOffset()
|
|
459
482
|
postForCurrentAttachment {
|
|
460
483
|
prepareAdjacentPages()
|
|
461
|
-
|
|
484
|
+
attachPrimaryScrollObserver()
|
|
462
485
|
}
|
|
463
486
|
}
|
|
464
487
|
|
|
465
488
|
private fun maximumHeaderOffset(): Int {
|
|
466
|
-
val
|
|
467
|
-
|
|
489
|
+
val scrollable = observedRecyclerView
|
|
490
|
+
?: observedNativeScroller
|
|
491
|
+
?: primaryScrollableForPage(selectedPage)
|
|
492
|
+
?: return headerHeightPx
|
|
493
|
+
val childCount = (scrollable as? ViewGroup)?.childCount ?: 0
|
|
494
|
+
if (childCount == 0 || scrollable.canScrollVertically(-1) || scrollable.canScrollVertically(1)) {
|
|
468
495
|
return headerHeightPx
|
|
469
496
|
}
|
|
470
497
|
// OneKey patch: short pages use the original rounded-DIP minimum content height.
|
|
@@ -503,51 +530,96 @@ class CollapsiblePagerHost(context: Context) : NestedScrollableHost(context), Ne
|
|
|
503
530
|
return false
|
|
504
531
|
}
|
|
505
532
|
|
|
506
|
-
private fun
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
533
|
+
private fun isVerticalRecyclerView(view: RecyclerView): Boolean {
|
|
534
|
+
val manager = view.layoutManager
|
|
535
|
+
return manager !is LinearLayoutManager || manager.orientation == RecyclerView.VERTICAL
|
|
536
|
+
}
|
|
537
|
+
|
|
538
|
+
private fun isExplicitNativeScroller(view: View): Boolean {
|
|
539
|
+
val nativeId = view.getTag(ReactR.id.view_tag_native_id) as? String ?: return false
|
|
540
|
+
return nativeId.startsWith(NATIVE_SCROLLER_ID_PREFIX)
|
|
541
|
+
}
|
|
542
|
+
|
|
543
|
+
private fun findExplicitNativeScrollerInView(view: View): View? {
|
|
544
|
+
if (view !== this && view is CollapsiblePagerHost) {
|
|
545
|
+
return view.currentPrimaryScrollableForParent()
|
|
546
|
+
}
|
|
547
|
+
if (isExplicitNativeScroller(view) &&
|
|
548
|
+
(view is ScrollView || view is RecyclerView && isVerticalRecyclerView(view))) {
|
|
549
|
+
return view
|
|
550
|
+
}
|
|
551
|
+
if (view is ViewGroup) {
|
|
552
|
+
for (index in 0 until view.childCount) {
|
|
553
|
+
findExplicitNativeScrollerInView(view.getChildAt(index))?.let { return it }
|
|
511
554
|
}
|
|
512
555
|
}
|
|
556
|
+
return null
|
|
557
|
+
}
|
|
558
|
+
|
|
559
|
+
private fun findVerticalScrollableView(view: View): View? {
|
|
560
|
+
if (view !== this && view is CollapsiblePagerHost) {
|
|
561
|
+
return view.currentPrimaryScrollableForParent()
|
|
562
|
+
}
|
|
563
|
+
if (view is RecyclerView && isVerticalRecyclerView(view)) return view
|
|
564
|
+
if (view is ScrollView) return view
|
|
513
565
|
if (view is ViewGroup) {
|
|
514
566
|
for (index in 0 until view.childCount) {
|
|
515
|
-
|
|
567
|
+
findVerticalScrollableView(view.getChildAt(index))?.let { return it }
|
|
516
568
|
}
|
|
517
569
|
}
|
|
518
570
|
return null
|
|
519
571
|
}
|
|
520
572
|
|
|
521
|
-
private fun
|
|
573
|
+
private fun primaryScrollableForPage(index: Int): View? {
|
|
522
574
|
if (index !in 0 until adapter.itemCount) return null
|
|
523
|
-
|
|
575
|
+
val page = adapter.pageAt(index)
|
|
576
|
+
return findExplicitNativeScrollerInView(page) ?: findVerticalScrollableView(page)
|
|
577
|
+
}
|
|
578
|
+
|
|
579
|
+
internal fun currentPrimaryScrollableForParent(): View? =
|
|
580
|
+
primaryScrollableForPage(selectedPage)
|
|
581
|
+
|
|
582
|
+
private fun recyclerViewForPage(index: Int): RecyclerView? =
|
|
583
|
+
primaryScrollableForPage(index) as? RecyclerView
|
|
584
|
+
|
|
585
|
+
private fun verticalScrollOffset(view: View): Int = when (view) {
|
|
586
|
+
is RecyclerView -> view.computeVerticalScrollOffset()
|
|
587
|
+
is ScrollView -> view.scrollY
|
|
588
|
+
else -> 0
|
|
524
589
|
}
|
|
525
590
|
|
|
526
591
|
private fun prepareAdjacentPages() {
|
|
527
592
|
val first = max(0, selectedPage - 1)
|
|
528
593
|
val last = min(adapter.itemCount - 1, selectedPage + 1)
|
|
529
594
|
for (index in first..last) {
|
|
530
|
-
|
|
531
|
-
applyRecyclerInsets(
|
|
595
|
+
when (val scrollable = primaryScrollableForPage(index)) {
|
|
596
|
+
is RecyclerView -> applyRecyclerInsets(scrollable, index)
|
|
597
|
+
is ScrollView -> applyNativeScrollerInsets(scrollable, index)
|
|
532
598
|
}
|
|
533
599
|
}
|
|
534
600
|
}
|
|
535
601
|
|
|
536
|
-
private fun
|
|
602
|
+
private fun attachPrimaryScrollObserver() {
|
|
537
603
|
if (selectedPage !in 0 until adapter.itemCount) return
|
|
538
|
-
val previous = observedRecyclerView
|
|
604
|
+
val previous = observedRecyclerView ?: observedNativeScroller
|
|
539
605
|
if (previous != null && !isDescendant(previous, adapter.pageAt(selectedPage))) {
|
|
540
|
-
|
|
541
|
-
// A replacement
|
|
606
|
+
detachPrimaryScrollObserver()
|
|
607
|
+
// A replacement scroller starts at the beginning while retaining header collapse.
|
|
542
608
|
pageOffsets[currentPageKey()] = 0
|
|
543
609
|
}
|
|
544
|
-
val
|
|
610
|
+
when (val scrollable = primaryScrollableForPage(selectedPage)) {
|
|
611
|
+
is RecyclerView -> attachRecyclerObserver(scrollable)
|
|
612
|
+
is ScrollView -> attachNativeScrollerObserver(scrollable)
|
|
613
|
+
}
|
|
614
|
+
}
|
|
615
|
+
|
|
616
|
+
private fun attachRecyclerObserver(recycler: RecyclerView) {
|
|
545
617
|
if (observedRecyclerView === recycler) {
|
|
546
618
|
applyRecyclerInsets(recycler, selectedPage)
|
|
547
619
|
return
|
|
548
620
|
}
|
|
549
621
|
|
|
550
|
-
|
|
622
|
+
detachPrimaryScrollObserver()
|
|
551
623
|
observedRecyclerView = recycler
|
|
552
624
|
applyRecyclerInsets(recycler, selectedPage)
|
|
553
625
|
val listener = object : RecyclerView.OnScrollListener() {
|
|
@@ -570,9 +642,11 @@ class CollapsiblePagerHost(context: Context) : NestedScrollableHost(context), Ne
|
|
|
570
642
|
}
|
|
571
643
|
|
|
572
644
|
private fun detachRecyclerObserver() {
|
|
573
|
-
storeObservedPageOffset()
|
|
574
645
|
val recycler = observedRecyclerView
|
|
575
646
|
val listener = observedScrollListener
|
|
647
|
+
if (recycler != null) {
|
|
648
|
+
pageOffsets[currentPageKey()] = recycler.computeVerticalScrollOffset()
|
|
649
|
+
}
|
|
576
650
|
if (recycler != null && listener != null) recycler.removeOnScrollListener(listener)
|
|
577
651
|
if (recycler != null) {
|
|
578
652
|
log(
|
|
@@ -584,10 +658,50 @@ class CollapsiblePagerHost(context: Context) : NestedScrollableHost(context), Ne
|
|
|
584
658
|
observedScrollListener = null
|
|
585
659
|
}
|
|
586
660
|
|
|
587
|
-
private fun
|
|
588
|
-
|
|
589
|
-
|
|
661
|
+
private fun attachNativeScrollerObserver(scroller: ScrollView) {
|
|
662
|
+
if (observedNativeScroller === scroller) {
|
|
663
|
+
applyNativeScrollerInsets(scroller, selectedPage)
|
|
664
|
+
return
|
|
590
665
|
}
|
|
666
|
+
|
|
667
|
+
detachPrimaryScrollObserver()
|
|
668
|
+
observedNativeScroller = scroller
|
|
669
|
+
applyNativeScrollerInsets(scroller, selectedPage)
|
|
670
|
+
val listener = ViewTreeObserver.OnScrollChangedListener {
|
|
671
|
+
val contentOffset = scroller.scrollY
|
|
672
|
+
pageOffsets[currentPageKey()] = contentOffset
|
|
673
|
+
if (contentOffset > 0 && headerOffsetPx < headerHeightPx) {
|
|
674
|
+
setHeaderOffset(headerHeightPx)
|
|
675
|
+
}
|
|
676
|
+
}
|
|
677
|
+
observedNativeScrollerListener = listener
|
|
678
|
+
scroller.viewTreeObserver.addOnScrollChangedListener(listener)
|
|
679
|
+
log(
|
|
680
|
+
"scroller-observer-attach inner=$selectedPage key=${currentPageKey()} " +
|
|
681
|
+
"scroller=${System.identityHashCode(scroller)}",
|
|
682
|
+
)
|
|
683
|
+
}
|
|
684
|
+
|
|
685
|
+
private fun detachNativeScrollerObserver() {
|
|
686
|
+
val scroller = observedNativeScroller
|
|
687
|
+
val listener = observedNativeScrollerListener
|
|
688
|
+
if (scroller != null) pageOffsets[currentPageKey()] = scroller.scrollY
|
|
689
|
+
if (scroller != null && listener != null && scroller.viewTreeObserver.isAlive) {
|
|
690
|
+
scroller.viewTreeObserver.removeOnScrollChangedListener(listener)
|
|
691
|
+
}
|
|
692
|
+
if (scroller != null) {
|
|
693
|
+
log(
|
|
694
|
+
"scroller-observer-detach inner=$selectedPage key=${currentPageKey()} " +
|
|
695
|
+
"scroller=${System.identityHashCode(scroller)}",
|
|
696
|
+
)
|
|
697
|
+
}
|
|
698
|
+
observedNativeScroller = null
|
|
699
|
+
observedNativeScrollerListener = null
|
|
700
|
+
}
|
|
701
|
+
|
|
702
|
+
private fun detachPrimaryScrollObserver() {
|
|
703
|
+
detachRecyclerObserver()
|
|
704
|
+
detachNativeScrollerObserver()
|
|
591
705
|
}
|
|
592
706
|
|
|
593
707
|
private fun applyRecyclerInsets(recycler: RecyclerView, pageIndex: Int) {
|
|
@@ -649,6 +763,57 @@ class CollapsiblePagerHost(context: Context) : NestedScrollableHost(context), Ne
|
|
|
649
763
|
}
|
|
650
764
|
}
|
|
651
765
|
|
|
766
|
+
private fun applyNativeScrollerInsets(scroller: ScrollView, pageIndex: Int) {
|
|
767
|
+
val original = originalScrollerPadding.getOrPut(scroller) {
|
|
768
|
+
ScrollerPadding(
|
|
769
|
+
scroller.paddingLeft,
|
|
770
|
+
scroller.paddingTop,
|
|
771
|
+
scroller.paddingRight,
|
|
772
|
+
scroller.paddingBottom,
|
|
773
|
+
scroller.clipToPadding,
|
|
774
|
+
)
|
|
775
|
+
}
|
|
776
|
+
updateScrollerPaddingOwnership(scroller, original)
|
|
777
|
+
val topInset = headerHeightPx + stickyHeaderHeightPx
|
|
778
|
+
val top = original.top + topInset
|
|
779
|
+
scroller.clipToPadding = false
|
|
780
|
+
if (scroller.paddingLeft != original.left || scroller.paddingTop != top ||
|
|
781
|
+
scroller.paddingRight != original.right || scroller.paddingBottom != original.bottom) {
|
|
782
|
+
scroller.setPadding(original.left, top, original.right, original.bottom)
|
|
783
|
+
}
|
|
784
|
+
original.appliedTopInset = topInset
|
|
785
|
+
|
|
786
|
+
val key = pageKey(pageIndex)
|
|
787
|
+
if (restoredScrollerKeys[scroller] != key) {
|
|
788
|
+
restoredScrollerKeys[scroller] = key
|
|
789
|
+
val generation = attachmentGeneration
|
|
790
|
+
scroller.post {
|
|
791
|
+
if (!isAttachedToWindow || generation != attachmentGeneration ||
|
|
792
|
+
restoredScrollerKeys[scroller] != key ||
|
|
793
|
+
originalScrollerPadding[scroller] !== original) {
|
|
794
|
+
if (restoredScrollerKeys[scroller] == key) restoredScrollerKeys.remove(scroller)
|
|
795
|
+
return@post
|
|
796
|
+
}
|
|
797
|
+
val saved = pageOffsets[key] ?: 0
|
|
798
|
+
if (scroller.scrollY != saved) scroller.scrollTo(scroller.scrollX, saved)
|
|
799
|
+
}
|
|
800
|
+
}
|
|
801
|
+
}
|
|
802
|
+
|
|
803
|
+
private fun updateScrollerPaddingOwnership(
|
|
804
|
+
scroller: ScrollView,
|
|
805
|
+
original: ScrollerPadding,
|
|
806
|
+
) {
|
|
807
|
+
val expectedTop = original.top + original.appliedTopInset
|
|
808
|
+
if (scroller.paddingLeft != original.left) original.left = scroller.paddingLeft
|
|
809
|
+
if (scroller.paddingTop != expectedTop) {
|
|
810
|
+
original.top = (scroller.paddingTop - original.appliedTopInset).coerceAtLeast(0)
|
|
811
|
+
}
|
|
812
|
+
if (scroller.paddingRight != original.right) original.right = scroller.paddingRight
|
|
813
|
+
if (scroller.paddingBottom != original.bottom) original.bottom = scroller.paddingBottom
|
|
814
|
+
if (scroller.clipToPadding) original.clipToPadding = true
|
|
815
|
+
}
|
|
816
|
+
|
|
652
817
|
private fun updateRecyclerPaddingOwnership(
|
|
653
818
|
recycler: RecyclerView,
|
|
654
819
|
original: RecyclerPadding,
|
|
@@ -665,7 +830,7 @@ class CollapsiblePagerHost(context: Context) : NestedScrollableHost(context), Ne
|
|
|
665
830
|
if (recycler.clipToPadding) original.clipToPadding = true
|
|
666
831
|
}
|
|
667
832
|
|
|
668
|
-
private fun
|
|
833
|
+
private fun reapplyScrollableInsets() {
|
|
669
834
|
prepareAdjacentPages()
|
|
670
835
|
}
|
|
671
836
|
|
|
@@ -677,6 +842,14 @@ class CollapsiblePagerHost(context: Context) : NestedScrollableHost(context), Ne
|
|
|
677
842
|
recycler.setPadding(original.left, original.top, original.right, original.bottom)
|
|
678
843
|
}
|
|
679
844
|
|
|
845
|
+
private fun restoreNativeScrollerInsets(scroller: ScrollView) {
|
|
846
|
+
val original = originalScrollerPadding.remove(scroller) ?: return
|
|
847
|
+
updateScrollerPaddingOwnership(scroller, original)
|
|
848
|
+
restoredScrollerKeys.remove(scroller)
|
|
849
|
+
scroller.clipToPadding = original.clipToPadding
|
|
850
|
+
scroller.setPadding(original.left, original.top, original.right, original.bottom)
|
|
851
|
+
}
|
|
852
|
+
|
|
680
853
|
private fun headerRegionAt(y: Float): String? {
|
|
681
854
|
val headerBottom = headerHeightPx - headerOffsetPx
|
|
682
855
|
val stickyBottom = headerHeightPx + stickyHeaderHeightPx - headerOffsetPx
|
|
@@ -736,26 +909,26 @@ class CollapsiblePagerHost(context: Context) : NestedScrollableHost(context), Ne
|
|
|
736
909
|
)
|
|
737
910
|
}
|
|
738
911
|
|
|
739
|
-
private fun
|
|
912
|
+
private fun dispatchToScrollable(scrollable: View, event: MotionEvent): Boolean {
|
|
740
913
|
val hostLocation = IntArray(2)
|
|
741
|
-
val
|
|
914
|
+
val scrollableLocation = IntArray(2)
|
|
742
915
|
getLocationOnScreen(hostLocation)
|
|
743
|
-
|
|
916
|
+
scrollable.getLocationOnScreen(scrollableLocation)
|
|
744
917
|
val copy = MotionEvent.obtain(event)
|
|
745
918
|
copy.offsetLocation(
|
|
746
|
-
(hostLocation[0] -
|
|
747
|
-
(hostLocation[1] -
|
|
919
|
+
(hostLocation[0] - scrollableLocation[0]).toFloat(),
|
|
920
|
+
(hostLocation[1] - scrollableLocation[1]).toFloat(),
|
|
748
921
|
)
|
|
749
|
-
val handled =
|
|
922
|
+
val handled = scrollable.dispatchTouchEvent(copy)
|
|
750
923
|
copy.recycle()
|
|
751
924
|
return handled
|
|
752
925
|
}
|
|
753
926
|
|
|
754
|
-
private fun
|
|
755
|
-
val
|
|
756
|
-
|
|
757
|
-
headerDownEvent?.let { down ->
|
|
758
|
-
return
|
|
927
|
+
private fun beginForwardingToPrimaryScrollable(event: MotionEvent): Boolean {
|
|
928
|
+
val scrollable = primaryScrollableForPage(selectedPage) ?: return false
|
|
929
|
+
forwardedScrollable = scrollable
|
|
930
|
+
headerDownEvent?.let { down -> dispatchToScrollable(scrollable, down) }
|
|
931
|
+
return dispatchToScrollable(scrollable, event)
|
|
759
932
|
}
|
|
760
933
|
|
|
761
934
|
private fun finishHeaderGesture(event: MotionEvent) {
|
|
@@ -776,7 +949,7 @@ class CollapsiblePagerHost(context: Context) : NestedScrollableHost(context), Ne
|
|
|
776
949
|
headerTouchRegion = "none"
|
|
777
950
|
headerGestureOwner = HeaderGestureOwner.NONE
|
|
778
951
|
headerHasHorizontalChild = false
|
|
779
|
-
|
|
952
|
+
forwardedScrollable = null
|
|
780
953
|
pressCancelled = false
|
|
781
954
|
}
|
|
782
955
|
|
|
@@ -789,7 +962,7 @@ class CollapsiblePagerHost(context: Context) : NestedScrollableHost(context), Ne
|
|
|
789
962
|
headerDownEvent?.recycle()
|
|
790
963
|
headerDownEvent = null
|
|
791
964
|
headerGestureOwner = HeaderGestureOwner.NONE
|
|
792
|
-
|
|
965
|
+
forwardedScrollable = null
|
|
793
966
|
pressCancelled = false
|
|
794
967
|
nativeGestureStarted = false
|
|
795
968
|
nestedNativeGestureStarted = false
|
|
@@ -832,10 +1005,10 @@ class CollapsiblePagerHost(context: Context) : NestedScrollableHost(context), Ne
|
|
|
832
1005
|
return when (headerGestureOwner) {
|
|
833
1006
|
HeaderGestureOwner.LIST -> {
|
|
834
1007
|
cancelHeaderPress(event, "list")
|
|
835
|
-
val
|
|
836
|
-
if (
|
|
837
|
-
|
|
838
|
-
} else if (
|
|
1008
|
+
val scrollable = forwardedScrollable
|
|
1009
|
+
if (scrollable != null) {
|
|
1010
|
+
dispatchToScrollable(scrollable, event)
|
|
1011
|
+
} else if (beginForwardingToPrimaryScrollable(event)) {
|
|
839
1012
|
true
|
|
840
1013
|
} else {
|
|
841
1014
|
headerGestureOwner = HeaderGestureOwner.HEADER_GUARD
|
|
@@ -855,8 +1028,8 @@ class CollapsiblePagerHost(context: Context) : NestedScrollableHost(context), Ne
|
|
|
855
1028
|
MotionEvent.ACTION_UP, MotionEvent.ACTION_CANCEL -> {
|
|
856
1029
|
if (!headerTouchActive) return super.dispatchTouchEvent(event)
|
|
857
1030
|
val handled = when (headerGestureOwner) {
|
|
858
|
-
HeaderGestureOwner.LIST ->
|
|
859
|
-
|
|
1031
|
+
HeaderGestureOwner.LIST -> forwardedScrollable?.let { scrollable ->
|
|
1032
|
+
dispatchToScrollable(scrollable, event)
|
|
860
1033
|
} ?: true
|
|
861
1034
|
HeaderGestureOwner.HEADER_GUARD -> true
|
|
862
1035
|
else -> super.dispatchTouchEvent(event)
|
|
@@ -966,6 +1139,7 @@ class CollapsiblePagerHost(context: Context) : NestedScrollableHost(context), Ne
|
|
|
966
1139
|
super.onAttachedToWindow()
|
|
967
1140
|
attachmentGeneration += 1
|
|
968
1141
|
restoredRecyclerKeys.clear()
|
|
1142
|
+
restoredScrollerKeys.clear()
|
|
969
1143
|
viewTreeObserver.addOnPreDrawListener(pageContentLayoutListener)
|
|
970
1144
|
log(
|
|
971
1145
|
"host-attach generation=$attachmentGeneration inner=$selectedPage " +
|
|
@@ -978,15 +1152,18 @@ class CollapsiblePagerHost(context: Context) : NestedScrollableHost(context), Ne
|
|
|
978
1152
|
headerDownEvent?.recycle()
|
|
979
1153
|
headerDownEvent = null
|
|
980
1154
|
headerTouchActive = false
|
|
981
|
-
|
|
1155
|
+
forwardedScrollable = null
|
|
982
1156
|
pressCancelled = false
|
|
983
1157
|
nativeGestureStarted = false
|
|
984
1158
|
nestedNativeGestureStarted = false
|
|
985
1159
|
viewTreeObserver.removeOnPreDrawListener(pageContentLayoutListener)
|
|
986
|
-
|
|
1160
|
+
detachPrimaryScrollObserver()
|
|
987
1161
|
for (recycler in originalRecyclerPadding.keys.toList()) {
|
|
988
1162
|
restoreRecyclerInsets(recycler)
|
|
989
1163
|
}
|
|
1164
|
+
for (scroller in originalScrollerPadding.keys.toList()) {
|
|
1165
|
+
restoreNativeScrollerInsets(scroller)
|
|
1166
|
+
}
|
|
990
1167
|
log(
|
|
991
1168
|
"host-detach generation=$attachmentGeneration inner=$selectedPage " +
|
|
992
1169
|
"outer=${outerPagerIndex()} nativePages=${adapter.itemCount}",
|
|
@@ -995,6 +1172,7 @@ class CollapsiblePagerHost(context: Context) : NestedScrollableHost(context), Ne
|
|
|
995
1172
|
}
|
|
996
1173
|
|
|
997
1174
|
companion object {
|
|
1175
|
+
const val NATIVE_SCROLLER_ID_PREFIX = "rnc-collapsible-pager-native-scroller:"
|
|
998
1176
|
const val PAGE_SLOT_OFFSET = 2
|
|
999
1177
|
}
|
|
1000
1178
|
}
|
|
@@ -181,6 +181,7 @@ class CollapsiblePagerViewManager : ViewGroupManager<CollapsiblePagerHost>(),
|
|
|
181
181
|
// OneKey patch: CollapsiblePagerHost always coordinates nested pagers on Android.
|
|
182
182
|
}
|
|
183
183
|
|
|
184
|
+
@ReactProp(name = "nativeSmoothHeaderScrollEnabled", defaultBoolean = false)
|
|
184
185
|
override fun setNativeSmoothHeaderScrollEnabled(
|
|
185
186
|
view: CollapsiblePagerHost?,
|
|
186
187
|
value: Boolean,
|
|
@@ -210,16 +211,19 @@ class CollapsiblePagerViewManager : ViewGroupManager<CollapsiblePagerHost>(),
|
|
|
210
211
|
view?.retainedPages = value ?: "[]"
|
|
211
212
|
}
|
|
212
213
|
|
|
214
|
+
@ReactProp(name = "nativeTabBarItems")
|
|
213
215
|
override fun setNativeTabBarItems(view: CollapsiblePagerHost?, value: String?) {
|
|
214
216
|
view?.updateNativeTabBarItems(value)
|
|
215
217
|
}
|
|
216
218
|
|
|
219
|
+
@ReactProp(name = "nativeTabBarHeight")
|
|
217
220
|
override fun setNativeTabBarHeight(view: CollapsiblePagerHost?, value: Double) {
|
|
218
221
|
view ?: return
|
|
219
222
|
view.nativeTabBarHeight = value
|
|
220
223
|
view.applyNativeHeaderStyle()
|
|
221
224
|
}
|
|
222
225
|
|
|
226
|
+
@ReactProp(name = "nativeTabBarContentPaddingHorizontal")
|
|
223
227
|
override fun setNativeTabBarContentPaddingHorizontal(
|
|
224
228
|
view: CollapsiblePagerHost?,
|
|
225
229
|
value: Double,
|
|
@@ -229,64 +233,75 @@ class CollapsiblePagerViewManager : ViewGroupManager<CollapsiblePagerHost>(),
|
|
|
229
233
|
view.applyNativeHeaderStyle()
|
|
230
234
|
}
|
|
231
235
|
|
|
236
|
+
@ReactProp(name = "nativeTabBarItemSpacing")
|
|
232
237
|
override fun setNativeTabBarItemSpacing(view: CollapsiblePagerHost?, value: Double) {
|
|
233
238
|
view ?: return
|
|
234
239
|
view.nativeTabBarItemSpacing = value
|
|
235
240
|
view.applyNativeHeaderStyle()
|
|
236
241
|
}
|
|
237
242
|
|
|
243
|
+
@ReactProp(name = "nativeTabBarFontSize")
|
|
238
244
|
override fun setNativeTabBarFontSize(view: CollapsiblePagerHost?, value: Double) {
|
|
239
245
|
view ?: return
|
|
240
246
|
view.nativeTabBarFontSize = value
|
|
241
247
|
view.applyNativeHeaderStyle()
|
|
242
248
|
}
|
|
243
249
|
|
|
250
|
+
@ReactProp(name = "nativeTabBarFontFamily")
|
|
244
251
|
override fun setNativeTabBarFontFamily(view: CollapsiblePagerHost?, value: String?) {
|
|
245
252
|
view ?: return
|
|
246
253
|
view.nativeTabBarFontFamily = value
|
|
247
254
|
view.applyNativeHeaderStyle()
|
|
248
255
|
}
|
|
249
256
|
|
|
257
|
+
@ReactProp(name = "nativeTabBarBackgroundColor", customType = "Color")
|
|
250
258
|
override fun setNativeTabBarBackgroundColor(view: CollapsiblePagerHost?, value: Int?) {
|
|
251
259
|
view ?: return
|
|
252
260
|
view.nativeTabBarBackgroundColor = value ?: Color.TRANSPARENT
|
|
253
261
|
view.applyNativeHeaderStyle()
|
|
254
262
|
}
|
|
255
263
|
|
|
264
|
+
@ReactProp(name = "nativeTabBarActiveTextColor", customType = "Color")
|
|
256
265
|
override fun setNativeTabBarActiveTextColor(view: CollapsiblePagerHost?, value: Int?) {
|
|
257
266
|
view ?: return
|
|
258
267
|
view.nativeTabBarActiveTextColor = value ?: Color.BLACK
|
|
259
268
|
view.applyNativeHeaderStyle()
|
|
260
269
|
}
|
|
261
270
|
|
|
271
|
+
@ReactProp(name = "nativeTabBarInactiveTextColor", customType = "Color")
|
|
262
272
|
override fun setNativeTabBarInactiveTextColor(view: CollapsiblePagerHost?, value: Int?) {
|
|
263
273
|
view ?: return
|
|
264
274
|
view.nativeTabBarInactiveTextColor = value ?: Color.GRAY
|
|
265
275
|
view.applyNativeHeaderStyle()
|
|
266
276
|
}
|
|
267
277
|
|
|
278
|
+
@ReactProp(name = "nativeTabBarIndicatorColor", customType = "Color")
|
|
268
279
|
override fun setNativeTabBarIndicatorColor(view: CollapsiblePagerHost?, value: Int?) {
|
|
269
280
|
view ?: return
|
|
270
281
|
view.nativeTabBarIndicatorColor = value ?: view.nativeTabBarActiveTextColor
|
|
271
282
|
view.applyNativeHeaderStyle()
|
|
272
283
|
}
|
|
273
284
|
|
|
285
|
+
@ReactProp(name = "nativeTabBarIndicatorHeight")
|
|
274
286
|
override fun setNativeTabBarIndicatorHeight(view: CollapsiblePagerHost?, value: Double) {
|
|
275
287
|
view ?: return
|
|
276
288
|
view.nativeTabBarIndicatorHeight = value
|
|
277
289
|
view.applyNativeHeaderStyle()
|
|
278
290
|
}
|
|
279
291
|
|
|
292
|
+
@ReactProp(name = "nativeTabBarIndicatorBottom")
|
|
280
293
|
override fun setNativeTabBarIndicatorBottom(view: CollapsiblePagerHost?, value: Double) {
|
|
281
294
|
view ?: return
|
|
282
295
|
view.nativeTabBarIndicatorBottom = value
|
|
283
296
|
view.applyNativeHeaderStyle()
|
|
284
297
|
}
|
|
285
298
|
|
|
299
|
+
@ReactProp(name = "nativeSubHeaderConfig")
|
|
286
300
|
override fun setNativeSubHeaderConfig(view: CollapsiblePagerHost?, value: String?) {
|
|
287
301
|
view?.updateNativeSubHeader(value)
|
|
288
302
|
}
|
|
289
303
|
|
|
304
|
+
@ReactProp(name = "nativeSubHeaderSelectedBackgroundColor", customType = "Color")
|
|
290
305
|
override fun setNativeSubHeaderSelectedBackgroundColor(
|
|
291
306
|
view: CollapsiblePagerHost?,
|
|
292
307
|
value: Int?,
|