当前,我有多个视图可以通过下拉手势关闭。向下拖动时,视图会变小,直到到达我在导航器上调用goBack()
的位置,将其完全关闭。
现在,由于我不想一遍又一遍地在许多文件中实现此逻辑,因此我尝试创建一个HoC来编写一次关闭动画逻辑,并使其他组件专注于其特定任务。我还想将dismissAnimationProgress
值传递给包装的组件,以便它们可以在用户向下拖动时处理一些额外的逻辑(例如使某些东西褪色)。
这是我的DismissableView.tsx
:
export interface DismissableViewProps {
dismissProgress: Reanimated.Value<number>;
}
export default function DismissableView<TView extends React.Component<TViewProps>, TViewProps extends DismissableViewProps>(
WrappedComponent: TView,
props: TViewProps,
): React.ReactElement {
const { navigation, ...passThroughProps } = props;
const navigateBack = useMemo(() => navigation.pop(), [navigation]);
const gestureHandler = usePanGestureHandler();
const dismissAnimationProgress = useValue(0); // Animation from 0 -> 1, where 1 is dismiss.
const cardBorderRadius = useMemo(() => {
return Reanimated.interpolate(dismissAnimationProgress, {
inputRange: [0, 1],
outputRange: [0, 30],
extrapolate: Extrapolate.CLAMP,
});
}, [dismissAnimationProgress]);
const viewScale = useMemo(() => {
return Reanimated.interpolate(dismissAnimationProgress, {
inputRange: [0, 1],
outputRange: [1, 0.8],
extrapolate: Extrapolate.CLAMP,
});
}, [dismissAnimationProgress]);
useCode(
() => [
cond(eq(gestureHandler.state, State.ACTIVE), [
set(
dismissAnimationProgress,
Reanimated.interpolate(gestureHandler.translation.y, {
inputRange: [0, SCREEN_HEIGHT * 0.2],
outputRange: [0, 1],
}),
),
]),
cond(eq(gestureHandler.state, State.END), [
set(dismissAnimationProgress, timing({ from: dismissAnimationProgress, to: 0, duration: 200, easing: Easing.out(Easing.ease) })),
]),
cond(greaterOrEq(dismissAnimationProgress, 1), [call([], navigateBack)]),
],
[],
);
const viewStyle = useMemo(() => {
return { transform: [{ scale: viewScale, borderRadius: cardBorderRadius }] };
}, [viewScale, cardBorderRadius]);
return (
<PanGestureHandler {...gestureHandler.gestureHandler}>
<Reanimated.View style={viewStyle}>
<WrappedComponent {...passThroughProps} navigation={navigation} dismissAnimationProgress={dismissAnimationProgress} />
</Reanimated.View>
</PanGestureHandler>
);
}
这不会按预期方式工作,因为不会传递组件的属性(因为不会在参数中提供它们的属性,并且也不会设置dismissAnimationProgress道具。
在我的导航器(@react-navigation/stack
)中,我像这样使用它:
import ProfileScreen from '../screens/social/ProfileScreen';
import DismissableView from '../components/DismissableView';
// No parameter for props here
const DismissableProfileScreen = DismissableView(ProfileScreen);
// Props include { route, navigation } for "ProfileScreen"
const Stack = createStackNavigator<MainStackNavigatorProps>();
export default function MainStackNavigator(): JSX.Element {
return (
<Stack.Navigator>
<Stack.Screen name="ProfileScreen" component={DismissableProfileScreen} />
</Stack.Navigator> );
}
因为您要声明HOC,所以实际上您需要将DismissableView
声明为“自己”及其将接收的组件的父组件-
const dismissableView = <TView extends object>(Component: React.ComponentType<P>) =>
const DismissableView: React.FC<TView & DismissableViewProps> = props => {
另一种方法是将DismissableView
视为
const withDismissableScreen = Component => <DismissableView> <Component/> </DismissableView>;
<Stack.Screen name="ProfileScreen" component={withDismissableScreen(ProfileScreen)} />
现在DismissableScreen
的声明仍将在一行中,但是您可以通过props.children
获得该组件