Skip to content

Commit 5ac4b7e

Browse files
authored
fix(android): fix crash on pager unmount (#1001)
1 parent af4d585 commit 5ac4b7e

File tree

3 files changed

+28
-7
lines changed

3 files changed

+28
-7
lines changed

android/src/main/java/com/reactnativepagerview/PagerViewViewManagerImpl.kt

Lines changed: 26 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,15 @@ import android.view.View
44
import android.view.ViewGroup
55
import androidx.viewpager2.widget.ViewPager2
66
import com.facebook.react.uimanager.PixelUtil
7+
import android.os.Handler
8+
import android.os.Looper
9+
import android.view.Choreographer
710

811
object PagerViewViewManagerImpl {
912
const val NAME = "RNCViewPager"
1013

14+
private var refreshFrameCallback: Choreographer.FrameCallback? = null
15+
1116
fun getViewPager(view: NestedScrollableHost): ViewPager2 {
1217
if (view.getChildAt(0) is ViewPager2) {
1318
return view.getChildAt(0) as ViewPager2
@@ -78,8 +83,8 @@ object PagerViewViewManagerImpl {
7883
}
7984

8085
adapter?.removeChildAt(index)
81-
82-
refreshViewChildrenLayout(pager)
86+
87+
debouncedRefreshViewChildrenLayout(pager)
8388
}
8489

8590
fun needsCustomLayoutForChildren(): Boolean {
@@ -157,9 +162,26 @@ object PagerViewViewManagerImpl {
157162
private fun refreshViewChildrenLayout(view: View) {
158163
view.post {
159164
view.measure(
160-
View.MeasureSpec.makeMeasureSpec(view.width, View.MeasureSpec.EXACTLY),
161-
View.MeasureSpec.makeMeasureSpec(view.height, View.MeasureSpec.EXACTLY))
165+
View.MeasureSpec.makeMeasureSpec(view.width, View.MeasureSpec.EXACTLY),
166+
View.MeasureSpec.makeMeasureSpec(view.height, View.MeasureSpec.EXACTLY))
162167
view.layout(view.left, view.top, view.right, view.bottom)
163168
}
164169
}
170+
171+
private fun debouncedRefreshViewChildrenLayout(view: View) {
172+
// Fixes https://github.com/callstack/react-native-pager-view/issues/946
173+
refreshFrameCallback?.let { Choreographer.getInstance().removeFrameCallback(it) }
174+
175+
val adapter = (view as? ViewPager2)?.adapter as? ViewPagerAdapter
176+
if (adapter == null || adapter.itemCount == 0) {
177+
// Do not call refreshViewChildrenLayout on pager unmount
178+
return
179+
}
180+
181+
refreshFrameCallback = Choreographer.FrameCallback {
182+
refreshViewChildrenLayout(view)
183+
refreshFrameCallback = null
184+
}
185+
Choreographer.getInstance().postFrameCallback(refreshFrameCallback)
186+
}
165187
}

example/src/App.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -95,7 +95,7 @@ const Stack = createStackNavigator();
9595
const NativeStack = createNativeStackNavigator();
9696

9797
export function Navigation() {
98-
const [mode, setMode] = React.useState<'native' | 'js'>('js');
98+
const [mode, setMode] = React.useState<'native' | 'js'>('native');
9999
const NavigationStack = mode === 'js' ? Stack : NativeStack;
100100
return (
101101
<SafeAreaProvider>

example/src/OnPageScrollExample.tsx

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
import React from 'react';
2-
import { StyleSheet, Text, View, SafeAreaView, Animated } from 'react-native';
2+
import { StyleSheet, Text, View, SafeAreaView, Animated, ScrollView, TouchableOpacity } from 'react-native';
33
import PagerView from 'react-native-pager-view';
4-
import { ScrollView, TouchableOpacity } from 'react-native-gesture-handler';
54
import { ProgressBar } from './component/ProgressBar';
65
import { useNavigationPanel } from './hook/useNavigationPanel';
76

0 commit comments

Comments
 (0)