开发者问题收集

在 React Native 中选项卡底部导航流程中的任意屏幕上打开模式

2020-09-18
10013

我在使用 React Native tabBottom 导航时遇到了问题。我有一个 TabButton 自定义组件,单击时会呈现模态,但我似乎找不到在其他选项卡上呈现该特定模态的方法,而不仅仅是将其呈现为独立的组件。

我想要实现的是,当我单击黄色按钮时,它会呈现模态,但选项卡(如主页、帮助、调整和图形)会保留为模态的背景,而不仅仅是在另一个组件中呈现模态。

我的定制 TabButton 组件:

import React from 'react';
import {TouchableWithoutFeedback} from 'react-native-gesture-handler';
import Icon from 'react-native-vector-icons/MaterialIcons';
import Button from './styles';

const TabButton = ({onPress, focused}) => {
  return (
    <TouchableWithoutFeedback onPress={onPress}>
      <Button focused={focused}>
        <Icon name="add" size={35} color={'white'} />
      </Button>
    </TouchableWithoutFeedback>
  );
};

export default TabButton;

tabbutton

我的tab.routes.js:

import React from 'react';
import {createBottomTabNavigator} from '@react-navigation/bottom-tabs';
import TabButton from '../components/Tab/Button';
import Icon from 'react-native-vector-icons/MaterialIcons';
import Home from '../containers/Home';
import Graphic from '../containers/Graphic';
import Help from '../containers/Help';
import NewTransaction from '../containers/NewTransaction';
import SettingsStack from './settings.routes';

const icons = {
  Home: {
    name: 'home',
  },
  Graphic: {
    name: 'pie-chart',
  },
  NewTransaction: {
    name: 'notifications-none',
  },
  Help: {
    name: 'help-outline',
  },
  Adjustment: {
    name: 'settings',
  },
};

const Tab = createBottomTabNavigator();
const TabRoutes = () => (
  <Tab.Navigator
    initialRouteName="HomeScreen"
    screenOptions={({route, navigation}) => ({
      tabBarIcon: ({color, size, focused}) => {
        if (route.name === 'NewTransaction') {
          return <TabButton focused={focused} onPress={() => navigation.navigate('NewTransaction')} />;
        }
        const {name} = icons[route.name];
        return <Icon name={name} size={size} color={color} />;
      },
    })}
    tabBarOptions={{
      keyboardHidesTabBar: true,
      activeTintColor: '#f8b006',
      inactiveTintColor: '#1C3041',
      style: {
        height: 60,
      },
      iconStyle: {
        marginTop: 5,
      },
      labelStyle: {
        fontSize: 12,
        marginBottom: 10,
      },
    }}>
    <Tab.Screen
      options={{
        title: 'Home',
      }}
      name="Home"
      component={Home}
    />
    <Tab.Screen
      options={{
        title: 'Gráfico',
      }}
      name="Graphic"
      component={Graphic}
    />
    <Tab.Screen
      options={{
        title: '',
      }}
      component={NewTransaction}
      name="NewTransaction"/>
    <Tab.Screen
      options={{
        title: 'Ajuda',
      }}
      name="Help"
      component={Help}
    />
    <Tab.Screen
      options={{
        title: 'Ajustes',
      }}
      name="Adjustment"
      component={SettingsStack}
    />
  </Tab.Navigator>
);

export default TabRoutes;

我的模态组件:

import React from 'react';
import RBSheet from 'react-native-raw-bottom-sheet';
import PropTypes from 'prop-types';

const CustomModal = ({children, refRBSheet, borderRadius, height, animationType, onClose, onOpen}) => {
  return (
    <RBSheet
      animationType={animationType}
      height={height}
      onClose={onClose}
      onOpen={onOpen}
      ref={refRBSheet}
      closeOnDragDown={true}
      closeOnPressMask={true}
      customStyles={{
        container: {
          backgroundColor: 'white',
          borderTopLeftRadius: borderRadius,
          borderTopRightRadius: borderRadius,
        },
      }}>
      {children}
    </RBSheet>
  );
};

export default CustomModal;

以及呈现模态的 NewTransaction 组件:

import React, {useRef, useEffect} from 'react';
import {Text, View} from 'react-native';
import CustomModal from '../../components/Modal/';
const NewTransaction = ({isVisible, onClose}) => {
  const refRBSheet = useRef();

  useEffect(() => {
    if (isVisible) {
      refRBSheet.current.open();
    } else {
      refRBSheet.current.close();
    }
  }, [isVisible]);

  return (
    <CustomModal refRBSheet={refRBSheet} onClose={onClose}>
      <View>
        <Text>Hellow</Text>
      </View>
    </CustomModal>
  );
};

export default NewTransaction;

2个回答

您需要将其全部包装在 RootNavigator 中,如下所示:

const RootStack = createStackNavigator();

const RootNavigator = () => {
  return (
    <RootStack.Navigator screenOptions={{ headerShown: false, presentation: 'modal', animationEnabled: false }}>
      <RootStack.Screen name="BottomTabNavigatorScreen" component={TabRoutes}/>
      <RootStack.Screen name="CustomModal" component={CustomModal} options={{ animationEnabled: true }}/>
    </RootStack.Navigator>
  )
}

export default () => {
  return (
    <NavigationContainer>
      <RootNavigator />
    </NavigationContainer>
  );
};

然后,您可以在按钮上添加 tabPress 监听器以导航到模式,并在组件字段中添加所需的 placeholder

const placeholder = () => <View />


<Tab.Screen name="NewTransaction" component={placeholder}
    listeners={({ navigation }) => ({
       tabPress: (e) => {
          e.preventDefault();
          navigation.navigate('CustomModal');
       }
    })>
</Tab.Screen>
ben-natan
2022-01-08

首先,创建一个返回 null 的新页面/屏幕,这样当您启动模式时它不会显示任何背景。 像这样

const MyModalBackgroundScreen = () => {
  return null;
};

之后在选项卡导航器中创建选项卡

import React from 'react';
import {createBottomTabNavigator} from '@react-navigation/bottom-tabs';
import TabButton from '../components/Tab/Button';
import Icon from 'react-native-vector-icons/MaterialIcons';
import Home from '../containers/Home';
import Graphic from '../containers/Graphic';
import Help from '../containers/Help';
import NewTransaction from '../containers/NewTransaction';
import SettingsStack from './settings.routes';

const icons = {
  Home: {
    name: 'home',
  },
  Graphic: {
    name: 'pie-chart',
  },
  NewTransaction: {
    name: 'notifications-none',
  },
  Help: {
    name: 'help-outline',
  },
  Adjustment: {
    name: 'settings',
  },
};

const Tab = createBottomTabNavigator();
const TabRoutes = () => (
  <Tab.Navigator
    initialRouteName="HomeScreen"
    screenOptions={({route, navigation}) => ({
      tabBarIcon: ({color, size, focused}) => {
        //removd that if condition 
        const {name} = icons[route.name];
        return <Icon name={name} size={size} color={color} />;
      },
    })}
    tabBarOptions={{
      keyboardHidesTabBar: true,
      activeTintColor: '#f8b006',
      inactiveTintColor: '#1C3041',
      style: {
        height: 60,
      },
      iconStyle: {
        marginTop: 5,
      },
      labelStyle: {
        fontSize: 12,
        marginBottom: 10,
      },
    }}>
    <Tab.Screen
      options={{
        title: 'Home',
      }}
      name="Home"
      component={Home}
    />
    <Tab.Screen
      options={{
        title: 'Gráfico',
      }}
      name="Graphic"
      component={Graphic}
    />
    <Tab.Screen
      name="Graphic"
      component={MyModalBackgroundScreen} //first import this in this 
      options={{
        tabBarLabel: ({}) => {
          return null; //no label will be displayed
        },
        tabBarButton: () => {
          return <CustomModal refRBSheet={refRBSheet} onClose={onClose}>; // call your modal here directly.
        },
      }}
    />
    <Tab.Screen
      options={{
        title: '',
      }}
      component={NewTransaction}
      name="NewTransaction"/>
    <Tab.Screen
      options={{
        title: 'Ajuda',
      }}
      name="Help"
      component={Help}
    />
    <Tab.Screen
      options={{
        title: 'Ajustes',
      }}
      name="Adjustment"
      component={SettingsStack}
    />
  </Tab.Navigator>
);

export default TabRoutes;
rishikesh_07
2020-09-18