React-native-router-flux: How to open Drawer When use a custom icon in Scene

Created on 24 Aug 2016  路  11Comments  路  Source: aksonov/react-native-router-flux

Hi,I using Drawer my app, my problem is i want use a custom icon in Drawer Scene and its ok but i dont see any docs to tell me how to open or close the drawer!

this is my router :

    <Scene
                                key="TabbarWrapper"
                                component={NavigationDrawer}
                                initial={true}
                            >
                                <Scene key="Tabbar"
                                       tabs={true}
                                       initial={true}
                                       tabBarStyle={styles.tabBar}
                                       default="ProductExplorer">

                                    <Scene key="ProductExplorer"
                                           title="Lists"
                                           icon={TabIcon}
                                           iconName={"list"}
                                           initial={true}
                                           leftButtonIconStyle={{tintColor: "#FFF"}}
                                           renderBackButton={backButtonFunction}
                                           component={ProductExplorer}/>

                                    <Scene key="Profile"
                                           title="Profile"
                                           icon={TabIcon}
                                           iconName={"gear"}
                                           leftButtonIconStyle={{tintColor: "#FFF"}}
                                           renderBackButton={backButtonFunction}
                                           component={Profile}/>
                                </Scene>

                            </Scene>

and this is my button renderer function :

let backButtonFunction = function () {
    var TouchableElement = TouchableHighlight;
    if (Platform.OS === 'android')TouchableElement = TouchableNativeFeedback;
    return (
        <TouchableElement onPress={()=>{ 
           **** my problem is here **** what do you think i should do?!what function must be call here to toggle open and close menu?
         }} style={{position : "absolute",left: 12,bottom:12}}>
            <Icon style={{color: "#FFF"}} name={"bars"} size={23}/>
        </TouchableElement>
    );
};

question

Most helpful comment

@danieladias I don't see anything wrong with your Drawer.

Could be a react-native version issue. I'm using react-native 0.31.0 instead of 0.32.0. Maybe give that version a try?

These are all the changes I made:

In Drawer component:
<Drawer ref="navigation"></Drawer>
componentDidMount() { Actions.refresh({key: 'drawer', ref: this.refs.navigation}); }

In MenuButton component:
onPress={() => {Actions.get('drawer').ref.toggle()}}

In Scene:
<Scene leftButton={Button}>

All 11 comments

Answered in #1078

In Drawer component:
componentDidMount() { Actions.refresh({key: 'drawer', ref: this.refs.navigation}); }

In Button component:
onPress={() => {Actions.get('drawer').ref.toggle()}}

woww tnx! it's worked perfect :) @wildQueequeg

@wildQueequeg is that the only thing we would need to do?
I am a noob in reactive native but seems to be saying I can't access refs in the refresh method. Is that possible?

Here is a screenshot showing the error I am getting:
ce5343d6-750c-11e6-8ab7-6cd6d78a73f3

Versions

"dependencies": {
    "react": "15.3.1",
    "react-native": "0.32.0",
    "react-native-drawer": "^2.3.0",
    "react-native-router-flux": "^3.35.0",
    "react-native-vector-icons": "^2.1.0"
  }

Drawer

export default class NavigationDrawer extends Component {

  componentDidMount() {
    Actions.refresh({key: 'drawer', ref: this.refs.navigationDrawer});
}

  render() {
    const state = this.props.navigationState;
    const children = state.children;
    return (
      <Drawer
        ref="navigationDrawer"
        type="displace"
        onOpen={() => Actions.refresh({ key: state.key, open: true })}
        onClose={() => Actions.refresh({ key: state.key, open: false })}
        content={<NavigationDrawerView />}
        tapToClose
        openDrawerOffset={150}
        panOpenMask={10}
        negotiatePan
        tweenHandler={(ratio) => ({
          main: { opacity: Math.max(0.54, 1 - ratio) },
        })} >
        <DefaultRenderer navigationState={children[0]} onNavigate={this.props.onNavigate} />
      </Drawer>
    );
  }
}

NavigationDrawer.propTypes = propTypes;

Button

renderMenuButton() {
    return (
      <TouchableOpacity onPress={() => {Actions.get('drawer').ref.toggle()}}>
        <Icon name="ios-menu-outline" style={styles.navBarMenuIcon} />
      </TouchableOpacity>
    );
  }

@danieladias

this is my drawer component,i hope it can help you :

class NavigationDrawer extends React.Component {

    componentDidMount() {
        Actions.refresh({key: 'drawer', ref: this.refs.navigation});
    }

    render() {
        const state = this.props.navigationState;
        const children = state.children;

        return (
            <Drawer
                styles={drawerStyles}
                ref="navigation"
                type="displace"
                // onOpen={() => Actions.refresh({ key:  'drawer', open: true })}
                // onClose={() => Actions.refresh({ key: 'drawer', open: false })}
                content={<TabView />}
                tapToClose
                openDrawerOffset={0.2}
                panCloseMask={0.2}
                negotiatePan
                tweenHandler={(ratio) => ({
                main: { opacity: Math.max(0.54, 1 - ratio) }
        })}
            >
                <DefaultRenderer navigationState={children[0]} onNavigate={this.props.onNavigate}/>
            </Drawer>
        );
    }
}


and this is my Scene
 <Scene
                                key="drawer"
                                component={NavigationDrawer}
                                initial={true}
                            >
 /*another  Scene*/
</Scene>

@alirezavalizade thanks for your help. I tried but still getting the same issue. As soon as I add the line Actions.refresh({key: 'drawer', ref: this.refs.navigation}); to componentDidMount I get the error.

@danieladias I don't see anything wrong with your Drawer.

Could be a react-native version issue. I'm using react-native 0.31.0 instead of 0.32.0. Maybe give that version a try?

These are all the changes I made:

In Drawer component:
<Drawer ref="navigation"></Drawer>
componentDidMount() { Actions.refresh({key: 'drawer', ref: this.refs.navigation}); }

In MenuButton component:
onPress={() => {Actions.get('drawer').ref.toggle()}}

In Scene:
<Scene leftButton={Button}>

@wildQueequeg thanks for your help. Tried with 0.31.0 but no luck. Still the same stateless functions error as soon as I add that line in componentDidMount in my Drawer.
If I just print the refs like this console.log(this.refs.navigationDrawer) I can access it fine. My problem is with refresh I think.

I can also do this:
this.refs.navigationDrawer.toggle()
in componentDidMount and the drawer opens at launch.

Use renderBackButton prop of Scene component. Pass a private function, and inside that function just call Actions.refresh({key: 'drawer', open: value => !value});

Example below:
<Scene sceneStyle={styles.sceneStyle} renderBackButton={this._showCustomButton} hideNavBar={false} key="test" component={Test} title="Test"/>

_showCustomButton() { return ( <TouchableOpacity onPress={()=>Actions.refresh({key: 'drawer', open: value => !value })}> <Image style={styles.tabImage} source={require('./images/settings.png')} /> </TouchableOpacity> ) }

PS: please teach me formatting....

@wildQueequeg Thanks it works 馃憤

Until now it renders but doesn't open the drawer.

I believe is something associated to the _references_ but I'm not sure.

router.js

import React, { Component } from 'react';
import { Actions, Router, Scene } from 'react-native-router-flux';

import Dashboard from './components/dashboard';
import Home from './components/home';
import ViewCamera from './components/view-camera';
import Register from './components/register';
import SideDrawer from './components/sideDrawer';
import TabIcon from './components/tabIcon';

function openDrawer() {
  return (<TabIcon
    press={() => {
      Actions.refresh({ key: 'drawer', open: true })
    }}
  />);
}

class RouterComponent extends Component {
  render() {
    return (
      <Router>
        <Scene key="root">
          <Scene
            panHandlers={null}
            key="home"
            hideNavBar component={Home} title="Login" initial
          />
          <Scene
            panHandlers={null}
            key="viewCamera"
            hideNavBar component={ViewCamera} title="Captura del Documento"
          />
          <Scene
            panHandlers={null}
            key="register"
            hideNavBar component={Register} title="Registro"
          />
        </Scene>
        <Scene
          key="drawer" component={SideDrawer}
        >
          <Scene
            key="tabs"
            tabs
          >
            <Scene
              initial
              panHandlers={null}
              component={Dashboard}
              hideTabBar
              key="dashboard"
              title="Propuestas"
              renderLeftButton={openDrawer}
            />
            {/*<Scene panHandlers={null} key="pollCreation" component={Poll} />*/}
          </Scene>
        </Scene>
      </Router>
    );
  }
}
export default RouterComponent;

components/tabIcon.js

import React, {
  Component,
  PropTypes,
  StyleSheet
} from 'react';

import {
  Text,
} from 'react-native';

import MaterialIcons from 'react-native-vector-icons/MaterialIcons';
import { Button } from 'native-base';
import { Actions } from 'react-native-router-flux';

const propTypes = {
  selected: PropTypes.bool,
  title: PropTypes.string,
};

class TabIcon extends Component {
  render() {
    return (
      <Button
        transparent
        onPress={this.openDrawer.bind(this)} style={styles.navButton}
        style={{ backgroundColor: 'rgba(0,0,0,0)' }}
      >
        <Text>
          <MaterialIcons name="menu" size={30} />
        </Text>
      </Button>
    );
  }
  openDrawer = () => {
    Actions.get('drawer').ref.toggle();
  };
}
TabIcon.propTypes = propTypes;

const styles = {
  navButton: {
    alignItems: 'flex-end',
    flex: 1,
  }
};

export default TabIcon;

sideDrawer.js

import React, { Component, PropTypes } from 'react';

import {
  BackAndroid,
  StyleSheet,
  Text,
  View,
} from 'react-native';
import { Drawer } from 'native-base';

import { DefaultRenderer, Actions } from 'react-native-router-flux';
import SideBar from './sidebar';

const propTypes = {
  navigationState: PropTypes.object,
};

class SideDrawer extends Component {
  static propTypes = {
    closeDrawer: React.PropTypes.func,
    drawerState: React.PropTypes.string,
  }

  constructor(props) {
    super(props);
    this.state = {
      animatingLoadingSpinner: false,
      url: 'polls',
    };
  }

  componentDidMount() {
    BackAndroid.addEventListener('hardwareBackPress', () => {
      Actions.pollCreation();
    });
  }

  finishSpinnerAnimation() {
    this.setState({
      animatingLoadingSpinner: false
    });
  }

  startSpinnerAnimation() {
    this.setState({
      animatingLoadingSpinner: true
    });
  }


  noServerConnection() {
    return (
      <View style={styles.errorBody} >
        <Text > No es posible la conexi贸n con Nuestros servidores </Text>
      </View>
    );
  }

  render() {
    const state = this.props.navigationState;
    const children = state.children;
    console.log(`(Poll) url: ${this.props.url}`);
    return (
      <View style={styles.container} >
        <Drawer
          ref={ref => (this.drawer = ref)}
          type="overlay"
          tweenDuration={150}
          content={
            <SideBar
              closeDrawer={() => {
                this.drawer.close();
         }} />}
          tapToClose
          acceptPan={false}
          openDrawerOffset={0.2}
          panCloseMask={0.2}
          styles={{
            drawer: {
              shadowColor: '#000000',
              shadowOpacity: 0.8,
              shadowRadius: 3,
            },
          }}
          tweenHandler={(ratio) => {  // eslint-disable-line
            return {
              drawer: { shadowRadius: ratio < 0.2 ? ratio * 5 * 5 : 5 },
              main: {
                opacity: (2 - ratio) / 2,
              },
            };
          }}
          negotiatePan
          onOpen={() => Actions.refresh({ key: state.key, open: true })}
          onClose={() => Actions.refresh({ key: state.key, open: false })}
        >
          {/*<View style={{ marginTop: 45 }} />*/}

          <DefaultRenderer navigationState={children[0]} onNavigate={this.props.onNavigate} />
        </Drawer>
      </View>
    );
  }

}

let WEBVIEW_REF = 'webview';
const BGWASH = '#F6F6F6';

const styles = StyleSheet.create({
  container: {
    flex: 1,
    backgroundColor: BGWASH,
  },
  addressBarRow: {
    flexDirection: 'row',
    height: 10,
  },
  errorBody: {
    alignItems: 'center',
    justifyContent: 'center',
  },
  navButton: {
    alignItems: 'flex-end',
    flex: 1,
  },
  navText: {
    fontSize: 18,
  },
  navTextContainer: {
    alignItems: 'center',
    flex: 8,
    justifyContent: 'center',
  },
});

SideDrawer.propTypes = propTypes;
export default SideDrawer;

My entire screen along with the header/title moves down by 2 cm or so, after i added the side menu on the title. Where could be the problem?

Was this page helpful?
0 / 5 - 0 ratings