useDrawerProgress报错未找到抽屉导航器的动画实现方案
报错现象
运行项目时触发如下报错:
Error: Couldn't find a drawer. Is your component inside a drawer navigator?
错误说明:无法找到抽屉导航实例,请确认当前组件是否嵌套在抽屉导航器(drawer navigator)内部。
关联代码
interface MainContainerProps { header?: ToolbarProps, props?: any, children?: ReactNode } const MainContainer: React.FC<MainContainerProps> = ({ header, props, children }) => { const [slideDrawer, setSlideDrawer] = useState(false); const drawerProgress = useDrawerProgress() const screenStyle = useAnimatedStyle(() => { const scaleY = interpolate(/*sv.value*/drawerProgress.value, [0, 1], [1, 0.8], { extrapolateRight: Extrapolate.CLAMP, }); const borderRadius = interpolate(/*sv.value*/drawerProgress.value, [0, 1], [1, 20], { extrapolateRight: Extrapolate.CLAMP, }); const animatedStyle = { borderRadius, transform: [{ scaleY }] }; console.log('HERE CALLED : ' + scaleY); return { transform: [ { scaleY, }, ], }; }); return (<Animated.View> ... </Animated.View>)
需求说明
需要在作为主容器的<Animated.View>中实现抽屉联动动画,当前在MainContainer组件内调用useDrawerProgress()钩子触发上述报错,所有被该MainContainer包裹的页面均受影响,需要找到正确的调整方案,为这些页面正确应用抽屉关联动画效果。
报错原因
useDrawerProgress钩子只能在Drawer.Navigator直接注册的屏幕组件上下文内调用。当前MainContainer是抽离的公共容器组件,本身不属于抽屉导航直接挂载的屏幕,无法获取抽屉导航的上下文实例,因此触发报错。
解决方案
提供两种可落地的调整方式,根据项目场景选择即可:
- 方式一:通过Props透传抽屉进度值
不在MainContainer内部直接调用useDrawerProgress,改为在每个被抽屉导航直接注册的页面中调用该钩子拿到进度值,再通过Props传入MainContainer,容器内部直接使用传入的进度值计算动画样式即可。
抽屉页面调用示例:
对应修改MainContainer的Props类型定义,新增import { useDrawerProgress } from '@react-navigation/drawer'; // 该组件为Drawer.Screen直接注册的页面组件 const HomePage = () => { // 此处可正常获取抽屉进度 const drawerProgress = useDrawerProgress(); return ( <MainContainer drawerProgress={drawerProgress}> {/* 页面业务内容 */} </MainContainer> ) }drawerProgress入参,删除组件内部直接调用useDrawerProgress()的代码即可。 - 方式二:全局配置抽屉屏幕动画包裹层(推荐)
如果需要给所有抽屉下的页面统一加联动动画,不想逐个页面修改传值,可以在配置抽屉导航时,统一给屏幕套一层动画容器,该容器处于抽屉导航上下文内,可以正常调用useDrawerProgress,一次配置全局生效。
配置示例:
配置完成后,MainContainer不需要再处理抽屉进度相关逻辑,所有页面自动应用抽屉联动动画,后续维护成本更低。import { createDrawerNavigator, useDrawerProgress } from '@react-navigation/drawer'; import Animated, { interpolate, Extrapolate, useAnimatedStyle } from 'react-native-reanimated'; const Drawer = createDrawerNavigator(); // 全局抽屉动画包裹组件 const DrawerAnimatedWrapper = ({ children }) => { const drawerProgress = useDrawerProgress(); const animatedStyle = useAnimatedStyle(() => { const scaleY = interpolate(drawerProgress.value, [0, 1], [1, 0.8], { extrapolateRight: Extrapolate.CLAMP, }); const borderRadius = interpolate(drawerProgress.value, [0, 1], [1, 20], { extrapolateRight: Extrapolate.CLAMP, }); return { borderRadius, transform: [{ scaleY }] } }); return <Animated.View style={[{ flex: 1, overflow: 'hidden' }, animatedStyle]}>{children}</Animated.View> } // 根导航配置 const RootDrawerNavigator = () => { return ( <Drawer.Navigator screenOptions={{ sceneContainerStyle: { backgroundColor: 'transparent' }, }} > <Drawer.Screen name="Home" component={HomePage} /> <Drawer.Screen name="Profile" component={ProfilePage} /> {/* 其余抽屉页面 */} </Drawer.Navigator> ) }
内容的提问来源于stack exchange,提问作者Moin Maniar
相关产品推荐
相关产品推荐

