第一步:安装
npm i @react-navigation/native react-native-screens react-native-safe-area-context @react-navigation/native-stack @react-navigation/bottom-tabs
如果是iOS上跑程序,就需要重新去pod install
,把上面新增的库,下载到工程本地
第二步:配置
1、如图所示,在 src/pages 目录下,
新建 index.js --- 用来导出所有页面
新建tabBar/Home.js --- 项目首页
新建 My.js --- 项目个人中心页
新建 TabBarNavigator.js --- 配置tabBar页面
新建 launchPage/LaunchPage.js --- 项目启动页
新建 launchPage/GuidePage.js --- 项目引导页
2、编写index.js
import LaunchPage from './launchPage/LaunchPage';
import GuidePage from './launchPage/GuidePage';
import Home from './tabBar/Home';
import My from './tabBar/My';
import TabBarNavigator from './tabBar/TabBarNavigator';
const appRouter = [
{
name: 'LaunchPage',
component: LaunchPage,
headerShown: false,
},
{
name: 'GuidePage',
component: GuidePage,
headerShown: false,
},
{
name: 'Home',
component: Home,
headerShown: false,
},
{
name: 'My',
component: My,
headerShown: false,
},
{
name: 'TabBarNavigator',
component: TabBarNavigator,
headerShown: false,
},
];
export default appRouter;
注意name和component名字可以不一样,但是后续 navigation 的页面跳转都是用 name,以免造成开发上面的心智困难,建议弄成一样,不然后续你看着页面文件想不起页面的name命名。。。
3、修改App.js
Provider 是全局状态管理redux --- 不需要可以去掉
AntdProvider 是@ant-design/react-native的Provider自定义重命名,有的这个东西antd的一些弹窗才能显示 --- 不需要可以去掉
import React from 'react';
import {StyleSheet} from 'react-native';
import {NavigationContainer} from '@react-navigation/native';
import {createNativeStackNavigator} from '@react-navigation/native-stack';
import {
SafeAreaProvider,
initialWindowMetrics,
} from 'react-native-safe-area-context';
import {Provider} from 'react-redux';
import {Provider as AntdProvider} from '@ant-design/react-native';
import appRouter from 'src/pages';
import store from 'src/redux/store';
const Stack = createNativeStackNavigator();
export default function App() {
console.log(appRouter);
return (
<Provider store={store}>
<AntdProvider>
<SafeAreaProvider initialMetrics={initialWindowMetrics}>
<NavigationContainer>
<Stack.Navigator initialRouteName={'LaunchPage'}>
{appRouter &&
appRouter.map(item => {
return (
<Stack.Screen
key={item.name}
name={item.name}
component={item.component}
options={{headerShown: item.headerShown}}
/>
);
})}
</Stack.Navigator>
</NavigationContainer>
</SafeAreaProvider>
</AntdProvider>
</Provider>
);
}
const styles = StyleSheet.create({});
此处我的默认页面为 LaunchPage 就启动App 进入首页前,必须经过 LaunchPage页面。
在LaunchPage页面初始化一些App数据很有必要。
如果说后续配置了App的启动图,再到我们页面的启动页会显示两张,解决方法也很简单,就是将App的启动图和我们页面的启动页图设置成同一张图即可
4、 编写LaunchPage.js
import React, {useEffect} from 'react';
import {NativeModules, Platform, StatusBar, View} from 'react-native';
import {useNavigation} from '@react-navigation/native';
import {commonSize, commonStyle} from 'src/assets/css/commonStyle';
import {storageSync} from 'src/utils/storage';
import {navigateReplace, setNavigation} from 'src/utils/navigation';
import {useSafeAreaInsets} from 'react-native-safe-area-context';
import {CtImage} from 'src/components';
import Orientation from '@hortau/react-native-orientation-locker';
const LaunchPage = () => {
// 给 navigation.js 传递 navigation
const navigation = useNavigation();
setNavigation(navigation);
const insets = useSafeAreaInsets();
// 获取状态栏高度
const {StatusBarManager} = NativeModules;
if (Platform.OS === 'ios') {
commonSize.statusBarHeight = StatusBarManager.HEIGHT;
} else if (Platform.OS === 'android') {
commonSize.statusBarHeight =
(StatusBarManager && StatusBarManager.HEIGHT) || StatusBar.currentHeight;
}
// 获取iOS安全区域距离
// 注意 iOS的状态栏高度 与 iOS的顶部安全距离 不一定一样高
// 在布局特殊全面屏头部的时候 建议使用 iOS的顶部安全距离
if (Platform.OS === 'ios') {
commonSize.safeAreaInsetTop = insets.top;
commonSize.safeAreaInsetBottom = insets.bottom;
commonSize.safeAreaInsetLeft = insets.left;
commonSize.safeAreaInsetRight = insets.right;
}
// 获取当前设备的方向
commonSize.screenOrientation = Orientation.getInitialOrientation();
useEffect(() => {
// 判断用户是否是第一层启动App 是则进入引导页 否则进入首页
setTimeout(async () => {
let isFirstLaunchApp = await storageSync.getStorage('isFirstLaunchApp');
if (Number(isFirstLaunchApp) === 1) {
goHome();
} else {
goGuide();
}
}, 1000);
}, []);
const goHome = () => {
navigateReplace('TabBarNavigator');
};
return (
<View style={commonStyle.container}>
<CtImage source={require('src/assets/images/img_launchPage.jpg')} />
</View>
);
};
export default LaunchPage;
5、编写GuidePage.js
import React, {useState} from 'react';
import {StyleSheet, View} from 'react-native';
import {CustomSwiper, CtBtn} from 'src/components';
import {commonStyle} from 'src/assets/css/commonStyle';
import {navigateReplace} from 'src/utils/navigation';
import {storageSync} from 'src/utils/storage';
const GuidePage = () => {
const [swiperCurrentIndex, setSwiperCurrentIndex] = useState(0);
const guideList = [
{
image_url: require('src/assets/images/img_GuidePage01.jpg'),
name: '001',
},
{
image_url: require('src/assets/images/img_GuidePage02.jpg'),
name: '002',
},
{
image_url: require('src/assets/images/img_GuidePage03.jpg'),
name: '003',
},
];
const getSwiperChange = item => {
setSwiperCurrentIndex(item.index);
};
const guideSwiperMask = () => {
if (swiperCurrentIndex === guideList.length - 1) {
return (
<View style={[commonStyle.flexCenter, styles.swiperMaks]}>
<CtBtn
btnText={"Let's go"}
onPress={() => {
storageSync.setStorage('isFirstLaunchApp', 1);
navigateReplace('TabBarNavigator');
}}
/>
</View>
);
} else {
return <View style={styles.swiperMaks} />;
}
};
return (
<View style={styles.container}>
<CustomSwiper
onSwiperChange={getSwiperChange}
data={guideList}
autoplay={false}
/>
{guideSwiperMask(guideList)}
</View>
);
};
export default GuidePage;
const styles = StyleSheet.create({
container: {
flex: 1,
},
swiperMaks: {
position: 'absolute',
left: 0,
right: 0,
bottom: 60,
},
});
这个页面就是一个轮播图,轮播到最后一张引导图的时候,显示一个按钮,点击按钮,进入首页
6、编写TabBarNavigator.js
import React from 'react';
import {StyleSheet, Image} from 'react-native';
import {createBottomTabNavigator} from '@react-navigation/bottom-tabs';
import {commonColors} from 'src/assets/css/commonStyle';
import Home from './Home';
import My from './My';
const Tab = createBottomTabNavigator();
const TabBarNavigator = () => {
return (
<Tab.Navigator
initialRouteName={Home}
screenOptions={{
tabBarHideOnKeyboard: true,
tabBarInactiveTintColor: commonColors.textColorSecondary,
tabBarActiveTintColor: commonColors.textColorPrimary,
tabBarStyle: styles.tabBarStyle,
}}>
<Tab.Screen
name={'Home'}
component={Home}
options={{
headerShown: false,
tabBarIcon: ({focused}) => (
<Image
style={styles.tabBarIcon}
source={
focused
? require('src/assets/images/tabBar/tab_home_active.png')
: require('src/assets/images/tabBar/tab_home.png')
}
/>
),
}}
/>
<Tab.Screen
name={'My'}
component={My}
options={{
headerShown: false,
tabBarIcon: ({focused}) => (
<Image
style={styles.tabBarIcon}
source={
focused
? require('src/assets/images/tabBar/tab_my_active.png')
: require('src/assets/images/tabBar/tab_my.png')
}
/>
),
}}
/>
</Tab.Navigator>
);
};
export default TabBarNavigator;
const styles = StyleSheet.create({
tabBarStyle: {
backgroundColor: commonColors.bgColorWhite,
},
tabBarIcon: {
resizeMode: 'cover',
width: 28,
height: 28,
},
});
7、上面的代码里面,我重新封装了navigation。在 src/utils 下 新建navigation.js
import React from 'react';
import {StackActions} from '@react-navigation/native';
import indexConfig from 'src/config/index.config';
let _navigation;
function setNavigation(navigation) {
_navigation = navigation;
}
const navigatePush = (routeName, params) => {
_navigation.dispatch(StackActions.push(routeName, params));
};
const navigateReplace = (routeName, params) => {
_navigation.dispatch(StackActions.replace(routeName, params));
};
const navigateBack = (count = 1) => {
_navigation.dispatch(StackActions.pop(count));
};
const navigateToTop = () => {
_navigation.dispatch(StackActions.popToTop());
};
const authNavigatePush = (routeName, params) => {
let accessToken = indexConfig.accessToken;
if (accessToken) {
navigatePush(routeName, params);
} else {
navigatePush('Login', params);
}
};
const authNavigateReplace = (routeName, params) => {
let accessToken = indexConfig.accessToken;
if (accessToken) {
navigateReplace(routeName, params);
} else {
navigatePush('Login', params);
}
};
export {
setNavigation,
navigatePush,
navigateReplace,
navigateBack,
navigateToTop,
authNavigatePush,
authNavigateReplace,
};
在 LaunchPage 页面 调用 setNavigation(navigation); 把 useNavigation hock方法传进来,
这样以来,就不用在每个页面去写 useNavigation。并且 新增了 authNavigatePush 等方法,可以简单判断用户是否登录。
8、此外,贴上我的 src/assets/css/commonStyle.js
import {Dimensions, Platform, StatusBar, StyleSheet} from 'react-native';
const {width, height} = Dimensions.get('window');
const commonColors = {
colorPrimary: '#FFD200',
colorPrimaryRgba: 'rgba(255, 210, 0, 0.2)',
colorSuccess: '#07c160',
colorWarning: '#F59A23',
colorDanger: '#ee0a24',
colorInfo: '#fffbe8',
bgColorBlack: '#000',
bgColorWhite: '#fff',
bgColorPrimary: '#F5F5F5',
bgColorTransparent: 'transparent',
textColorPrimary: '#333',
textColorRegular: '#666',
textColorSecondary: '#999',
textColorPlaceholder: '#E0E0E0',
borderColorBase: '#AAA',
borderColorDark: '#999',
borderColorLight: '#E5E5E5',
borderColorLighter: '#E0E0E0',
};
const commonSize = {
screenOrientation: '',
width: width,
height: height,
statusBarHeight: 0,
safeAreaInsetTop: 0,
safeAreaInsetBottom: 0,
safeAreaInsetLeft: 0,
safeAreaInsetRight: 0,
navBarHeight: 44,
radiusMedium: 12,
radiusSmall: 8,
radiusMini: 4,
borderWidth: StyleSheet.hairlineWidth,
};
const commonStyle = {
/** flex **/
flexLeftCenter: {
flexDirection: 'row',
alignItems: 'center',
},
flexCenter: {
flexDirection: 'row',
alignItems: 'center',
justifyContent: 'center',
},
flexRightCenter: {
flexDirection: 'row',
alignItems: 'center',
justifyContent: 'flex-end',
},
flexBetween: {
flexDirection: 'row',
alignItems: 'center',
justifyContent: 'space-between',
},
flexColumnLeft: {
flexDirection: 'column',
alignItems: 'flex-start',
},
flexColumnCenter: {
flexDirection: 'column',
alignItems: 'center',
justifyContent: 'center',
},
flexColumnRight: {
flexDirection: 'column',
alignItems: 'flex-end',
},
flexColumnBetween: {
flexDirection: 'column',
justifyContent: 'space-between',
},
flexAround: {
flexDirection: 'row',
justifyContent: 'space-around',
},
flexWrap: {
flexDirection: 'row',
flexWrap: 'wrap',
},
testBorder: {
borderWidth: 5,
borderColor: 'red',
},
bgFFF: {
backgroundColor: commonColors.bgColorWhite,
},
bg000: {
backgroundColor: commonColors.bgColorBlack,
},
container: {
flex: 1,
position: 'relative',
backgroundColor: commonColors.bgColorPrimary,
},
relative: {
position: 'relative',
},
absolute: {
position: 'absolute',
},
};
export {commonColors, commonSize, commonStyle};