@onekeyfe/react-native-pager-view 6.7.0-2 → 6.7.0-20
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/README.md +14 -0
- package/android/src/androidTest/AndroidManifest.xml +7 -0
- package/android/src/androidTest/java/com/reactnativepagerview/CollapsiblePagerTabReservationTest.kt +306 -0
- package/android/src/main/java/com/reactnativepagerview/CollapsiblePagerHost.kt +90 -21
- package/android/src/main/java/com/reactnativepagerview/CollapsiblePagerNativeHeaders.kt +72 -7
- package/android/src/main/java/com/reactnativepagerview/CollapsiblePagerViewManager.kt +27 -0
- package/android/src/main/java/com/reactnativepagerview/NativeScrollerScrollAwayInsets.kt +19 -0
- package/android/src/main/java/com/reactnativepagerview/NativeScrollerView.kt +50 -6
- package/android/src/test/java/com/reactnativepagerview/NativeScrollerScrollAwayInsetsTest.kt +40 -0
- package/docs/SPEC.md +253 -10
- package/ios/RNCCollapsiblePagerViewComponentView.mm +614 -42
- package/ios/RNCNativeScrollerComponentView.h +2 -0
- package/ios/RNCNativeScrollerComponentView.mm +42 -0
- package/ios/tests/RNCCollapsiblePagerFirstFrameTests.mm +393 -0
- package/ios/tests/RNCCollapsiblePagerHitTestTests.mm +338 -0
- package/ios/tests/RNCCollapsiblePagerPressCancellationTests.mm +74 -9
- package/ios/tests/RNCCollapsiblePagerRefreshControlTests.mm +50 -0
- package/lib/module/CollapsiblePagerView.js +32 -7
- package/lib/module/CollapsiblePagerView.web.js +439 -39
- package/lib/module/CollapsiblePagerViewNativeComponent.ts +13 -0
- package/lib/module/NativeScroller.web.js +16 -3
- package/lib/module/WebCollapsiblePagerPage.js +182 -0
- package/lib/module/index.js +2 -0
- package/lib/module/index.native.js +9 -0
- package/lib/module/index.web.js +2 -0
- package/lib/typescript/src/CollapsiblePagerView.d.ts +10 -3
- package/lib/typescript/src/CollapsiblePagerView.web.d.ts +66 -3
- package/lib/typescript/src/CollapsiblePagerViewNativeComponent.d.ts +5 -0
- package/lib/typescript/src/WebCollapsiblePagerPage.d.ts +42 -0
- package/lib/typescript/src/index.d.ts +4 -0
- package/lib/typescript/src/index.native.d.ts +13 -0
- package/lib/typescript/src/index.web.d.ts +4 -0
- package/package.json +6 -4
- package/react-native-pager-view.podspec +1 -0
- package/src/CollapsiblePagerView.tsx +99 -8
- package/src/CollapsiblePagerView.web.tsx +657 -51
- package/src/CollapsiblePagerViewNativeComponent.ts +13 -0
- package/src/NativeScroller.web.tsx +24 -2
- package/src/WebCollapsiblePagerPage.tsx +258 -0
- package/src/index.native.tsx +30 -0
- package/src/index.tsx +4 -0
- package/src/index.web.tsx +4 -0
|
@@ -65,7 +65,11 @@ private class CollapsiblePagerHorizontalItemsView(
|
|
|
65
65
|
) : HorizontalScrollView(context) {
|
|
66
66
|
private val density = resources.displayMetrics.density
|
|
67
67
|
private val content = FrameLayout(context)
|
|
68
|
+
private val track = View(context)
|
|
68
69
|
private val indicator = View(context)
|
|
70
|
+
private val trackBackground = GradientDrawable().apply {
|
|
71
|
+
shape = GradientDrawable.RECTANGLE
|
|
72
|
+
}
|
|
69
73
|
private val indicatorBackground = GradientDrawable().apply {
|
|
70
74
|
shape = GradientDrawable.RECTANGLE
|
|
71
75
|
}
|
|
@@ -75,6 +79,8 @@ private class CollapsiblePagerHorizontalItemsView(
|
|
|
75
79
|
private var selectedKey = ""
|
|
76
80
|
private var rowHeightPx = dp(if (showsProgressIndicator) 44.0 else 42.0)
|
|
77
81
|
private var contentPaddingPx = dp(20.0)
|
|
82
|
+
private var contentPaddingVerticalPx = 0
|
|
83
|
+
private var segmented = false
|
|
78
84
|
private var itemSpacingPx = dp(8.0)
|
|
79
85
|
private var fontSize = if (showsProgressIndicator) 16.0 else 14.0
|
|
80
86
|
private var fontFamily: String? = null
|
|
@@ -96,7 +102,9 @@ private class CollapsiblePagerHorizontalItemsView(
|
|
|
96
102
|
isFillViewport = true
|
|
97
103
|
overScrollMode = OVER_SCROLL_NEVER
|
|
98
104
|
clipToPadding = false
|
|
105
|
+
track.background = trackBackground
|
|
99
106
|
indicator.background = indicatorBackground
|
|
107
|
+
content.addView(track, FrameLayout.LayoutParams(0, 0))
|
|
100
108
|
content.addView(indicator, FrameLayout.LayoutParams(0, 0))
|
|
101
109
|
addView(
|
|
102
110
|
content,
|
|
@@ -149,17 +157,24 @@ private class CollapsiblePagerHorizontalItemsView(
|
|
|
149
157
|
fontFamily: String?,
|
|
150
158
|
indicatorHeight: Double = 0.0,
|
|
151
159
|
indicatorBottom: Double = 0.0,
|
|
160
|
+
variant: String = "underline",
|
|
161
|
+
contentPaddingVertical: Double = 0.0,
|
|
152
162
|
) {
|
|
153
163
|
rowHeightPx = max(1, dp(rowHeight))
|
|
154
164
|
contentPaddingPx = max(0, dp(contentPadding))
|
|
165
|
+
contentPaddingVerticalPx = max(0, dp(contentPaddingVertical))
|
|
166
|
+
val wasSegmented = segmented
|
|
167
|
+
segmented = showsProgressIndicator && variant == "segmented"
|
|
155
168
|
itemSpacingPx = max(0, dp(itemSpacing))
|
|
156
169
|
this.fontSize = max(1.0, fontSize)
|
|
157
170
|
this.fontFamily = fontFamily
|
|
158
171
|
if (showsProgressIndicator) {
|
|
159
172
|
indicatorHeightPx = max(0, dp(indicatorHeight))
|
|
160
173
|
indicatorBottomPx = max(0, dp(indicatorBottom))
|
|
161
|
-
indicatorBackground.cornerRadius = indicatorHeightPx / 2f
|
|
174
|
+
indicatorBackground.cornerRadius = if (segmented) dp(14.0).toFloat() else indicatorHeightPx / 2f
|
|
162
175
|
}
|
|
176
|
+
track.visibility = if (segmented) VISIBLE else GONE
|
|
177
|
+
if (segmented && !wasSegmented) scrollTo(0, 0)
|
|
163
178
|
applyTypeface()
|
|
164
179
|
requestLayout()
|
|
165
180
|
}
|
|
@@ -171,8 +186,9 @@ private class CollapsiblePagerHorizontalItemsView(
|
|
|
171
186
|
selectedBackgroundColor: Int,
|
|
172
187
|
indicatorColor: Int,
|
|
173
188
|
) {
|
|
174
|
-
setBackgroundColor(backgroundColor)
|
|
175
|
-
content.setBackgroundColor(backgroundColor)
|
|
189
|
+
setBackgroundColor(if (segmented) Color.TRANSPARENT else backgroundColor)
|
|
190
|
+
content.setBackgroundColor(if (segmented) Color.TRANSPARENT else backgroundColor)
|
|
191
|
+
trackBackground.setColor(backgroundColor)
|
|
176
192
|
this.activeTextColor = activeTextColor
|
|
177
193
|
this.inactiveTextColor = inactiveTextColor
|
|
178
194
|
this.selectedBackgroundColor = selectedBackgroundColor
|
|
@@ -213,6 +229,46 @@ private class CollapsiblePagerHorizontalItemsView(
|
|
|
213
229
|
}
|
|
214
230
|
applyTypeface()
|
|
215
231
|
itemFrames.clear()
|
|
232
|
+
if (segmented) {
|
|
233
|
+
val actualPaddingHorizontal = min(contentPaddingPx, width / 2)
|
|
234
|
+
val actualPaddingVertical = min(contentPaddingVerticalPx, height / 2)
|
|
235
|
+
val trackLeft = actualPaddingHorizontal
|
|
236
|
+
val trackRight = max(trackLeft, width - contentPaddingPx)
|
|
237
|
+
val trackTop = actualPaddingVertical
|
|
238
|
+
val trackBottom = max(trackTop, height - contentPaddingVerticalPx)
|
|
239
|
+
val trackWidth = trackRight - trackLeft
|
|
240
|
+
val trackHeight = trackBottom - trackTop
|
|
241
|
+
trackBackground.cornerRadius = trackHeight / 2f
|
|
242
|
+
indicatorBackground.cornerRadius = max(0, trackHeight - dp(4.0)) / 2f
|
|
243
|
+
track.layoutParams = FrameLayout.LayoutParams(trackWidth, trackHeight).apply {
|
|
244
|
+
gravity = Gravity.TOP or Gravity.LEFT
|
|
245
|
+
leftMargin = trackLeft
|
|
246
|
+
topMargin = trackTop
|
|
247
|
+
}
|
|
248
|
+
buttons.forEachIndexed { index, button ->
|
|
249
|
+
val count = buttons.size
|
|
250
|
+
val first = trackLeft + trackWidth * index / count
|
|
251
|
+
val last = trackLeft + trackWidth * (index + 1) / count
|
|
252
|
+
val start = if (layoutDirection == View.LAYOUT_DIRECTION_RTL) trackRight - (last - trackLeft) else first
|
|
253
|
+
val end = if (layoutDirection == View.LAYOUT_DIRECTION_RTL) trackRight - (first - trackLeft) else last
|
|
254
|
+
val buttonWidth = max(0, end - start)
|
|
255
|
+
val thumbInset = dp(2.0)
|
|
256
|
+
itemFrames.add(intArrayOf(start, buttonWidth, start + thumbInset, max(0, buttonWidth - 2 * thumbInset)))
|
|
257
|
+
button.layoutParams = FrameLayout.LayoutParams(buttonWidth, trackHeight).apply {
|
|
258
|
+
gravity = Gravity.TOP or Gravity.LEFT
|
|
259
|
+
leftMargin = start
|
|
260
|
+
topMargin = trackTop
|
|
261
|
+
}
|
|
262
|
+
}
|
|
263
|
+
content.layoutParams = LayoutParams(width, height)
|
|
264
|
+
content.measure(
|
|
265
|
+
MeasureSpec.makeMeasureSpec(width, MeasureSpec.EXACTLY),
|
|
266
|
+
MeasureSpec.makeMeasureSpec(height, MeasureSpec.EXACTLY),
|
|
267
|
+
)
|
|
268
|
+
setMeasuredDimension(width, height)
|
|
269
|
+
return
|
|
270
|
+
}
|
|
271
|
+
track.layoutParams = FrameLayout.LayoutParams(0, 0)
|
|
216
272
|
var x = contentPaddingPx
|
|
217
273
|
buttons.forEachIndexed { index, button ->
|
|
218
274
|
val textWidth = ceil(button.paint.measureText(button.text.toString()).toDouble()).toInt()
|
|
@@ -260,6 +316,9 @@ private class CollapsiblePagerHorizontalItemsView(
|
|
|
260
316
|
return super.onTouchEvent(event)
|
|
261
317
|
}
|
|
262
318
|
|
|
319
|
+
override fun onInterceptTouchEvent(event: MotionEvent): Boolean =
|
|
320
|
+
if (segmented) false else super.onInterceptTouchEvent(event)
|
|
321
|
+
|
|
263
322
|
private fun updatePresentation() {
|
|
264
323
|
if (buttons.isEmpty() || itemFrames.size != buttons.size) return
|
|
265
324
|
val selectedIndex: Int
|
|
@@ -275,14 +334,16 @@ private class CollapsiblePagerHorizontalItemsView(
|
|
|
275
334
|
val interpolatedIndicatorWidth = from[3] + (to[3] - from[3]) * fraction
|
|
276
335
|
val indicatorX = interpolatedIndicatorX.roundToInt()
|
|
277
336
|
val indicatorWidth = interpolatedIndicatorWidth.roundToInt()
|
|
278
|
-
val
|
|
337
|
+
val actualPaddingVertical = min(contentPaddingVerticalPx, measuredHeight / 2)
|
|
338
|
+
val indicatorHeight = if (segmented) max(0, measuredHeight - 2 * actualPaddingVertical - dp(4.0)) else indicatorHeightPx
|
|
339
|
+
val indicatorTop = if (segmented) actualPaddingVertical + dp(2.0) else max(0, measuredHeight - indicatorBottomPx - indicatorHeightPx)
|
|
279
340
|
indicator.layout(
|
|
280
341
|
indicatorX,
|
|
281
342
|
indicatorTop,
|
|
282
343
|
indicatorX + indicatorWidth,
|
|
283
|
-
indicatorTop +
|
|
344
|
+
indicatorTop + indicatorHeight,
|
|
284
345
|
)
|
|
285
|
-
indicator.visibility = if (
|
|
346
|
+
indicator.visibility = if (indicatorHeight > 0) VISIBLE else GONE
|
|
286
347
|
scrollTargetCenterX = interpolatedIndicatorX + interpolatedIndicatorWidth / 2f
|
|
287
348
|
selectedIndex = clamped.roundToInt()
|
|
288
349
|
buttons.forEachIndexed { index, button ->
|
|
@@ -304,7 +365,7 @@ private class CollapsiblePagerHorizontalItemsView(
|
|
|
304
365
|
}
|
|
305
366
|
}
|
|
306
367
|
|
|
307
|
-
if (centerSelectionWhenIdle && !isTouchDragging && width > 0 && selectedIndex in itemFrames.indices) {
|
|
368
|
+
if (centerSelectionWhenIdle && !segmented && !isTouchDragging && width > 0 && selectedIndex in itemFrames.indices) {
|
|
308
369
|
val desired = (scrollTargetCenterX - width / 2f).roundToInt()
|
|
309
370
|
.coerceIn(0, max(0, content.measuredWidth - width))
|
|
310
371
|
scrollTo(desired, 0)
|
|
@@ -335,7 +396,9 @@ internal class CollapsiblePagerNativeTabBarView(context: Context) : FrameLayout(
|
|
|
335
396
|
|
|
336
397
|
fun updateStyle(
|
|
337
398
|
height: Double,
|
|
399
|
+
variant: String,
|
|
338
400
|
contentPadding: Double,
|
|
401
|
+
contentPaddingVertical: Double,
|
|
339
402
|
itemSpacing: Double,
|
|
340
403
|
fontSize: Double,
|
|
341
404
|
fontFamily: String?,
|
|
@@ -351,6 +414,8 @@ internal class CollapsiblePagerNativeTabBarView(context: Context) : FrameLayout(
|
|
|
351
414
|
fontFamily,
|
|
352
415
|
indicatorHeight,
|
|
353
416
|
indicatorBottom,
|
|
417
|
+
variant,
|
|
418
|
+
contentPaddingVertical,
|
|
354
419
|
)
|
|
355
420
|
requestLayout()
|
|
356
421
|
}
|
|
@@ -239,6 +239,18 @@ class CollapsiblePagerViewManager : ViewGroupManager<CollapsiblePagerHost>(),
|
|
|
239
239
|
view.applyNativeHeaderStyle()
|
|
240
240
|
}
|
|
241
241
|
|
|
242
|
+
@ReactProp(name = "nativeTabBarVariant")
|
|
243
|
+
override fun setNativeTabBarVariant(view: CollapsiblePagerHost?, value: String?) {
|
|
244
|
+
view ?: return
|
|
245
|
+
view.nativeTabBarVariant = if (value == "segmented") "segmented" else "underline"
|
|
246
|
+
view.applyNativeHeaderStyle()
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
@ReactProp(name = "nativeTabBarTrailingReservedWidth", defaultDouble = 0.0)
|
|
250
|
+
override fun setNativeTabBarTrailingReservedWidth(view: CollapsiblePagerHost?, value: Double) {
|
|
251
|
+
view?.nativeTabBarTrailingReservedWidth = value
|
|
252
|
+
}
|
|
253
|
+
|
|
242
254
|
@ReactProp(name = "nativeTabBarContentPaddingHorizontal")
|
|
243
255
|
override fun setNativeTabBarContentPaddingHorizontal(
|
|
244
256
|
view: CollapsiblePagerHost?,
|
|
@@ -249,6 +261,13 @@ class CollapsiblePagerViewManager : ViewGroupManager<CollapsiblePagerHost>(),
|
|
|
249
261
|
view.applyNativeHeaderStyle()
|
|
250
262
|
}
|
|
251
263
|
|
|
264
|
+
@ReactProp(name = "nativeTabBarContentPaddingVertical")
|
|
265
|
+
override fun setNativeTabBarContentPaddingVertical(view: CollapsiblePagerHost?, value: Double) {
|
|
266
|
+
view ?: return
|
|
267
|
+
view.nativeTabBarContentPaddingVertical = if (value.isFinite()) value.coerceAtLeast(0.0) else 0.0
|
|
268
|
+
view.applyNativeHeaderStyle()
|
|
269
|
+
}
|
|
270
|
+
|
|
252
271
|
@ReactProp(name = "nativeTabBarItemSpacing")
|
|
253
272
|
override fun setNativeTabBarItemSpacing(view: CollapsiblePagerHost?, value: Double) {
|
|
254
273
|
view ?: return
|
|
@@ -343,6 +362,14 @@ class CollapsiblePagerViewManager : ViewGroupManager<CollapsiblePagerHost>(),
|
|
|
343
362
|
view?.scrollToTop(target, animated)
|
|
344
363
|
}
|
|
345
364
|
|
|
365
|
+
override fun scrollHeaderBy(view: CollapsiblePagerHost?, delta: Double) {
|
|
366
|
+
view?.scrollHeaderBy(delta)
|
|
367
|
+
}
|
|
368
|
+
|
|
369
|
+
override fun scrollHeaderToOffset(view: CollapsiblePagerHost?, offset: Double) {
|
|
370
|
+
view?.scrollHeaderToOffset(offset)
|
|
371
|
+
}
|
|
372
|
+
|
|
346
373
|
override fun setPage(view: CollapsiblePagerHost?, selectedPage: Int) {
|
|
347
374
|
if (view != null && selectedPage in 0 until view.adapter.itemCount) {
|
|
348
375
|
view.beginPageTransition(selectedPage)
|
|
@@ -39,3 +39,22 @@ internal class NativeRefreshForegroundAlpha(initialAlpha: Float) {
|
|
|
39
39
|
return lastApplied
|
|
40
40
|
}
|
|
41
41
|
}
|
|
42
|
+
|
|
43
|
+
// Skip ViewPager2 RecyclerView layout when explicitly suppressed or when all React page
|
|
44
|
+
// children have been removed on unmount while rendered ViewHolder views remain attached.
|
|
45
|
+
internal fun shouldSuppressCollapsiblePagerRecyclerLayout(
|
|
46
|
+
isLayoutSuppressed: Boolean,
|
|
47
|
+
adapterItemCount: Int,
|
|
48
|
+
attachedPageCount: Int,
|
|
49
|
+
): Boolean = isLayoutSuppressed || (adapterItemCount <= 0 && attachedPageCount > 0)
|
|
50
|
+
|
|
51
|
+
internal fun shouldDrainCollapsiblePagerLayout(
|
|
52
|
+
isLayoutRequested: Boolean,
|
|
53
|
+
isLayoutSuppressed: Boolean,
|
|
54
|
+
isComputingLayout: Boolean,
|
|
55
|
+
width: Int,
|
|
56
|
+
height: Int,
|
|
57
|
+
adapterItemCount: Int,
|
|
58
|
+
): Boolean = adapterItemCount > 0 && isLayoutRequested && !isLayoutSuppressed &&
|
|
59
|
+
!isComputingLayout && width > 0 && height > 0
|
|
60
|
+
|
|
@@ -37,26 +37,50 @@ class NativeScrollerView(context: Context) : FrameLayout(context) {
|
|
|
37
37
|
setMeasuredDimension(MeasureSpec.getSize(widthSpec), MeasureSpec.getSize(heightSpec))
|
|
38
38
|
}
|
|
39
39
|
override fun onLayout(changed: Boolean, left: Int, top: Int, right: Int, bottom: Int) = Unit
|
|
40
|
+
|
|
41
|
+
override fun startViewTransition(view: View) {
|
|
42
|
+
super.startViewTransition(view)
|
|
43
|
+
if (view === reactChild) transitioningReactChild = view
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
override fun endViewTransition(view: View) {
|
|
47
|
+
super.endViewTransition(view)
|
|
48
|
+
if (transitioningReactChild === view) transitioningReactChild = null
|
|
49
|
+
if (retainedReactChild === view) {
|
|
50
|
+
clearRetainedGeometry()
|
|
51
|
+
if (isAttachedToWindow) scheduleLayout()
|
|
52
|
+
}
|
|
53
|
+
}
|
|
40
54
|
}
|
|
41
55
|
private val contentFrame = object : FrameLayout(context) {
|
|
42
56
|
override fun onMeasure(widthSpec: Int, heightSpec: Int) {
|
|
43
57
|
setMeasuredDimension(
|
|
44
|
-
max(MeasureSpec.getSize(widthSpec),
|
|
45
|
-
|
|
58
|
+
max(MeasureSpec.getSize(widthSpec), effectiveContentWidthPx + insetLeft + insetRight),
|
|
59
|
+
effectiveContentHeightPx + contentTop + insetBottom,
|
|
46
60
|
)
|
|
47
61
|
}
|
|
48
62
|
|
|
49
63
|
override fun onLayout(changed: Boolean, left: Int, top: Int, right: Int, bottom: Int) {
|
|
50
64
|
// Only the native origin layer moves. Fabric owns its React child's layout/transform.
|
|
65
|
+
val contentWidth = effectiveContentWidthPx
|
|
66
|
+
val contentHeight = effectiveContentHeightPx
|
|
51
67
|
contentOriginFrame.measure(
|
|
52
|
-
MeasureSpec.makeMeasureSpec(
|
|
53
|
-
MeasureSpec.makeMeasureSpec(
|
|
68
|
+
MeasureSpec.makeMeasureSpec(contentWidth, MeasureSpec.EXACTLY),
|
|
69
|
+
MeasureSpec.makeMeasureSpec(contentHeight, MeasureSpec.EXACTLY),
|
|
54
70
|
)
|
|
55
|
-
contentOriginFrame.layout(insetLeft, contentTop, insetLeft +
|
|
71
|
+
contentOriginFrame.layout(insetLeft, contentTop, insetLeft + contentWidth, contentTop + contentHeight)
|
|
56
72
|
}
|
|
57
73
|
}
|
|
58
74
|
private val pagerInsets = WeakHashMap<View, Int>()
|
|
59
75
|
private var reactChild: View? = null
|
|
76
|
+
private var transitioningReactChild: View? = null
|
|
77
|
+
private var retainedReactChild: View? = null
|
|
78
|
+
private var retainedContentWidthPx = 0
|
|
79
|
+
private var retainedContentHeightPx = 0
|
|
80
|
+
private val effectiveContentWidthPx: Int
|
|
81
|
+
get() = if (reactChild == null && retainedReactChild != null) retainedContentWidthPx else contentWidthPx
|
|
82
|
+
private val effectiveContentHeightPx: Int
|
|
83
|
+
get() = if (reactChild == null && retainedReactChild != null) retainedContentHeightPx else contentHeightPx
|
|
60
84
|
private var fabricState: StateWrapper? = null
|
|
61
85
|
private var lastOriginX: Int? = null
|
|
62
86
|
private var lastOriginY: Int? = null
|
|
@@ -172,6 +196,8 @@ class NativeScrollerView(context: Context) : FrameLayout(context) {
|
|
|
172
196
|
internal fun addReactChild(child: View, index: Int) {
|
|
173
197
|
require(index == 0 && reactChild == null) { "NativeScroller requires one React content view" }
|
|
174
198
|
viewport.stopMotion()
|
|
199
|
+
clearRetainedGeometry()
|
|
200
|
+
transitioningReactChild = null
|
|
175
201
|
reactChild = child
|
|
176
202
|
contentOriginFrame.addView(child)
|
|
177
203
|
scheduleLayout()
|
|
@@ -180,13 +206,29 @@ class NativeScrollerView(context: Context) : FrameLayout(context) {
|
|
|
180
206
|
internal fun removeReactChild() {
|
|
181
207
|
viewport.stopMotion()
|
|
182
208
|
pendingRestore.cancel()
|
|
183
|
-
reactChild?.let
|
|
209
|
+
reactChild?.let { child ->
|
|
210
|
+
clearRetainedGeometry()
|
|
211
|
+
// Fabric removes the child before its disappearing view finishes drawing.
|
|
212
|
+
if (transitioningReactChild === child &&
|
|
213
|
+
contentOriginFrame.width > 0 && contentOriginFrame.height > 0) {
|
|
214
|
+
retainedReactChild = child
|
|
215
|
+
retainedContentWidthPx = contentOriginFrame.width
|
|
216
|
+
retainedContentHeightPx = contentOriginFrame.height
|
|
217
|
+
}
|
|
218
|
+
contentOriginFrame.removeView(child)
|
|
219
|
+
}
|
|
184
220
|
reactChild = null
|
|
185
221
|
contentWidthPx = 0
|
|
186
222
|
contentHeightPx = 0
|
|
187
223
|
scheduleLayout()
|
|
188
224
|
}
|
|
189
225
|
|
|
226
|
+
private fun clearRetainedGeometry() {
|
|
227
|
+
retainedReactChild = null
|
|
228
|
+
retainedContentWidthPx = 0
|
|
229
|
+
retainedContentHeightPx = 0
|
|
230
|
+
}
|
|
231
|
+
|
|
190
232
|
internal fun reactChildCount() = if (reactChild == null) 0 else 1
|
|
191
233
|
internal fun reactChildAt(index: Int): View {
|
|
192
234
|
require(index == 0)
|
|
@@ -381,6 +423,8 @@ class NativeScrollerView(context: Context) : FrameLayout(context) {
|
|
|
381
423
|
lastContentViewportHeight = null
|
|
382
424
|
viewport.stopMotion()
|
|
383
425
|
viewport.setTag(R.id.onekey_native_scroll_coordinator_offset_listener, null)
|
|
426
|
+
transitioningReactChild = null
|
|
427
|
+
clearRetainedGeometry()
|
|
384
428
|
super.onDetachedFromWindow()
|
|
385
429
|
}
|
|
386
430
|
|
package/android/src/test/java/com/reactnativepagerview/NativeScrollerScrollAwayInsetsTest.kt
CHANGED
|
@@ -72,4 +72,44 @@ fun main() {
|
|
|
72
72
|
check(nativeRefreshForegroundTop(37 + 230 + 64, 294f) == 37f)
|
|
73
73
|
check(nativeRefreshForegroundTop(-40 + 294, 294f) == -40f)
|
|
74
74
|
println("Refresh foreground policy: repeat, owner transfer/release, external alpha, transparent baseline, caller offset, and combined nested inset passed")
|
|
75
|
+
|
|
76
|
+
// Initial mount before any page ViewHolder is attached still measures ViewPager2.
|
|
77
|
+
check(!shouldSuppressCollapsiblePagerRecyclerLayout(isLayoutSuppressed = false, adapterItemCount = 0, attachedPageCount = 0))
|
|
78
|
+
// Unmount removes all adapter pages while rendered ViewHolder views remain attached.
|
|
79
|
+
check(shouldSuppressCollapsiblePagerRecyclerLayout(isLayoutSuppressed = false, adapterItemCount = 0, attachedPageCount = 1))
|
|
80
|
+
check(shouldSuppressCollapsiblePagerRecyclerLayout(isLayoutSuppressed = true, adapterItemCount = 2, attachedPageCount = 1))
|
|
81
|
+
// Re-adding pages resumes ViewPager2 layout.
|
|
82
|
+
check(!shouldSuppressCollapsiblePagerRecyclerLayout(isLayoutSuppressed = false, adapterItemCount = 1, attachedPageCount = 1))
|
|
83
|
+
|
|
84
|
+
check(
|
|
85
|
+
!shouldDrainCollapsiblePagerLayout(
|
|
86
|
+
isLayoutRequested = true,
|
|
87
|
+
isLayoutSuppressed = false,
|
|
88
|
+
isComputingLayout = false,
|
|
89
|
+
width = 1080,
|
|
90
|
+
height = 2400,
|
|
91
|
+
adapterItemCount = 0,
|
|
92
|
+
),
|
|
93
|
+
)
|
|
94
|
+
check(
|
|
95
|
+
shouldDrainCollapsiblePagerLayout(
|
|
96
|
+
isLayoutRequested = true,
|
|
97
|
+
isLayoutSuppressed = false,
|
|
98
|
+
isComputingLayout = false,
|
|
99
|
+
width = 1080,
|
|
100
|
+
height = 2400,
|
|
101
|
+
adapterItemCount = 2,
|
|
102
|
+
),
|
|
103
|
+
)
|
|
104
|
+
check(
|
|
105
|
+
!shouldDrainCollapsiblePagerLayout(
|
|
106
|
+
isLayoutRequested = true,
|
|
107
|
+
isLayoutSuppressed = true,
|
|
108
|
+
isComputingLayout = false,
|
|
109
|
+
width = 1080,
|
|
110
|
+
height = 2400,
|
|
111
|
+
adapterItemCount = 2,
|
|
112
|
+
),
|
|
113
|
+
)
|
|
114
|
+
println("CollapsiblePager unmount layout guard: initial mount, unmount retention, suppression, and re-add passed")
|
|
75
115
|
}
|