React Navigation5.X (Stack,BottomTab,Drawer,登录权限认证)

React Navigation V5 的发布和之前版本写法上有些不同,这篇文章就讲Stack,BottomTab,Drawer使用和登录权限认证

v5移除了createSwitchNavigator登录权限认证会和之前有些变动

在新版React Navigation V5中使用的新的HOC模式,只需要在应用最外层包裹 NavigationContainer

import React from 'React'
import { NavigationContainer } from '@react-navigation/native';

export default function App() {
  return (
    <NavigationContainer>{/* Rest of your app code */}</NavigationContainer>
  );
}

文章涉及代码:github

开始使用React Navigation V5

createStackNavigator

· StackNavigator现在的写法类似数据结构的堆栈
默认情况下屏幕的跳转方式 ios 从右侧滑入,android 从底部划入,可以在ScreenOptions中设置屏幕的跳转方式 cardStyleInterpolator文档

  screenOptions={{
      cardStyleInterpolator: CardStyleInterpolators.forHorizontalIOS,
  }}>
import React from 'react';

import {NavigationContainer} from '@react-navigation/native';
import {createStackNavigator} from '@react-navigation/stack';
import {HomeScreen, DetailsScreen} from './Screen';

const Stack = createStackNavigator();

function StackScreen() {
  return (
    <Stack.Navigator 
      screenOptions={{
        cardStyleInterpolator: CardStyleInterpolators.forHorizontalIOS,
      }}>
      <Stack.Screen name="Home" component={HomeScreen} />
      <Stack.Screen name="Details" component={DetailsScreen} />
    </Stack.Navigator>
  );
}

export default function App() {
  return (
    <NavigationContainer>
      <StackScreen />
    </NavigationContainer>
  );
}

createDrawerNavigator

93rpr-zkv73.gif

点击按钮或从屏幕侧边划入显示抽屉界面

import React from 'react';
import {NavigationContainer} from '@react-navigation/native';
import {createDrawerNavigator} from '@react-navigation/drawer';

const Drawer = createDrawerNavigator();
function DrawerScreen() {
  return (
    <Drawer.Navigator>
      <Drawer.Screen name="Home" component={HomeScreen} />
      <Drawer.Screen name="Setting" component={SettingScreen} />
    </Drawer.Navigator>
  );
}

export default function App() {
  return (
    <NavigationContainer>
      <DrawerScreen/>
    </NavigationContainer>
  );
}

createBottomTabNavigator


屏幕底部TabBar

import React from 'react';
import {View} from 'react-native';
import {NavigationContainer} from '@react-navigation/native';
import {createBottomTabNavigator} from '@react-navigation/bottom-tabs';
const Tab = createBottomTabNavigator();
const TabBarIcon = (focused, color) => {
  return (
    <View
      style={{
        width: focused ? 24 : 18,
        height: focused ? 24 : 18,
        backgroundColor: color,
      }}
    />
  );
};
function TabScreen() {
  return (
    <Tab.Navigator
      tabBarOptions={{activeTintColor: '#FD7328', inactiveTintColor: '#999'}}
      screenOptions={{
        tabBarIcon: ({focused, color}) => {
          return TabBarIcon(focused, color);
        },
      }}>
      <Tab.Screen
        name="Home"
        component={HomeScreen}
        options={{title: '首页'}}
      />
      <Tab.Screen
        name="Mine"
        component={MineScreen}
        options={{title: '我的'}}
      />
    </Tab.Navigator>
  );
}

export default function App() {
  return (
    <NavigationContainer>
      <TabScreen />
    </NavigationContainer>
  );
}

Stack,Drawer,BottomTab结合使用

import React from 'react';
import {View} from 'react-native';
import {NavigationContainer} from '@react-navigation/native';
import {
  createStackNavigator,
  CardStyleInterpolators,
} from '@react-navigation/stack';
import {createDrawerNavigator} from '@react-navigation/drawer';
import {createBottomTabNavigator} from '@react-navigation/bottom-tabs';
import {HomeScreen, DetailsScreen, SettingScreen, MineScreen} from './Screen';

const Stack = createStackNavigator();

function StackScreen() {
  return (
    <Stack.Navigator
      screenOptions={{
        cardStyleInterpolator: CardStyleInterpolators.forHorizontalIOS,
      }}>
      <Stack.Screen name="Drawer" component={DrawerScreen} />
      <Stack.Screen name="Details" component={DetailsScreen} />
    </Stack.Navigator>
  );
}

const Drawer = createDrawerNavigator();

function DrawerScreen() {
  return (
    <Drawer.Navigator>
      <Drawer.Screen name="Tab" component={TabScreen} />
      <Drawer.Screen name="Setting" component={SettingScreen} />
    </Drawer.Navigator>
  );
}

const Tab = createBottomTabNavigator();

const TabBarIcon = (focused, color) => {
  return (
    <View
      style={{
        width: focused ? 24 : 18,
        height: focused ? 24 : 18,
        backgroundColor: color,
      }}
    />
  );
};
function TabScreen() {
  return (
    <Tab.Navigator
      tabBarOptions={{activeTintColor: '#FD7328', inactiveTintColor: '#999'}}
      screenOptions={{
        tabBarIcon: ({focused, color}) => {
          return TabBarIcon(focused, color);
        },
      }}>
      <Tab.Screen
        name="Home"
        component={HomeScreen}
        options={{title: '首页'}}
      />
      <Tab.Screen
        name="Mine"
        component={MineScreen}
        options={{title: '我的'}}
      />
    </Tab.Navigator>
  );
}

export default function App() {
  return (
    <NavigationContainer>
      <StackScreen />
    </NavigationContainer>
  );
}

登录权限认证

v5版本之前可以使用createSwitchNavigator做登录身份认证,在V5版本移除了这个方法,可以使用V5新特性,根据状态定义和更改导航器的内容

本次使用react Context进行管理,也可根据项目需要使用reduxmobx

1.创建context

import React from 'react';

export const AuthContext = React.createContext();

2.屏幕导航

// screen
export function SettingScreen() {
  const {signOut} = React.useContext(AuthContext);
  return (
    <BaseCenterView>
      <Text>设置</Text>
      <Button
        title="退出登录"
        onPress={() => {
          signOut();
        }}
      />
    </BaseCenterView>
  );
}
export function SignInScreen() {
  const {signIn} = React.useContext(AuthContext);
  return (
    <BaseCenterView>
      <Text>登录页面</Text>
      <Button
        title="登录"
        onPress={() => {
          signIn();
        }}
      />
    </BaseCenterView>
  );
}
export function SplashScreen() {
  return (
    <BaseCenterView>
      <Text>loading...</Text>
    </BaseCenterView>
  );
}
// Auth屏幕堆栈
const AuthStack = createStackNavigator();
const AuthStackScreen = () => (
  <AuthStack.Navigator headerMode="none">
    <AuthStack.Screen name="SignIn" component={SignInScreen} />
  </AuthStack.Navigator>
);
// APP堆栈
const Drawer = createDrawerNavigator();
function DrawerScreen() {
  return (
    <Drawer.Navigator>
      <Drawer.Screen name="Tab" component={TabScreen} />
      <Drawer.Screen name="Setting" component={SettingScreen} />
    </Drawer.Navigator>
  );
}

const Tab = createBottomTabNavigator();
const TabBarIcon = (focused, color) => {
  return (
    <View
      style={{
        width: focused ? 24 : 18,
        height: focused ? 24 : 18,
        backgroundColor: color,
      }}
    />
  );
};

function TabScreen() {
  return (
    <Tab.Navigator
      tabBarOptions={{activeTintColor: '#FD7328', inactiveTintColor: '#999'}}
      screenOptions={{
        tabBarIcon: ({focused, color}) => {
          return TabBarIcon(focused, color);
        },
      }}>
      <Tab.Screen
        name="Home"
        component={HomeScreen}
        options={{title: '首页'}}
      />
      <Tab.Screen
        name="Mine"
        component={MineScreen}
        options={{title: '我的'}}
      />
    </Tab.Navigator>
  );
}

const MainStack = createStackNavigator();
function MainStackScreen() {
  return (
    <MainStack.Navigator
      screenOptions={{
        cardStyleInterpolator: CardStyleInterpolators.forHorizontalIOS,
      }}>
      {/* <MainStack.Screen name="Drawer" component={DrawerScreen} /> */}
      <MainStack.Screen name="Home" component={HomeScreen} />
      <MainStack.Screen name="Details" component={DetailsScreen} />
    </MainStack.Navigator>
  );
}
// Root堆栈
const RootStack = createStackNavigator();
const RootStackScreen = ({userToken = false}) => (
  <RootStack.Navigator headerMode="none">
    {userToken ? (
      <RootStack.Screen
        name="App"
        component={MainStackScreen}
        options={{
          animationEnabled: false,
        }}
      />
    ) : (
      <RootStack.Screen
        name="Auth"
        component={AuthStackScreen}
        options={{
          animationEnabled: false,
        }}
      />
    )}
  </RootStack.Navigator>
);
// 主路由
export default () => {
  const [isLoading, setIsLoading] = React.useState(true);
  const [userToken, setUserToken] = React.useState(null);

  const authContext = React.useMemo(() => {
    return {
      signIn: () => {
        setIsLoading(false);
        setUserToken('asdf');
      },
      signUp: () => {
        setIsLoading(false);
        setUserToken('asdf');
      },
      signOut: () => {
        setIsLoading(false);
        setUserToken(null);
      },
    };
  }, []);

  React.useEffect(() => {
    setTimeout(() => {
      setIsLoading(false);
    }, 1000);
  }, []);
  if (isLoading) {
    return <SplashScreen />;
  }
  return (
    <AuthContext.Provider value={authContext}>
      <NavigationContainer>
        <RootStackScreen userToken={userToken} />
      </NavigationContainer>
    </AuthContext.Provider>
  );
};

结束

文章涉及代码:github

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 217,542评论 6 504
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,822评论 3 394
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 163,912评论 0 354
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,449评论 1 293
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,500评论 6 392
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,370评论 1 302
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,193评论 3 418
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,074评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,505评论 1 314
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,722评论 3 335
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,841评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,569评论 5 345
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,168评论 3 328
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,783评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,918评论 1 269
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,962评论 2 370
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,781评论 2 354

推荐阅读更多精彩内容