上个篇幅主要介绍了RN的环境搭建,以及它自带的一个默认界面。实际开发的过程中,我们肯定是要重新设计的。那么最常见的就是做一个界面:有导航栏,底部条和一些文字按钮等,以及需要实现界面之间的跳转。类似如下图实现:
这个界面:1是导航栏;2是一个界面的文字说明;3是一个跳转button;4是底部条数据:总共有4个底部模块;
除了这个界面以外,我们还希望通过点击跳转button,能够跳转到一个详情介绍页面。参考下图:
我们可以通过点击返回,退回到首页。项目实现大致就是这些内容。下面简单介绍一下如何去实现。
(一)功能包下载:根目录下执行安装
前一节也有说过,rn集成了很多功能包,都是通过npm下载和安装的。通过这些功能包的组合,我们来实现我们所需要的功能。
npm add react-navigation
npm add react-native-gesture-handler
react-native link react-native-gesture-handler
npm install react-native-tab-navigator --save
主要就是上述的几个包,我们需要这么几个函数:createStackNavigator:创建导航栏;createBottomTabNavigator:底部条;createAppContainer这个是最终的展示界面。
(二)package.json安装文件列表:
我们下载完包以后,检查一下是否安装成功:
这个里面还有一些其他的包,比如os就是用来判断平台的,目前没有用到,暂时不管。
(三)文件架构:
我们需要建立4个底部模块和1个详情界面总共5个js文件,同时需要修改我们的入口文件App.js。首先看一下App.js文件的实现:
//1.先导入我们所需要的包
import React, {Component} from 'react';
import {Platform, StyleSheet, Text, View, Image} from 'react-native';
import PropTypes from 'prop-types';
import { platform } from "os";
import TabNavigator from 'react-native-tab-navigator';
//2.引入的底部条模块。注意:from引入的是一个js文件,虽然没有.js后缀。
import Home from './src/Component/Home';
import Article from './src/Component/Article';
import Owner from './src/Component/Owner';
import Order from './src/Component/Order';
import Details from './src/Component/Details';
/*****
3.我们需要使用到的三个方法:
createStackNavigator:创建导航栏
createBottomTabNavigator:创建底部条,这里我们抛弃了TabNavigator这种老方式定义
createAppContainer:创建最终的展示界面
******/
import {createStackNavigator} from 'react-navigation-stack'
import { createBottomTabNavigator, createAppContainer } from 'react-navigation';
var navigation = null;
type Props = {};
//4.程序入口,使用export的方式给外部调用
export default class App extends Component<Props> {
constructor(props){
super(props);
navigation = this.props.navigation;
this.state = {
selectedTab:'Home'
}
}
//5.底部模块嵌套导航栏组成一个界面,最后合并成一个包含4个底部模块的完整界面
topNavigator(){
let topTabs = createBottomTabNavigator({
//6.我们这里把首页和详情页放在一个控件里,属于一个空间
HomeVC:createStackNavigator(
{
Home: { screen: Home },
DetailsVC: { screen: Details },
},{
//6.导航栏属性定义:标题,底部模块名字,底部模块选中和正常的图片
navigationOptions:{
headerTitle:'首页',
tabBarLabel: '首页',
tabBarIcon: ({ focused, tintColor }) => (
<Image
source={focused ? require('./image/home_s.png') : require('./image/home_n.png')}
style={{ width: 26, height: 26, tintColor: tintColor }}
/>
)
} }),
ArticleVC:createStackNavigator({screen:Article},{
navigationOptions:{
headerTitle:'文章',
tabBarLabel: '文章',
tabBarIcon: ({ focused, tintColor }) => (
<Image
source={focused ? require('./image/article_s.png') : require('./image/article_n.png')}
style={{ width: 26, height: 26, tintColor: tintColor }}
/>
)
} }),
OwnerVC:createStackNavigator({screen:Owner},{
navigationOptions:{
headerTitle:'我的',
tabBarLabel: '我的',
tabBarIcon: ({ focused, tintColor }) => (
<Image
source={focused ? require('./image/owner_s.png') : require('./image/owner_n.png')}
style={{ width: 26, height: 26, tintColor: tintColor }}
/>
)
} }),
OrderVC:createStackNavigator({screen:Order},{
navigationOptions:{
headerTitle:'订单',
tabBarLabel: '订单',
tabBarIcon: ({ focused, tintColor }) => (
<Image
source={focused ? require('./image/order_s.png') : require('./image/order_n.png')}
style={{ width: 26, height: 26, tintColor: tintColor }}
/>
)
} }),
},
{
//7.整个底部条的属性
tabBarOptions: {
activeTintColor: '#4BC1D2',
inactiveTintColor: '#000',
showIcon: true,
showLabel: true,
upperCaseLabel: false,
pressColor: '#823453',
pressOpacity: 0.8,
style: {
backgroundColor: '#fff',
paddingBottom: 0,
borderTopWidth: 0.5,
borderTopColor: '#ccc',
},
labelStyle: {
fontSize: 12,
margin: 1
},
indicatorStyle: { height: 0 }, //8.android 中TabBar下面会显示一条线,高度设为 0 后就不显示线了
},
tabBarPosition: 'bottom',
swipeEnabled: false,
animationEnabled: false,
lazy: true,
backBehavior: 'none',
}
)
//9.组合成一个最终展示界面
return createAppContainer(topTabs)
}
render(){
let Pages = this.topNavigator()
return <Pages/>
}
}
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: '#F5FCFF',
},
tabIcon:{
width:23,
height:23,
}
});
再来看一下各个功能模块的界面实现代码,选Home.js来介绍一下,其他的模块都差不多,就不多一一展示了。
import React,{ Component } from 'react';
//1.这里要注意,我们所使用的视图类型必须在这里定义
import {
StyleSheet,
Text, Button,
View, Image,TouchableOpacity,
} from 'react-native';
import PropTypes from 'prop-types';
import { platform } from "os";
import TabNavigator from 'react-native-tab-navigator';
import { createStackNavigator, createAppContainer } from 'react-navigation';
type props = {}
export default class Home extends Component<props>{
static navigationOptions = {
headerTitle: '首页',//对页面的配置
tabBarLabel: '首页',
tabBarIcon: ({ focused, tintColor }) => (
<Image
source={focused ? require('./image/home_s.png') : require('./image/home_n.png')}
style={{ width: 26, height: 26, tintColor: tintColor }}
/>
)
};
constructor(props){
super(props);
}
//2.点击button我们跳转到详情界面
render(){
return (
<View style={styles.container}>
<Text style={styles.text}>首页</Text>
<Button title='去详情页' onPress={() => this.props.navigation.navigate('DetailsVC')}/>
</View>
);
}
}
const styles = StyleSheet.create({
container:{
flex:1,
justifyContent:'center',
alignItems:'center',
backgroundColor:'grey'
},
text:{
fontSize:30,
color:'black'
}
});
接下来再看一下详情界面。
import React,{ Component } from 'react';
import {
StyleSheet,
Text,
View, Image,TouchableOpacity,
} from 'react-native';
import PropTypes from 'prop-types';
import { platform } from "os";
import TabNavigator from 'react-native-tab-navigator';
import { createStackNavigator, createAppContainer } from 'react-navigation';
type props = {}
export default class Details extends Component<props>{
//1.重点说一下,通过设置标题
static navigationOptions = {
headerTitle: '详情'
};
constructor(props){
super(props);
}
render(){
const { navigate } = this.props.navigation;
return (
<View style={styles.container}>
<Text style={styles.text}>详情展示页</Text>
</View>
);
}
}
const styles = StyleSheet.create({
container:{
flex:1,
justifyContent:'center',
alignItems:'center',
backgroundColor:'grey'
},
text:{
fontSize:30,
color:'black'
}
});
主要的文件基本上就这些了。我们看一下文件目录。
注意:
1.目前最新的RN已经没有index.android.js和index.ios.js,统一成了index.js
2.ios和android代表的平台,相关的工程文件都放在各自对应的目录下。比如android目录打开就是这个样子:
这个就是一个典型的 Android Studio工程,我们如果需要做原生修改,就可以直接导入android这个目录。
注意:红箭头指向的assets目录是需要手工建立的,最后生成的bundle文件就放在这个目录下,我们再展开看一下:
通过编译,我们会生成一个index,android.bundle文件,包含了我们所有的源文件和资源。
3.image和src是我们自己建立的。我把资源图片放在了image下,js文件我放在了src目录下。
4.node_module目录下存放的是我们安装的react native包。
大致就是这样的一个目录结构。
(四)编译
1.Android版本:
react-native bundle --platform android --dev false --entry-file index.js --bundle-output android/app/src/main/assets/index.android.bundle --assets-dest android/app/src/main/res/
执行成功后,我们打开Android Studio运行就可以了。
2.Ios版本:
这个相对比较复杂,我们需要先在ios目录下建立一个目录,取名bundle,我们通过命令生成的离线包就安装在这个目录下。
react-native bundle --entry-file index.js --platform ios --dev false --bundle-output ./ios/bundle/index.ios.jsbundle --assets-dest ./ios/bundle
执行成功后,我们会在bundle下看到一个bundle文件和assets目录。如下图所示:
assets目录存放的就是我们所需要的全部资源。
现在我们要把生成的index.ios.jsbundle编译进我们的工程,打开xcode,先导入整个bundle目录。在工程目录下按右键,在出现的菜单栏中选择Add files功能,
选择bundle目录整个导入:
这样就把所有的bundle文件导入进来了。如下图:
现在打开AppDelegate.m,我们要改一行代码,参考下图:
注释1处使用的是原来的index文件,我们现在用的是离线包,因此需要改成2处的设计。
接下来还要配置网络访问白名单,打开info.plist :
一定要保证是YES,开启才能使用。
(五)总结
RN编译和运行经常会出现一个莫名其妙的错误,还是要多尝试去写,参考官网:https://reactnavigation.org/docs/zh-Hans/hello-react-navigation.html,大部分的问题都可以解决。
网上还多帖子都是用的比较旧的工程,只能仅供参考,需要自己多尝试和多学习。