Hirurg103
Hirurg103

Reputation: 4953

How to add extra item at the bottom of the drawer navigation manually (like logout button)?

I want to add logout button to the bottom of the drawer navigation in my RN app.

As you can see the Logout button is located at the bottom of the drawer menu. How can I move it to the bottom of the drawer panel?

I am trying to use contentComponent the following way:

const DrawerWithLogoutButton = (props) => (
  <ScrollView>
    <SafeAreaView style={styles.container} forceInset={{ top: 'always', horizontal: 'never' }}>
      <DrawerItems {...props} />
    </SafeAreaView>
    <Button
      style={styles.logoutButton}
      title="Logout"
      onPress={() => props.navigation.navigate('Login') }/>
  </ScrollView>
);

export default Home = createDrawerNavigator({
  // screens
}, {
  // other settings
  contentComponent: DrawerWithLogoutButton,
});

const styles = StyleSheet.create({
  container: {
    flex: 1,
    flexDirection: 'column',
  },
  logoutButton: {
    backgroundColor: 'red',
    position: 'absolute',
    bottom: 0
  }
});

In the result I have the Logout button at the bottom of the menu. But I want it to be located at the bottom of the drawer panel instead

Also I would want the Logout button to look like other menu items and had an icon

Is there a way to create drawer navigator with a menu item which has no screen but is just an action like Logout as in my case?

Upvotes: 16

Views: 15482

Answers (6)

adamwjohnson5
adamwjohnson5

Reputation: 763

Version: 6.x solution:

Add flex: 1 to drawerContentContainerStyle and then marginTop: "auto" to the last item. No need for drawerContent.

    <Drawer
  screenOptions={{
    drawerContentContainerStyle: {
      flex: 1,
    },
  }}
>
  <Drawer.Screen
    name="index"
    options={{
      drawerLabel: "Home",
    }}
  />

  <Drawer.Screen
    name="logout"
    options={{
      drawerLabel: "Logout",
      drawerItemStyle: {
        marginTop: "auto",
      },
    }}
  />
</Drawer>;

Upvotes: 0

dsax7
dsax7

Reputation: 1343

The accepted answer did not work out for me directly. I had to do some modifications, but in general the secret is indeed using justifyContent: 'space-between'.

import {View} from 'react-native';
import {
  createDrawerNavigator,
  DrawerContentScrollView,
  DrawerItem,
  DrawerItemList,
  DrawerContentComponentProps,
} from '@react-navigation/drawer';

const Drawer = createDrawerNavigator();

function CustomDrawerContent(props: DrawerContentComponentProps) {
  return (
    <DrawerContentScrollView
      {...props}
      contentContainerStyle={{flex: 1, justifyContent: 'space-between'}}>
      <View style={{justifyContent: 'flex-start'}}>
        <DrawerItemList {...props} />
      </View>
      <DrawerItem
        label="Logout"
        onPress={() => console.log('Logged out')}
      />
    </DrawerContentScrollView>
  );
}

.
.
.

        <Drawer.Navigator
          initialRouteName="HomeScreen"
          drawerContent={(props) => <CustomDrawerContent {...props} />}
          drawerContentOptions={{
            activeTintColor: color.primaryDark,
            itemStyle: {
              backgroundColor: 'transperant',
              borderColor: color.primaryDark,
              borderBottomWidth: 1,
              opacity: 0.8,
            },
          }}
          drawerStyle={styles.drawer}>
          <Drawer.Screen name="Home" component={HomeScreen} />
          <Drawer.Screen name="Notifications" component={NotificationsScreen} />
        </Drawer.Navigator>

Upvotes: 2

MoreFoam
MoreFoam

Reputation: 689

Similar to William Griffins answer, except their answer does not end up with the logout button at the bottom of the drawer. To have logout be at the bottom, I put my DrawerContentScrollView inside a SafeAreaView, then beneath the DrawerContentScrollView I put a regular View containing the DrawerItem, which is the logout button.

function CustomDrawerContent(props) {
    return (
        <SafeAreaView style={{flex: 1}} forceInset={{top: "always", horizontal: "never"}}>
            <DrawerContentScrollView {...props}>
                <DrawerItemList {...props} />
            </DrawerContentScrollView>
            <View>
                <DrawerItem label={"Logout"}
                            style={styles.logoutDrawerItem}
                            onPress={() => console.log('Logout pressed!')}
                />
            </View>
        </SafeAreaView>
    );
}

function App(props) {
  return (
    <Provider store={store}>
      <View style={styles.container}>
        <StatusBar translucent={true} />
        <NavigationContainer>
          <Drawer.Navigator drawerContent={props => <CustomDrawerContent {...props} />}>
            <Drawer.Screen name='Home' component={Home} />
            <Drawer.Screen name='Edit Profile' component={EditProfile} />
            <Drawer.Screen name='Landing' component={Landing} />
          </Drawer.Navigator>
        </NavigationContainer>
      </View>
    </Provider>
  )
}

const styles = StyleSheet.create({
    logoutDrawerItem: {
        borderRadius: 5,
    },
});

Any items you place beneath the DrawerContentScrollView will be placed at the bottom of the drawer.

Note that I set borderRadius to 5 on the logout DrawerItem, so that it closely matches the border radius of regular drawer items.

Upvotes: 4

William Griffin
William Griffin

Reputation: 196

React Navigation docs recommend wrapping the drawer navigation with a custom content drawer function. This is what we do did to give our drawer a logout button, but also keep all of the Drawer.Screens in place.

In the code below we create a CustomDrawerContent that contains a DrawerItem as our logout button. This function wraps the Drawer.Navigator through its property drawerContent. Our final drawer then looks like:

  • Home (Drawer.Screen)
  • Edit Profile (Drawer.Screen)
  • Landing (Drawer.Screen)
  • Logout (DrawerItem)
const Drawer = createDrawerNavigator();

function CustomDrawerContent(props) {
  return (
    <DrawerContentScrollView {...props}>
      <DrawerItemList {...props} />
      <DrawerItem label={() => <Text style={{ color: 'white' }}>Logout</Text>}
        style={{backgroundColor: 'red'}} 
        onPress={() => alert('Logged out')}
      />
    </DrawerContentScrollView>
  );
}

function App(props) {
  return (
    <Provider store={store}>
      <View style={styles.container}>
        <StatusBar translucent={true} />
        <NavigationContainer>
          <Drawer.Navigator drawerContent={props => <CustomDrawerContent {...props} />}>
            <Drawer.Screen name='Home' component={Home} />
            <Drawer.Screen name='Edit Profile' component={EditProfile} />
            <Drawer.Screen name='Landing' component={Landing} />
          </Drawer.Navigator>
        </NavigationContainer>
      </View>
    </Provider>
  )
}

Upvotes: 8

Ali SabziNezhad
Ali SabziNezhad

Reputation: 3118

You can set position:'absolute' and buttom:0 like this code:

<TouchableOpacity 
    onPress={() => {this.logout()}}
    style={{ bottom: 0, position: 'absolute', width: '100%' }}>
      <View style={{ flex: 1, justifyContent: 'center', alignItems: 'center', flexDirection:'row', alignItems: 'center' }}>
        <Icon name="md-log-out" style={{marginRight: 10, color: '#444'}} size={20}/>
        <Text style={{color: '#444'}}>Logout</Text>
      </View>
</TouchableOpacity>

You can change the style to make it like other buttons. I hope this will help you...

Upvotes: 2

Hirurg103
Hirurg103

Reputation: 4953

I was able to align Logout at the bottom of the drawer menu with adding justifyContent: 'space-between' to the ScrollView container. You can see the result in the picture

the Logout button is located at the bottom of the drawer menu

The result source code looks the following way:

const DrawerWithLogoutButton = (props) => (
  <ScrollView contentContainerStyle={{flex: 1,  flexDirection: 'column', justifyContent: 'space-between' }}>
    <SafeAreaView forceInset={{ top: 'always', horizontal: 'never' }}>
      <DrawerItems {...props} />
    </SafeAreaView>
    <TouchableOpacity>
      <View style={styles.item}>
        <View style={styles.iconContainer}>
          <Image source={require('./img/logout.png')} style={styles.icon}></Image>
        </View>
        <Text style={styles.label}>Logout</Text>
      </View>
    </TouchableOpacity>
  </ScrollView>
);

const styles = StyleSheet.create({
  item: {
    flexDirection: 'row',
    alignItems: 'center',
  },
  label: {
    margin: 16,
    fontWeight: 'bold',
    color: 'rgba(0, 0, 0, .87)',
  },
  iconContainer: {
    marginHorizontal: 16,
    width: 24,
    alignItems: 'center',
  },
  icon: {
    width: 24,
    height: 24,
  }
});

Upvotes: 18

Related Questions