@@ -2,6 +2,8 @@ package com.reactnativepagerview
22
33import android.view.View
44import android.view.ViewGroup
5+ import androidx.recyclerview.widget.LinearLayoutManager
6+ import androidx.recyclerview.widget.RecyclerView
57import androidx.viewpager2.widget.ViewPager2
68import androidx.viewpager2.widget.ViewPager2.OnPageChangeCallback
79import com.facebook.infer.annotation.Assertions
@@ -41,13 +43,49 @@ class PagerViewViewManager : ViewGroupManager<NestedScrollableHost>(), RNCViewPa
4143 mDelegate.receiveCommand(root, commandId, args)
4244 }
4345
46+ /* *
47+ * Replaces ViewPager2's internal LayoutManager references with [safeLayoutManager] via reflection.
48+ * ViewPager2 caches the LayoutManager in multiple internal objects at construction time.
49+ * If we don't update all of them, components like ScrollEventAdapter will use the
50+ * stale (detached) LayoutManager and fail to report page changes correctly.
51+ * Each patch is isolated so a single failure doesn't prevent the others.
52+ */
53+ private fun patchViewPager2LayoutManager (vp : ViewPager2 , safeLayoutManager : SafeLinearLayoutManager ) {
54+ val vpFields = vp.javaClass.declaredFields
55+
56+ vpFields.firstOrNull { it.name == " mLayoutManager" }?.let { field ->
57+ field.isAccessible = true
58+ field.set(vp, safeLayoutManager)
59+ }
60+
61+ for (name in arrayOf(" mScrollEventAdapter" , " mPageTransformerAdapter" )) {
62+ vpFields.firstOrNull { it.name == name }?.let { adapterField ->
63+ adapterField.isAccessible = true
64+ val adapter = adapterField.get(vp) ? : return @let
65+ adapter.javaClass.declaredFields.firstOrNull { it.name == " mLayoutManager" }?.let { field ->
66+ field.isAccessible = true
67+ field.set(adapter, safeLayoutManager)
68+ }
69+ }
70+ }
71+ }
72+
4473 public override fun createViewInstance (reactContext : ThemedReactContext ): NestedScrollableHost {
4574 val host = NestedScrollableHost (reactContext)
4675 host.id = View .generateViewId()
4776 host.layoutParams = ViewGroup .LayoutParams (ViewGroup .LayoutParams .MATCH_PARENT , ViewGroup .LayoutParams .MATCH_PARENT )
4877 host.isSaveEnabled = false
4978 val vp = ViewPager2 (reactContext)
5079 vp.adapter = ViewPagerAdapter ()
80+ (vp.getChildAt(0 ) as ? RecyclerView )?.let { rv ->
81+ rv.itemAnimator = null
82+ val safeLayoutManager = SafeLinearLayoutManager (reactContext, vp)
83+ safeLayoutManager.orientation = rv.layoutManager?.let {
84+ (it as ? LinearLayoutManager )?.orientation
85+ } ? : RecyclerView .HORIZONTAL
86+ rv.layoutManager = safeLayoutManager
87+ patchViewPager2LayoutManager(vp, safeLayoutManager)
88+ }
5189 // https://github.com/callstack/react-native-viewpager/issues/183
5290 vp.isSaveEnabled = false
5391
@@ -88,6 +126,18 @@ class PagerViewViewManager : ViewGroupManager<NestedScrollableHost>(), RNCViewPa
88126 return host
89127 }
90128
129+ private fun stopScrollIfNeeded (host : NestedScrollableHost ) {
130+ val recyclerView = (host.getChildAt(0 ) as ? ViewPager2 )?.getChildAt(0 ) as ? RecyclerView
131+ recyclerView?.stopScroll()
132+ }
133+
134+ override fun onDropViewInstance (view : NestedScrollableHost ) {
135+ stopScrollIfNeeded(view)
136+ val recyclerView = (view.getChildAt(0 ) as ? ViewPager2 )?.getChildAt(0 ) as ? RecyclerView
137+ recyclerView?.swapAdapter(null , false )
138+ super .onDropViewInstance(view)
139+ }
140+
91141 override fun addView (host : NestedScrollableHost , child : View , index : Int ) {
92142 PagerViewViewManagerImpl .addView(host, child, index)
93143 }
@@ -99,14 +149,17 @@ class PagerViewViewManager : ViewGroupManager<NestedScrollableHost>(), RNCViewPa
99149 }
100150
101151 override fun removeView (parent : NestedScrollableHost , view : View ) {
152+ stopScrollIfNeeded(parent)
102153 PagerViewViewManagerImpl .removeView(parent, view)
103154 }
104155
105156 override fun removeAllViews (parent : NestedScrollableHost ) {
157+ stopScrollIfNeeded(parent)
106158 PagerViewViewManagerImpl .removeAllViews(parent)
107159 }
108160
109161 override fun removeViewAt (parent : NestedScrollableHost , index : Int ) {
162+ stopScrollIfNeeded(parent)
110163 PagerViewViewManagerImpl .removeViewAt(parent, index)
111164 }
112165
@@ -206,4 +259,4 @@ class PagerViewViewManager : ViewGroupManager<NestedScrollableHost>(), RNCViewPa
206259 PageScrollStateChangedEvent .EVENT_NAME , MapBuilder .of(" registrationName" , " onPageScrollStateChanged" ),
207260 PageSelectedEvent .EVENT_NAME , MapBuilder .of(" registrationName" , " onPageSelected" ))
208261 }
209- }
262+ }
0 commit comments