react-native中DrawerLayoutAndroid的基本使用

本文记录在react-native中DrawerLayoutAndroid的基本使用,主要是为了解决导航菜单显示问题。

本文做练习用的工程来自上一篇文章 react-native中navigator的基本使用

首先,官方文档地址如下:
http://facebook.github.io/react-native/docs/drawerlayoutandroid.html#content

DrawerLayoutAndroid组件通过其名字就能知道,只能在android系统上使用(好像是废话)。
该组件使用renderNavigationView方法来渲染Drawer(一般用来导航)。
该组件的直接子元素是主视图,用来显示内容。

在一开始,导航视图是被隐藏的,但是可以被从窗体的侧边拉出来(是的,就像抽屉一样),具体的从窗体哪个方向拉,可以通过drawerPosition属性指定,同时拉出来的宽度(抽屉的深度)可以通过drawerWidth属性指定。

示例code:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
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}
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>
</View>
</DrawerLayoutAndroid>
);
}

重要属性说明:

  • drawerWidth Drawer的宽度,类型为Number
  • drawerPosition Drawer拉出的方向,类型为枚举,可选的有DrawerConsts.DrawerPosition.LeftDrawerConsts.DrawerPosition.Right
  • renderNavigationView 一个函数用来渲染导航的视图,当drawer被拉出来时显示

OK,现在开始改造我们上篇文章中创建的工程:

首先加入对DrawerLayoutAndroid的引用

1
2
3
var {
AppRegistry, View, Navigator, Text, BackAndroid, StyleSheet, DrawerLayoutAndroid
} = React;

然后修改App组件的render方法如下,就是将原来的Navigator组件包裹在DrawerLayoutAndroid中:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
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 = {200}
drawerPosition={DrawerLayoutAndroid.positions.Left}
renderNavigationView={() => navigationView}>
<Navigator
initialRoute ={{name: 'home'}}
configureScene = {this.configureScene}
renderScene = {this.renderScene}>
</Navigator>
</DrawerLayoutAndroid>
);
}

这时候,刷新JS,在模拟器中如下,可以从窗口左边拉出Drawer:

截图

有了这个之后,我们就可以去掉原来home页面内的导航菜单了,并且每个页面也不需要返回按钮了
下面以home页面为例,其他页面的修改类似:

1
2
3
4
5
6
7
8
9
var HomeView = React.createClass({
render: function() {
return (
<View style = {styles.container}>
<Text>首页view</Text>
</View>
);
}
});

下面,我们将导航按钮放进Drawer中,修改App组件中render方法内的navigationView:

  • onNavPress方法中使用了外部的_navigator变量来控制页面切换
  • 使用了 ref 获取对 DrawerLayoutAndroid 的引用,在点击菜单之后关闭 DrawerLayoutAndroid
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
onNavPress: function(target) {
_navigator.push({
name: target
});
//关闭drawer
this.refs['DRAWER'].closeDrawer();
},
render: function() {
var navigationView = (
<View style={{flex: 1, backgroundColor: '#fff'}}>
<Text style={styles.button} onPress={() => this.onNavPress('home')}>[首页]</Text>
<Text style={styles.button} onPress={() => this.onNavPress('message')}>[消息]</Text>
<Text style={styles.button} onPress={() => this.onNavPress('discover')}>[发现]</Text>
<Text style={styles.button} onPress={() => this.onNavPress('user')}>[我的]</Text>
</View>
);
return (
<DrawerLayoutAndroid
ref={'DRAWER'}
drawerWidth = {200}
drawerPosition={DrawerLayoutAndroid.positions.Left}
renderNavigationView={() => navigationView}>
<Navigator
initialRoute ={{name: 'home'}}
configureScene = {this.configureScene}
renderScene = {this.renderScene}>
</Navigator>
</DrawerLayoutAndroid>
);
}

如果没有错误的话,showtime:

截图

最后,美化下我们的Drawer界面,这里我们直接使用了一个material-design组件库:
https://github.com/react-native-material-design/react-native-material-design

友情提醒:该组件库仍然处于开发阶段,API尚不稳定,文档也不全。

根据文档,安装之后,先在代码中添加引用

1
2
3
4
var MD = require('react-native-material-design');
var {
Card, Button, Avatar, Drawer, Divider, COLOR, TYPO
} = MD;

修改app组件的代码如下:

  • 使用了新的Drawer组件
  • 使用了state来区分当前激活状态
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
onNavPress: function(target) {
_navigator.push({
name: target
});
this.setState({
route: target
});
//关闭drawer
this.refs['DRAWER'].closeDrawer();
},
getInitialState: function() {
return {
route: 'home'
}
},
render: function() {
var navigationView = (
<Drawer theme='light'>
<Drawer.Header image={<Image source={require('./img/nav.jpg')} />}>
<View style={styles.header}>
<Avatar size={80} image={<Image source={{ uri: "http://facebook.github.io/react-native/img/opengraph.png?2" }}/>} />
<Text style={[styles.text, COLOR.paperGrey50, TYPO.paperFontSubhead]}>React Native</Text>
</View>
</Drawer.Header>
<Drawer.Section
items={[{
icon: 'home',
value: '首页',
active: !this.state.route || this.state.route === 'home',
onPress: () => this.onNavPress('home'),
onLongPress: () => this.onNavPress('home')
},
{
icon: 'message',
value: '消息',
active: !this.state.route || this.state.route === 'message',
onPress: () => this.onNavPress('message'),
onLongPress: () => this.onNavPress('message')
},
{
icon: 'search',
value: '发现',
active: !this.state.route || this.state.route === 'discover',
onPress: () => this.onNavPress('discover'),
onLongPress: () => this.onNavPress('discover')
},
{
icon: 'settings',
value: '我的',
active: !this.state.route || this.state.route === 'user',
onPress: () => this.onNavPress('user'),
onLongPress: () => this.onNavPress('user')
}]}
/>
</Drawer>
);
return (
<DrawerLayoutAndroid
ref={'DRAWER'}
drawerWidth = {200}
drawerPosition={DrawerLayoutAndroid.positions.Left}
renderNavigationView={() => navigationView}>
<Navigator
initialRoute ={{name: 'home'}}
configureScene = {this.configureScene}
renderScene = {this.renderScene}>
</Navigator>
</DrawerLayoutAndroid>
);
}

最终的效果如下:
截图