React-Native: 页面搭建,导航配置

第一步:安装

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};
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值