Show DrawerLayoutAndroid via ToolbarAndroid => onIconClicked
Asked Answered
I

5

18

I'm new to React native (and React) and I'm playing around a little bit with it.

I managed to add a DrawerLayout that I can drag from the left of my screen. However I'd like to open it when I click on my menu icon in my ToolbarAndroid.

I tried to use "refs" but it doesn't seem to work

I hope I'm clear enough.

Thank you

Inoperable answered 20/9, 2015 at 14:55 Comment(0)
P
32

You should use "refs" as you've mentioned. To do so, for your drawer component have "ref" attribute set:

<DrawerLayoutAndroid
   ...
   ref={'DRAWER_REF'}
   ...
/>

Then in your component use this.refs to access it and call openDrawer or closeDrawer on that ref (e.g. you may want to have Touchable element that will trigger this call):

this.refs['DRAWER_REF'].openDrawer();
Pyrophoric answered 21/9, 2015 at 9:23 Comment(7)
It doesn't seem to work, but I guess it's because I don't have access to this.refs on this component. My components are nested this way DrawerLayoutAndroid > Navigator (which render a scene) including a ToolbarAndroid in which I'm trying to to onIconClicked={this.refs['DRAWER_REF'].openDrawer()}Inoperable
this.refs['DRAWER_REF'] will only be accessible from the component that renders the drawer. If you want to access it from some component down the view hierarchy you need to either: pass ref down the view hierarchy as a property OR pass a callback method down the view hierarchy that will be defined on drawer parent component levelPyrophoric
i am getting "undefined is not a object (evaluating 'this.refs['DRAWER_REF']')Acetophenetidin
can i use many component with ref like. <MyDrawerLayoutAndroid renderNavigationView={ () => <MyDrawerAndroid /> }><MyNavigator /></MyDrawerLayoutAndroid> and inside <MyNavigator /> has ` <Icon.ToolbarAndroid title={"Home"} onIconClicked={this.openDrawer} navIconName="menu"/>` . When click icon refs is not ` undefined`.Kalfas
I think many of us tried this and got "undefined is not an object" error. Can someone please show us a rather complete code on this?Gruver
Drawer is opening in my emulator smoothly but it doesn't seems to work properly in my mobile device, it takes a while for the drawer to get opened.Bats
I fixed it by adding: onPress={() => this.refs.drawer.openDrawer()} to my button. My drawer simply have: ref="drawer"Auckland
S
8

Using the ReactNative sample, you can do like that:

var DrawerTest = React.createClass({
  openDrawer:function() {
    this.refs['DRAWER'].openDrawer()
  },
  render: function() {
    var navigationView = (
        <View style={{flex: 1, backgroundColor: '#fff'}}>
          <Text style={{margin: 10, fontSize: 15, textAlign: 'left'}}>I'm in the Drawer!</Text>
        </View>
    );
    return (
          <DrawerLayoutAndroid
              drawerWidth={300}
              ref={'DRAWER'}
              drawerPosition={DrawerLayoutAndroid.positions.Left}
              renderNavigationView={() => navigationView}>
            <View style={{flex: 1, alignItems: 'center'}}>
              <Text style={{margin: 10, fontSize: 15, textAlign: 'right'}}>Hello</Text>
              <Text style={{margin: 10, fontSize: 15, textAlign: 'right'}}>World!</Text>
              <TouchableHighlight onPress={this.openDrawer}>
                <Text>{'Open Drawer'}</Text>
              </TouchableHighlight>
            </View>
          </DrawerLayoutAndroid>
    );

  }
});

Full File Gist

Stooge answered 10/10, 2015 at 16:14 Comment(0)
G
2

Just want to add another solution, especially when Navigator is used to render the scene.

If this is the case, then the above solutions won't work as it doesn't have access to ref specified in the DrawerLayoutAndroid, and it will in fact return

"undefined is not an object (evaluating 'this.refs['DRAWER_REF']')"

or something like that.

Solution:

Create our own Toolbar so that we can pass our rendering component to it.

MyToolbar.js

... import stuff ...

module.exports = React.createClass({
  render: function() {
    return (
      <ToolbarAndroid
        title={this.props.title}
        navIcon = {{uri: "ic_menu_white_24dp", isStatic: true}}
        style = {styles.toolbar}
        titleColor='#FFFFFF'
        onIconClicked={this._onIconClicked}/>
    );
  },

  _onIconClicked: function(){
    this.props.sidebarRef.refs['DRAWER'].openDrawer();
    // sidebarRef is the rendering component we're passing
  }
});

OpenDrawerFromToolbar.js

...
module.exports = React.createClass({
  render: function() {
    var navigationView = (
      <View style={{flex: 1, backgroundColor: '#fff'}}>
        <Text style={{margin: 10, fontSize: 15, textAlign: 'left'}}>In the Drawer!</Text>
      </View>
    );

    return (
      <View style={styles.container}>
        <DrawerLayoutAndroid drawerWidth = {300}
                         drawerPosition = {DrawerLayoutAndroid.positions.Left}
                         renderNavigationView = {() => navigationView}
                         ref={'DRAWER'}>
        <MyToolbar style={styles.toolbar}
                   title={'My Awesome App'}
                   navigator={this.props.navigator}
                   sidebarRef={this}/> // pass the component to MyToolbar
        <View style = {{flex: 1, alignItems: 'center'}}>
          <Text style = {{margin: 10, fontSize: 15, textAlign: 'right'}}>Hello</Text>
          <Text style = {{margin: 10, fontSize: 15, textAlign: 'right'}}>World!</Text>
        </View>
      </DrawerLayoutAndroid>
    </View>
  );
  },

  _setDrawer: function() {
    this.refs['DRAWER'].openDrawer();
  }
});

Then our Navigator component with its renderingScene function will work:

module.exports = React.createClass({
  render: function() {
    return (
      <Navigator
        style = {styles.container}
        initialRoute = {{ name: 'openDrawerFromToolbar', index: 0 }}
        renderScene = {this.navigatorRenderScene}
        configureScene={ () => { return Navigator.SceneConfigs.PushFromRight; }}/>
  );
},

navigatorRenderScene: function(route, navigator) {
  _navigator = navigator;
      return (
          <OpenDrawerFromToolbar
            route={route}
            navigator={navigator}
            data={route.data}/>
      );
  }
});
Gruver answered 31/5, 2016 at 9:59 Comment(0)
H
2

"undefined is not an object" - Most of us ended up here with a above solution.

Please ensure that you have correctly used the ES6 syntax as mentioned below.

Incorrect Syntax:

onPress={this.drawer()}

Correct Syntax:

onPress={() => this.drawer()}

Code:

<DrawerLayoutAndroid
   ...
   ref={'DRAWER_REF'}
   ...
/>

--------------------------------------------------

//Write this just before render() method

drawer = () => {
  this.refs['DRAWER_REF'].openDrawer();
}

--------------------------------------------------

<TouchableHighlight onPress={() => this.drawer()}>
   <Icon name="bars" size={30} color="#900"/>
</TouchableHighlight>
Heretofore answered 14/6, 2017 at 10:38 Comment(0)
J
0

Following all those snippets and still getting the undefined is not an object error.

Then found this thread on GitHub which finally solved my issue and explains the refs problem perfectly.

To follow the DrawerLayoutAndroid example on the React Native documentation (http://facebook.github.io/react-native/docs/drawerlayoutandroid.html), this is the code which works:

constructor() {
  super();
  this.openDrawer = this.openDrawer.bind(this);
} 

openDrawer() {
  this.drawer.openDrawer();
}

render() {
  var navigationView = (
    <View style={{flex: 1, backgroundColor: '#fff'}}>
      <Text style={{margin: 10, fontSize: 15, textAlign: 'left'}}>I'm in the Drawer!</Text>
    </View>
  );
  return (
    <DrawerLayoutAndroid
      drawerWidth={300}
      ref={(_drawer) => this.drawer = _drawer}
      drawerPosition={DrawerLayoutAndroid.positions.Left}
      renderNavigationView={() => navigationView}>
      <View style={{flex: 1, alignItems: 'center'}}>
        <Text style={{margin: 10, fontSize: 15, textAlign: 'right'}}>Hello</Text>
        <Text style={{margin: 10, fontSize: 15, textAlign: 'right'}}>World!</Text>
        <TouchableHighlight onPress={this.openDrawer}>
          <Text>{'Open Drawer'}</Text>
        </TouchableHighlight>
      </View>
    </DrawerLayoutAndroid>
  );
}
Justicz answered 13/12, 2016 at 23:14 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.