如何迈出第三步(衔接)

第二步,我们依旧遗留了一个问题,从引导页进入到程序主界面,打算使用React-Router来解决这个问题。目前我对React-Router也是处于知道但没用过的状态,我们先尝试着寻找资料了解一下这个功能组件(记住React-Router这个名字还是因为我之前使用了很久的vue-router)。来到Reacr-Router Github的主页后,阅读了一下大致的介绍,感觉还是只适合Web的React相关的路由操作(小白见解),我们使用另一个:

1
$ npm i react-native-router-flux --save

并且在使用之前建议大家阅读一下这篇文章,接着我们按照Github的文档来看下具体该如何操作:

1
2
// 首先,引入路由
import { Router, Scene } from 'react-native-router-flux';

然后,我们先随便写一个程序的主界面RootPage.js

1
2
3
<View>
<Text>Hello main page.</Text>
</View>

然后我们要使用路由做一下界面的跳转之前,我们想一下,引导页只出现一次的,这个问题先留在这里,先去看怎么使用Router,首先改造我们的index.ios.js

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
import React, { Component } from 'react';
import { AppRegistry, StyleSheet, View} from 'react-native';
// 引入Router, Scene
import { Router, Scene } from 'react-native-router-flux';
import GuidePage from './GuidePage';
import RootPage from './RootPage';
class Project extends Component {
render() {
return (
// 创建路由
<Router>
<Scene key="root">
<Scene key="guide" component={GuidePage} hideNavBar title="GuidePage" initial={true} />
<Scene key="root" component={RootPage} title="RootPage" initial={false}/>
</Scene>
</Router>
);
};
};
AppRegistry.registerComponent('Project', () => Project);

先不要问为什么,接着按照git的文档进行操作,在GuidePage中引入:

1
import { Actions, ActionConst } from 'react-native-router-flux';

并修改进入按钮点击的事件:

1
2
3
4
5
6
7
<TouchableOpacity onPress={() => {
// 注意这里
Actions.RootPage({type: ActionConst.REPLACE});
}}
activeOpacity={50 / 100}>
...
</TouchableOpacity>

然后会发现点击进入按钮之后,界面被主界面替换掉了。现在我们来解释代码:

总共引入了:Router、Scene、Actions、ActionConst4个组件,他们分别的作用是,创建一个路由容器,创建容器内的场景,发起跳转动作,跳转的方式。

所以,这些代码好理解了,我们现在程序入口的时候,创建一个路由:

1
2
3
4
5
6
7
8
9
10
11
12
<Router>
<Scene key="root">
<Scene
key="GuidePage"
component={GuidePage}
hideNavBar
title="GuidePage"
initial={true}
/>
<Scene key="RootPage" component={RootPage} title="RootPage" initial={false}/>
</Scene>
</Router>

包含了2个界面(场景),供我们切换,里边是一些配置,都是顾名思义的,所以不做多的解释。我们看到有个initial属性,是用来控制谁是首要的,引导页出现一次,所以我们要根据属性来控制程序进入到哪一个界面,我们寻求App的帮助,打开Xcode工程,在AppDelegate中,我们存储一下用户的使用状态。最简单的办法改一下:

1
2
3
4
5
6
7
BOOL launched = [[NSUserDefaults standardUserDefaults] boolForKey:ApplicationDidLaunchedYet];
RCTRootView *rootView = [[RCTRootView alloc] initWithBundleURL:jsCodeLocation moduleName:@"Project" initialProperties:@{ @"launched": @(launched)
}
launchOptions:launchOptions];
[[NSUserDefaults standardUserDefaults] setBool:YES forKey:ApplicationDidLaunchedYet];
[[NSUserDefaults standardUserDefaults] synchronize];

然后我们在使用一下:

1
2
3
4
5
6
<Router>
<Scene key="root">
<Scene key="GuidePage" component={GuidePage} hideNavBar title="GuidePage" initial={this.props.launched} />
<Scene key="RootPage" component={RootPage} title="RootPage" initial={this.props.launched}/>
</Scene>
</Router>

就OK了,具体的router的其他方法看文档。我们常用的就是PUSH还有POP,接下来我们看看怎么能写一个类似微信iOS App的TabBar,也就是程序的主框架:假设我们需要2个组件,创建2个文件夹,假定我们做一个新闻类的App,第一个叫主页,第二个是个人中心,修改index为:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
import React, { Component } from 'react';
import { AppRegistry, StyleSheet, View} from 'react-native';
import { Router, Scene } from 'react-native-router-flux';
import GuidePage from './GuidePage';
import RootPage from './RootPage';
class Project extends Component {
render() {
return (
<Router>
<Scene key="root">
<Scene key="GuidePage" component={GuidePage} hideNavBar title="GuidePage" initial={this.props.launched} />
<Scene key="RootPage" component={RootPage} title="RootPage" hideNavBar initial={this.props.launched}/>
</Scene>
</Router>
);
};
};
AppRegistry.registerComponent('Project', () => Project);

在RootPage中创建Tabbar:

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
import React, { Component, } from 'react';
import { View, Text, StyleSheet, TabBarIOS } from 'react-native';
import { Router, Scene, Actions, ActionConst } from 'react-native-router-flux';
import NewsPage from './News/NewsPage';
import AccountPage from './Account/AccountPage';
class RootPage extends Component {
constructor(props) {
super(props);
this.state = { selectedTab: "newsTab" };
}
render() {
return (
<TabBarIOS
unselectedTintColor="darkgrey"
tintColor="#34A3FF"
barTintColor="white">
<TabBarIOS.Item
title="News"
systemIcon="featured"
selected={this.state.selectedTab === 'newsTab'}
onPress={() => {
this.setState({
selectedTab: 'newsTab'
});
} }>
<NewsPage />
</TabBarIOS.Item>
<TabBarIOS.Item
title="Account"
systemIcon="contacts"
selected={this.state.selectedTab === 'accountTab'}
onPress={() => {
this.setState({
selectedTab: 'accountTab'
});
} }>
<AccountPage />
</TabBarIOS.Item>
</TabBarIOS>
);
};
}
export default RootPage

然后举例看一下News模块(这个文件管理所有的News路由):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
import React, { Component, } from 'react'
import { View, } from 'react-native'
import { Router, Scene, Actions, ActionConst } from 'react-native-router-flux';
import News from './News'
class NewsPage extends Component {
render() {
return (
<Router>
<Scene key="_NewsRouter">
<Scene key="News" component={News} title="News" initial={true} />
</Scene>
</Router>
)
}
}
export default NewsPage

这个是默认的News界面:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
import React, { Component, } from 'react'
import { View, } from 'react-native'
import { Router, Scene, Actions, ActionConst } from 'react-native-router-flux';
class News extends Component {
render() {
return (
<View style={{ backgroundColor: 'red', flex: 1 }}>
</View>
)
}
}
export default News

我们来看一下效果:

代码已经上传到github,这就是一个简单的应用程序框架,下周一我们来写新闻列表的获取数据并展示。

代码地址依旧没变。

评论