@onekeyfe/react-native-pager-view 3.0.118 → 3.0.120

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.
@@ -226,6 +226,7 @@ dependencies {
226
226
  implementation "com.facebook.react:react-android"
227
227
  implementation "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version"
228
228
  implementation 'androidx.viewpager2:viewpager2:1.1.0'
229
+ implementation project(":onekeyfe_react-native-native-logger")
229
230
  }
230
231
 
231
232
  if (isNewArchitectureEnabled()) {
@@ -2,9 +2,13 @@ package com.reactnativepagerview
2
2
 
3
3
  import android.content.Context
4
4
  import android.graphics.Rect
5
+ import android.os.SystemClock
6
+ import android.view.MotionEvent
5
7
  import android.view.View
8
+ import android.view.ViewConfiguration
6
9
  import android.view.ViewGroup
7
10
  import android.view.ViewTreeObserver
11
+ import android.widget.HorizontalScrollView
8
12
  // OneKey patch: FrameLayout is inherited through NestedScrollableHost.
9
13
  // import android.widget.FrameLayout
10
14
  import androidx.core.view.NestedScrollingParent3
@@ -13,6 +17,8 @@ import androidx.core.view.ViewCompat
13
17
  import androidx.recyclerview.widget.LinearLayoutManager
14
18
  import androidx.recyclerview.widget.RecyclerView
15
19
  import androidx.viewpager2.widget.ViewPager2
20
+ import com.facebook.react.uimanager.events.NativeGestureUtil
21
+ import com.margelo.nitro.nativelogger.OneKeyLog
16
22
  import java.util.WeakHashMap
17
23
  import kotlin.math.max
18
24
  import kotlin.math.min
@@ -72,6 +78,13 @@ internal class CollapsiblePagerAdapter : RecyclerView.Adapter<ViewPagerViewHolde
72
78
  // OneKey patch: Match the standard pager's nested horizontal gesture host.
73
79
  // Original: class CollapsiblePagerHost(context: Context) : FrameLayout(context), NestedScrollingParent3 {
74
80
  class CollapsiblePagerHost(context: Context) : NestedScrollableHost(context), NestedScrollingParent3 {
81
+ private enum class HeaderGestureOwner {
82
+ NONE,
83
+ LIST,
84
+ HORIZONTAL_CHILD,
85
+ HEADER_GUARD,
86
+ }
87
+
75
88
  private data class RecyclerPadding(
76
89
  var left: Int,
77
90
  var top: Int,
@@ -83,6 +96,8 @@ class CollapsiblePagerHost(context: Context) : NestedScrollableHost(context), Ne
83
96
 
84
97
  val pager = ViewPager2(context)
85
98
  internal val adapter = CollapsiblePagerAdapter()
99
+ private val nativeTabBarView = CollapsiblePagerNativeTabBarView(context)
100
+ private val nativeSubHeaderView = CollapsiblePagerNativeSubHeaderView(context)
86
101
  private val logicalChildren = ArrayList<View>()
87
102
  private val nestedScrollingParentHelper = NestedScrollingParentHelper(this)
88
103
  private val originalRecyclerPadding = WeakHashMap<RecyclerView, RecyclerPadding>()
@@ -91,8 +106,20 @@ class CollapsiblePagerHost(context: Context) : NestedScrollableHost(context), Ne
91
106
  private var observedRecyclerView: RecyclerView? = null
92
107
  private var observedScrollListener: RecyclerView.OnScrollListener? = null
93
108
  private var attachmentGeneration = 0
109
+ private val touchSlopPx = ViewConfiguration.get(context).scaledTouchSlop
110
+ private val hostIdentity = System.identityHashCode(this)
94
111
  private var headerView: View? = null
95
112
  private var stickyHeaderView: View? = null
113
+ private var headerTouchActive = false
114
+ private var headerTouchRegion = "none"
115
+ private var headerGestureOwner = HeaderGestureOwner.NONE
116
+ private var headerDownX = 0f
117
+ private var headerDownY = 0f
118
+ private var headerDownEvent: MotionEvent? = null
119
+ private var headerHasHorizontalChild = false
120
+ private var forwardedRecycler: RecyclerView? = null
121
+ private var nativeGestureStarted = false
122
+ private var pressCancelled = false
96
123
  private val pageContentLayoutListener = ViewTreeObserver.OnPreDrawListener {
97
124
  if (width > 0 && height > 0 && isShown) layoutPagerIfRequested()
98
125
  // Fabric can mount a retained list without another Android layout pass.
@@ -128,6 +155,22 @@ class CollapsiblePagerHost(context: Context) : NestedScrollableHost(context), Ne
128
155
  var pageKeys: List<String> = emptyList()
129
156
  var retainedPages: String = "[]"
130
157
  var onHeaderOffsetChanged: (() -> Unit)? = null
158
+ var nativeSmoothHeaderScrollEnabled = false
159
+ var onNativeTabPress: ((Int, String) -> Unit)? = null
160
+ var onNativeSubHeaderPress: ((Int, String) -> Unit)? = null
161
+
162
+ var nativeTabBarHeight = 44.0
163
+ var nativeTabBarContentPaddingHorizontal = 20.0
164
+ var nativeTabBarItemSpacing = 8.0
165
+ var nativeTabBarFontSize = 16.0
166
+ var nativeTabBarFontFamily: String? = null
167
+ var nativeTabBarBackgroundColor = android.graphics.Color.TRANSPARENT
168
+ var nativeTabBarActiveTextColor = android.graphics.Color.BLACK
169
+ var nativeTabBarInactiveTextColor = android.graphics.Color.GRAY
170
+ var nativeTabBarIndicatorColor = android.graphics.Color.BLACK
171
+ var nativeTabBarIndicatorHeight = 2.0
172
+ var nativeTabBarIndicatorBottom = 0.0
173
+ var nativeSubHeaderSelectedBackgroundColor = android.graphics.Color.TRANSPARENT
131
174
 
132
175
  init {
133
176
  isSaveEnabled = false
@@ -139,6 +182,88 @@ class CollapsiblePagerHost(context: Context) : NestedScrollableHost(context), Ne
139
182
  pager,
140
183
  LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT),
141
184
  )
185
+ nativeTabBarView.onItemPress = { index, key -> onNativeTabPress?.invoke(index, key) }
186
+ nativeSubHeaderView.onItemPress = { index, key -> onNativeSubHeaderPress?.invoke(index, key) }
187
+ super.addView(nativeTabBarView)
188
+ super.addView(nativeSubHeaderView)
189
+ applyNativeHeaderStyle()
190
+ log("host-init generation=$attachmentGeneration")
191
+ }
192
+
193
+ private fun log(message: String) {
194
+ OneKeyLog.debug("CollapsiblePager", "host=$hostIdentity $message")
195
+ }
196
+
197
+ private fun outerPagerIndex(): Int {
198
+ var ancestor = parent as? View
199
+ while (ancestor != null) {
200
+ if (ancestor is ViewPager2) return ancestor.currentItem
201
+ ancestor = ancestor.parent as? View
202
+ }
203
+ return -1
204
+ }
205
+
206
+ fun updateNativeTabBarItems(value: String?) {
207
+ nativeTabBarView.updateItemsJSON(value)
208
+ bringNativeHeadersToFront()
209
+ updateHeaderLayout()
210
+ }
211
+
212
+ fun updateNativeSubHeader(value: String?) {
213
+ nativeSubHeaderView.updateConfigJSON(value)
214
+ applyNativeHeaderStyle()
215
+ bringNativeHeadersToFront()
216
+ updateHeaderLayout()
217
+ }
218
+
219
+ fun updateNativeTabProgress(position: Int, offset: Float) {
220
+ nativeTabBarView.setProgress(position + offset)
221
+ }
222
+
223
+ fun logPagerState(reason: String) {
224
+ log(
225
+ "pager-state reason=$reason inner=$selectedPage outer=${outerPagerIndex()} " +
226
+ "nativePages=${adapter.itemCount} attachedPages=${attachedPageCount()} " +
227
+ "headerOffset=$headerOffsetPx retained=$retainedPages",
228
+ )
229
+ }
230
+
231
+ fun setPagerLayoutDirection(layoutDirection: Int) {
232
+ pager.layoutDirection = layoutDirection
233
+ nativeTabBarView.layoutDirection = layoutDirection
234
+ nativeSubHeaderView.layoutDirection = layoutDirection
235
+ nativeSubHeaderView.requestLayout()
236
+ }
237
+
238
+ fun applyNativeHeaderStyle() {
239
+ nativeTabBarView.updateStyle(
240
+ nativeTabBarHeight,
241
+ nativeTabBarContentPaddingHorizontal,
242
+ nativeTabBarItemSpacing,
243
+ nativeTabBarFontSize,
244
+ nativeTabBarFontFamily,
245
+ nativeTabBarIndicatorHeight,
246
+ nativeTabBarIndicatorBottom,
247
+ )
248
+ nativeTabBarView.updateColors(
249
+ nativeTabBarBackgroundColor,
250
+ nativeTabBarActiveTextColor,
251
+ nativeTabBarInactiveTextColor,
252
+ nativeTabBarIndicatorColor,
253
+ )
254
+ nativeSubHeaderView.updateColors(
255
+ nativeTabBarBackgroundColor,
256
+ nativeTabBarActiveTextColor,
257
+ nativeTabBarInactiveTextColor,
258
+ nativeSubHeaderSelectedBackgroundColor,
259
+ nativeTabBarFontFamily,
260
+ )
261
+ updateHeaderLayout()
262
+ }
263
+
264
+ private fun bringNativeHeadersToFront() {
265
+ nativeTabBarView.bringToFront()
266
+ nativeSubHeaderView.bringToFront()
142
267
  }
143
268
 
144
269
  fun addReactChild(child: View, index: Int) {
@@ -160,7 +285,11 @@ class CollapsiblePagerHost(context: Context) : NestedScrollableHost(context), Ne
160
285
  applyPendingInitialPage()
161
286
  headerView?.bringToFront()
162
287
  stickyHeaderView?.bringToFront()
288
+ bringNativeHeadersToFront()
163
289
  requestLayout()
290
+ if (safeIndex >= PAGE_SLOT_OFFSET) {
291
+ log("page-attach slot=${safeIndex - PAGE_SLOT_OFFSET} nativePages=${adapter.itemCount}")
292
+ }
164
293
  }
165
294
 
166
295
  fun removeReactChild(child: View) {
@@ -179,6 +308,7 @@ class CollapsiblePagerHost(context: Context) : NestedScrollableHost(context), Ne
179
308
  else -> {
180
309
  findVerticalRecyclerView(child)?.let(::restoreRecyclerInsets)
181
310
  adapter.removePage(child)
311
+ log("page-detach slot=${index - PAGE_SLOT_OFFSET} nativePages=${adapter.itemCount}")
182
312
  }
183
313
  }
184
314
  }
@@ -195,6 +325,7 @@ class CollapsiblePagerHost(context: Context) : NestedScrollableHost(context), Ne
195
325
  logicalChildren.clear()
196
326
  adapter.clear()
197
327
  hasAppliedInitialPage = false
328
+ log("pages-clear")
198
329
  }
199
330
 
200
331
  fun reactChildCount() = logicalChildren.size
@@ -285,6 +416,20 @@ class CollapsiblePagerHost(context: Context) : NestedScrollableHost(context), Ne
285
416
  MeasureSpec.makeMeasureSpec(width, MeasureSpec.EXACTLY),
286
417
  MeasureSpec.makeMeasureSpec(stickyHeaderHeightPx, MeasureSpec.EXACTLY),
287
418
  )
419
+ val nativeTabHeight = if (nativeTabBarView.visibility == View.VISIBLE) {
420
+ nativeTabBarView.preferredHeightPx()
421
+ } else 0
422
+ nativeTabBarView.measure(
423
+ MeasureSpec.makeMeasureSpec(width, MeasureSpec.EXACTLY),
424
+ MeasureSpec.makeMeasureSpec(nativeTabHeight, MeasureSpec.EXACTLY),
425
+ )
426
+ val nativeSubHeaderHeight = if (nativeSubHeaderView.visibility == View.VISIBLE) {
427
+ nativeSubHeaderView.preferredHeightPx()
428
+ } else 0
429
+ nativeSubHeaderView.measure(
430
+ MeasureSpec.makeMeasureSpec(width, MeasureSpec.EXACTLY),
431
+ MeasureSpec.makeMeasureSpec(nativeSubHeaderHeight, MeasureSpec.EXACTLY),
432
+ )
288
433
  setMeasuredDimension(width, height)
289
434
  }
290
435
 
@@ -302,6 +447,14 @@ class CollapsiblePagerHost(context: Context) : NestedScrollableHost(context), Ne
302
447
  width,
303
448
  headerHeightPx + stickyHeaderHeightPx,
304
449
  )
450
+ val nativeTabHeight = nativeTabBarView.measuredHeight
451
+ nativeTabBarView.layout(0, headerHeightPx, width, headerHeightPx + nativeTabHeight)
452
+ nativeSubHeaderView.layout(
453
+ 0,
454
+ headerHeightPx + nativeTabHeight,
455
+ width,
456
+ headerHeightPx + nativeTabHeight + nativeSubHeaderView.measuredHeight,
457
+ )
305
458
  applyHeaderOffset()
306
459
  postForCurrentAttachment {
307
460
  prepareAdjacentPages()
@@ -333,6 +486,8 @@ class CollapsiblePagerHost(context: Context) : NestedScrollableHost(context), Ne
333
486
  pager.translationY = -offset
334
487
  headerView?.translationY = -offset
335
488
  stickyHeaderView?.translationY = -offset
489
+ nativeTabBarView.translationY = -offset
490
+ nativeSubHeaderView.translationY = -offset
336
491
  }
337
492
 
338
493
  private fun pageKey(index: Int): String = pageKeys.getOrNull(index) ?: "page-$index"
@@ -408,7 +563,10 @@ class CollapsiblePagerHost(context: Context) : NestedScrollableHost(context), Ne
408
563
  }
409
564
  observedScrollListener = listener
410
565
  recycler.addOnScrollListener(listener)
411
-
566
+ log(
567
+ "list-observer-attach inner=$selectedPage key=${currentPageKey()} " +
568
+ "recycler=${System.identityHashCode(recycler)}",
569
+ )
412
570
  }
413
571
 
414
572
  private fun detachRecyclerObserver() {
@@ -416,6 +574,12 @@ class CollapsiblePagerHost(context: Context) : NestedScrollableHost(context), Ne
416
574
  val recycler = observedRecyclerView
417
575
  val listener = observedScrollListener
418
576
  if (recycler != null && listener != null) recycler.removeOnScrollListener(listener)
577
+ if (recycler != null) {
578
+ log(
579
+ "list-observer-detach inner=$selectedPage key=${currentPageKey()} " +
580
+ "recycler=${System.identityHashCode(recycler)}",
581
+ )
582
+ }
419
583
  observedRecyclerView = null
420
584
  observedScrollListener = null
421
585
  }
@@ -513,6 +677,195 @@ class CollapsiblePagerHost(context: Context) : NestedScrollableHost(context), Ne
513
677
  recycler.setPadding(original.left, original.top, original.right, original.bottom)
514
678
  }
515
679
 
680
+ private fun headerRegionAt(y: Float): String? {
681
+ val headerBottom = headerHeightPx - headerOffsetPx
682
+ val stickyBottom = headerHeightPx + stickyHeaderHeightPx - headerOffsetPx
683
+ return when {
684
+ y < 0 || y >= stickyBottom -> null
685
+ y < headerBottom -> "header"
686
+ y < headerBottom + nativeTabBarView.measuredHeight &&
687
+ nativeTabBarView.visibility == View.VISIBLE -> "primary-tab"
688
+ y < headerBottom + nativeTabBarView.measuredHeight + nativeSubHeaderView.measuredHeight &&
689
+ nativeSubHeaderView.visibility == View.VISIBLE -> "secondary-header"
690
+ else -> "sticky-controls"
691
+ }
692
+ }
693
+
694
+ private fun deepestChildAt(group: ViewGroup, x: Float, y: Float): View {
695
+ for (index in group.childCount - 1 downTo 0) {
696
+ val child = group.getChildAt(index)
697
+ if (child.visibility != View.VISIBLE || child.alpha <= 0f) continue
698
+ val localX = x + group.scrollX - child.left - child.translationX
699
+ val localY = y + group.scrollY - child.top - child.translationY
700
+ if (localX < 0 || localY < 0 || localX >= child.width || localY >= child.height) continue
701
+ return if (child is ViewGroup) deepestChildAt(child, localX, localY) else child
702
+ }
703
+ return group
704
+ }
705
+
706
+ private fun hasHorizontalScrollOwner(x: Float, y: Float): Boolean {
707
+ var target: View? = deepestChildAt(this, x, y)
708
+ while (target != null && target !== this) {
709
+ if (
710
+ target is HorizontalScrollView ||
711
+ target.canScrollHorizontally(-1) ||
712
+ target.canScrollHorizontally(1) ||
713
+ (target is RecyclerView &&
714
+ (target.layoutManager as? LinearLayoutManager)?.orientation == RecyclerView.HORIZONTAL)
715
+ ) {
716
+ return true
717
+ }
718
+ target = target.parent as? View
719
+ }
720
+ return false
721
+ }
722
+
723
+ private fun cancelHeaderPress(event: MotionEvent, owner: String) {
724
+ if (pressCancelled) return
725
+ pressCancelled = true
726
+ val cancel = MotionEvent.obtain(event).apply { action = MotionEvent.ACTION_CANCEL }
727
+ super.dispatchTouchEvent(cancel)
728
+ cancel.recycle()
729
+ if (!nativeGestureStarted) {
730
+ NativeGestureUtil.notifyNativeGestureStarted(this, event)
731
+ nativeGestureStarted = true
732
+ }
733
+ log(
734
+ "press-cancel owner=$owner region=$headerTouchRegion " +
735
+ "inner=$selectedPage outer=${outerPagerIndex()}",
736
+ )
737
+ }
738
+
739
+ private fun dispatchToRecycler(recycler: RecyclerView, event: MotionEvent): Boolean {
740
+ val hostLocation = IntArray(2)
741
+ val recyclerLocation = IntArray(2)
742
+ getLocationOnScreen(hostLocation)
743
+ recycler.getLocationOnScreen(recyclerLocation)
744
+ val copy = MotionEvent.obtain(event)
745
+ copy.offsetLocation(
746
+ (hostLocation[0] - recyclerLocation[0]).toFloat(),
747
+ (hostLocation[1] - recyclerLocation[1]).toFloat(),
748
+ )
749
+ val handled = recycler.dispatchTouchEvent(copy)
750
+ copy.recycle()
751
+ return handled
752
+ }
753
+
754
+ private fun beginForwardingToRecycler(event: MotionEvent): Boolean {
755
+ val recycler = recyclerViewForPage(selectedPage) ?: return false
756
+ forwardedRecycler = recycler
757
+ headerDownEvent?.let { down -> dispatchToRecycler(recycler, down) }
758
+ return dispatchToRecycler(recycler, event)
759
+ }
760
+
761
+ private fun finishHeaderGesture(event: MotionEvent) {
762
+ val owner = headerGestureOwner.name.lowercase()
763
+ if (nativeGestureStarted) {
764
+ NativeGestureUtil.notifyNativeGestureEnded(this, event)
765
+ nativeGestureStarted = false
766
+ }
767
+ log(
768
+ "gesture-end action=${event.actionMasked} owner=$owner region=$headerTouchRegion " +
769
+ "inner=$selectedPage outer=${outerPagerIndex()} durationMs=" +
770
+ "${SystemClock.uptimeMillis() - event.downTime}",
771
+ )
772
+ headerDownEvent?.recycle()
773
+ headerDownEvent = null
774
+ headerTouchActive = false
775
+ headerTouchRegion = "none"
776
+ headerGestureOwner = HeaderGestureOwner.NONE
777
+ headerHasHorizontalChild = false
778
+ forwardedRecycler = null
779
+ pressCancelled = false
780
+ }
781
+
782
+ override fun dispatchTouchEvent(e: MotionEvent): Boolean {
783
+ val event = e
784
+ if (!nativeSmoothHeaderScrollEnabled) return super.dispatchTouchEvent(event)
785
+
786
+ when (event.actionMasked) {
787
+ MotionEvent.ACTION_DOWN -> {
788
+ headerDownEvent?.recycle()
789
+ headerDownEvent = null
790
+ headerGestureOwner = HeaderGestureOwner.NONE
791
+ forwardedRecycler = null
792
+ pressCancelled = false
793
+ nativeGestureStarted = false
794
+ headerTouchRegion = headerRegionAt(event.y) ?: "none"
795
+ headerTouchActive = headerTouchRegion != "none"
796
+ if (!headerTouchActive) return super.dispatchTouchEvent(event)
797
+ headerDownX = event.x
798
+ headerDownY = event.y
799
+ headerDownEvent = MotionEvent.obtain(event)
800
+ headerHasHorizontalChild = hasHorizontalScrollOwner(event.x, event.y)
801
+ parent.requestDisallowInterceptTouchEvent(true)
802
+ log(
803
+ "gesture-begin region=$headerTouchRegion owner=pending " +
804
+ "horizontalChild=$headerHasHorizontalChild inner=$selectedPage " +
805
+ "outer=${outerPagerIndex()} headerOffset=$headerOffsetPx",
806
+ )
807
+ return super.dispatchTouchEvent(event)
808
+ }
809
+
810
+ MotionEvent.ACTION_MOVE -> {
811
+ if (!headerTouchActive) return super.dispatchTouchEvent(event)
812
+ if (headerGestureOwner == HeaderGestureOwner.NONE) {
813
+ val dx = event.x - headerDownX
814
+ val dy = event.y - headerDownY
815
+ if (kotlin.math.abs(dx) <= touchSlopPx && kotlin.math.abs(dy) <= touchSlopPx) {
816
+ return super.dispatchTouchEvent(event)
817
+ }
818
+ headerGestureOwner = when {
819
+ kotlin.math.abs(dy) > kotlin.math.abs(dx) -> HeaderGestureOwner.LIST
820
+ headerHasHorizontalChild -> HeaderGestureOwner.HORIZONTAL_CHILD
821
+ else -> HeaderGestureOwner.HEADER_GUARD
822
+ }
823
+ log(
824
+ "direction-lock owner=${headerGestureOwner.name.lowercase()} " +
825
+ "region=$headerTouchRegion dx=${dx.roundToInt()} dy=${dy.roundToInt()} " +
826
+ "inner=$selectedPage outer=${outerPagerIndex()}",
827
+ )
828
+ }
829
+ parent.requestDisallowInterceptTouchEvent(true)
830
+ return when (headerGestureOwner) {
831
+ HeaderGestureOwner.LIST -> {
832
+ cancelHeaderPress(event, "list")
833
+ val recycler = forwardedRecycler
834
+ if (recycler != null) {
835
+ dispatchToRecycler(recycler, event)
836
+ } else if (beginForwardingToRecycler(event)) {
837
+ true
838
+ } else {
839
+ headerGestureOwner = HeaderGestureOwner.HEADER_GUARD
840
+ log("gesture-list-unavailable region=$headerTouchRegion inner=$selectedPage")
841
+ true
842
+ }
843
+ }
844
+ HeaderGestureOwner.HORIZONTAL_CHILD -> super.dispatchTouchEvent(event)
845
+ HeaderGestureOwner.HEADER_GUARD -> {
846
+ cancelHeaderPress(event, "header-guard")
847
+ true
848
+ }
849
+ HeaderGestureOwner.NONE -> super.dispatchTouchEvent(event)
850
+ }
851
+ }
852
+
853
+ MotionEvent.ACTION_UP, MotionEvent.ACTION_CANCEL -> {
854
+ if (!headerTouchActive) return super.dispatchTouchEvent(event)
855
+ val handled = when (headerGestureOwner) {
856
+ HeaderGestureOwner.LIST -> forwardedRecycler?.let { recycler ->
857
+ dispatchToRecycler(recycler, event)
858
+ } ?: true
859
+ HeaderGestureOwner.HEADER_GUARD -> true
860
+ else -> super.dispatchTouchEvent(event)
861
+ }
862
+ finishHeaderGesture(event)
863
+ return handled
864
+ }
865
+ }
866
+ return super.dispatchTouchEvent(event)
867
+ }
868
+
516
869
  private fun isCurrentPageTarget(target: View): Boolean {
517
870
  if (selectedPage !in 0 until adapter.itemCount) return false
518
871
  return isDescendant(target, adapter.pageAt(selectedPage))
@@ -612,15 +965,29 @@ class CollapsiblePagerHost(context: Context) : NestedScrollableHost(context), Ne
612
965
  attachmentGeneration += 1
613
966
  restoredRecyclerKeys.clear()
614
967
  viewTreeObserver.addOnPreDrawListener(pageContentLayoutListener)
968
+ log(
969
+ "host-attach generation=$attachmentGeneration inner=$selectedPage " +
970
+ "outer=${outerPagerIndex()} nativePages=${adapter.itemCount}",
971
+ )
615
972
  }
616
973
 
617
974
  override fun onDetachedFromWindow() {
618
975
  attachmentGeneration += 1
976
+ headerDownEvent?.recycle()
977
+ headerDownEvent = null
978
+ headerTouchActive = false
979
+ forwardedRecycler = null
980
+ pressCancelled = false
981
+ nativeGestureStarted = false
619
982
  viewTreeObserver.removeOnPreDrawListener(pageContentLayoutListener)
620
983
  detachRecyclerObserver()
621
984
  for (recycler in originalRecyclerPadding.keys.toList()) {
622
985
  restoreRecyclerInsets(recycler)
623
986
  }
987
+ log(
988
+ "host-detach generation=$attachmentGeneration inner=$selectedPage " +
989
+ "outer=${outerPagerIndex()} nativePages=${adapter.itemCount}",
990
+ )
624
991
  super.onDetachedFromWindow()
625
992
  }
626
993