react-navigation / react-navigation.github.io

Home of the documentation and other miscellanea
https://reactnavigation.org/
MIT License
315 stars 1.9k forks source link

Open a modal from a tab bar #27

Open brentvatne opened 6 years ago

brentvatne commented 6 years ago

Moved over from https://github.com/react-navigation/react-navigation/issues/3003 @spencercarli came up with this solution: https://snack.expo.io/SyJKMkFUM We might need to change the API a bit to make it cleaner but we can document this approach for now!


It would be great to get documentation done for this "open modal from tab bar" layout. I've seen it asked a bunch of times in different places as it's a very common/popular requirement.

While not as helpful as writing documentation myself, here are some of the places this was asked, to show it would be useful to have it in the official docs:

@TomAtterton seems to have a solution in this issue

https://github.com/react-community/react-navigation/issues/1576

He also left the same comment here:

https://stackoverflow.com/questions/42398911/how-do-i-make-a-tabnavigator-button-push-a-modal-screen-with-react-navigation

Anyway, best practice or not, Tom seems to have the only solution? Maybe he could give a slightly longer form answer and that can be used for docs? @spencercarli

I will try to write something up potentially.

iosdev-republicofapps commented 6 years ago

Just for the record, the answer by Thomas Kekeisen worked best: https://stackoverflow.com/a/42907868/961886

sean-macfarlane commented 6 years ago

FYI with v2 and "react-navigation-tabs" version "0.3.0" I have come up with a simpler solution for doing this: https://github.com/react-navigation/react-navigation/issues/1576#issuecomment-392918395

bjjeong commented 5 years ago

My goal was to create a pop up modal similar to what the OP was looking for in #1059 but I found that almost all of the solutions referenced involved a full page modal that covered up the tab bar and was not really an overlay, which was not what I was looking for.

The way I got it to work was to create a custom tab bar component and render the modal through there.

export default createBottomTabNavigator({
  ...
  AddStack,
  ...
}, {
  tabBarComponent: TabBarComponent,
})

where AddStack is just an empty StackNavigator with screen: () => null.

And in my TabBarComponent.js,

export default class TabBarComponent extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      modalVisible: false
    }
  }

  render() {
    const { navigation, renderIcon, activeTintColor, inactiveTintColor } = this.props;
    const { routes } = navigation.state;

    return (
      <SafeAreaView style={styles.tabbar}>
        {routes && routes.map((route, index) => {
          const focused = index === navigation.state.index;
          const tintColor = focused ? activeTintColor : inactiveTintColor;
          return (
            <TouchableWithoutFeedback
              key={route.key}
              style={styles.tab}
              onPress={() => {
                if (route.key == "AddStack") {
                  this.setState({ modalVisible: true })
                } else {
                  navigation.navigate(route)
                }
              }}
            >
              <View style={styles.tab}>
                { renderIcon({route, index, focused, tintColor })}
                <Modal
                  isVisible={this.state.modalVisible}
                  animationIn="fadeInUp"
                  animationOut="fadeOutDown"
                  backdropOpacity={.5}
                  onBackdropPress={() => this.setState({ modalVisible: false })}
                  onBackButtonPress={() => this.setState({ modalVisible: false })}
                  style={styles.bottomModal}
                  useNativeDriver={true}
                >
                  <View style={styles.modal}>
                     // Modal Content
                  </View>
                </Modal>
              </View>
            </TouchableWithoutFeedback>
          );
        })}
      </SafeAreaView>
    );
  }
};
zhuxx2021 commented 5 years ago

class TabBarButtonComponent extends Component { goToListPage = () => { this.props.children[0].props.navigation.navigate("ListPage"); }; }

this.props.children[0].props.navigation.navigate("ListPage");

就这一个,查看props得来的

jemjov41 commented 5 years ago

mr.@bjjeong i try to make adding post like you did, but its always show me the modal view this the code

export default class TabBarComponent extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      modalVisible: false
    }
  }

  render() {
    const { navigation, renderIcon, activeTintColor, inactiveTintColor } = this.props;
    const { routes } = navigation.state;

    return (
      <SafeAreaView style={{flexDirection: 'row',
                height: 50,
                width: '100%',}}>
        {routes && routes.map((route, index) => {
          const focused = index === navigation.state.index;
          const tintColor = focused ? activeTintColor : inactiveTintColor;
          return (
            <TouchableWithoutFeedback
              key={route.key}
              style={{flex:1}}
              onPress={() => {
                if (route.key == "Adding") {
                  console.log(route.key);
                  this.setState({ modalVisible: false })
                } else {
                  navigation.navigate(route)
                }
              }}
            >
              <View style={{flex:1}}>
                { renderIcon({route, index, focused, tintColor })}
                <Modal
                  isVisible={false}
                  animationIn="fadeInUp"
                  animationOut="fadeOutDown"
                  backdropOpacity={.5}
                  onBackdropPress={() => this.setState({ modalVisible: false })}
                  onBackButtonPress={() => this.setState({ modalVisible: false })}
                  style={{flex:1}}
                  useNativeDriver={true}
                >
                  <View style={{flex:1, backgroundColor:'rgba(100,100,100, 0.5)'}}>
                     <Text style={{color:"red"}}> modal content</Text>
                  </View>
                </Modal>
              </View>
            </TouchableWithoutFeedback>
          );
        })}
      </SafeAreaView>
    );
  }
};

can you tell me whats wrong with that code?

brentvatne commented 5 years ago

https://github.com/brentvatne/react-navigation-workshop-examples/blob/d90687777a95599a32e395f9e16aae642f5a8ee5/example/sections/Nesting.js#L61-L82

you can do something like this to change the behavior of pressing a tab

bjjeong commented 5 years ago

@setanallas you have 2 things wrong.

  1. The isVisible prop of your Modal is hardcoded to equal false. Instead, do this:
<Modal
  isVisible={this.state.isVisible}
</Modal>
  1. In your TouchableWithoutFeedback, you need to have the onPress change the state of the isVisible variable.
<TouchableWithoutFeedback
  onPress={() => {
    if (route.key === 'Adding') {
      this.setState({ isVisible: true })}
    } else {
      navigation.navigate(route)
    }
  }
>
</TouchableWithoutFeedback>

That should be it.

jemjov41 commented 5 years ago

@bjjeong yea i set it hardcode because its always showing even im not click the bottom tab button, even i set it to false its still show

but no problem i already fix it thx mr.@bjjeong for inspire me

immortalx commented 4 years ago

What's the current way to do this in V5?

sperezm97 commented 4 years ago

Any update to do this in v5?

bernardmma commented 4 years ago

@immortalx @sperezm97

Wish there was an easier way, but this is how I achieved it in v5.

I passed in a custom tab bar component into the tab navigator. This will give you the ability alter what happens with the onPress.

omorhefere commented 4 years ago

I found this helpful for open the modal from the navbar in react navigation 5: https://github.com/react-navigation/react-navigation/issues/7249

EdmundMai commented 4 years ago

@sperezm97 for opening a modal from tab click use listeners

      <Tab.Screen
        name="AddEntry"
        component={EntryFormScreen}
        listeners={({ navigation, route }) => ({
          tabPress: e => {
            e.preventDefault();
            navigation.navigate("EntryFormFlow");
          },
        })}
        options={({ route }) => ({
          tabBarIcon: ({ focused, color }) => (
            <AntDesign name={"pluscircleo"} size={25} color={color} />
          ),
        })}
      />
kturcios commented 4 years ago

@sperezm97 for opening a modal from tab click use listeners

      <Tab.Screen
        name="AddEntry"
        component={EntryFormScreen}
        listeners={({ navigation, route }) => ({
          tabPress: e => {
            e.preventDefault();
            navigation.navigate("EntryFormFlow");
          },
        })}
        options={({ route }) => ({
          tabBarIcon: ({ focused, color }) => (
            <AntDesign name={"pluscircleo"} size={25} color={color} />
          ),
        })}
      />

Dude thank you. I knew there had to be a simpler solution for v5. Just tried it out and works exactly as I needed.

hengkx commented 4 years ago

Any progress?