react-native路由之react-navigation(一)

安装

在react-native项目目录下,安装react-navigation包

npm install --save react-navigation

然后再安装react-native-gesture-handler包

npm install --save react-native-gesture-handler

link所有原生依赖

react-native link react-native-gesture-handler

react-native-gesture-handler在 Android 上的安装,还需要手动修改 MainActivity.java (./android/app/src/main/java/com/newpro)文件

package com.reactnavigation.newpro;

import com.facebook.react.ReactActivity;
+ import com.facebook.react.ReactActivityDelegate;
+ import com.facebook.react.ReactRootView;
+ import com.swmansion.gesturehandler.react.RNGestureHandlerEnabledRootView;

public class MainActivity extends ReactActivity {

  @Override
  protected String getMainComponentName() {
    return "newpro";
  }

+  @Override
+  protected ReactActivityDelegate createReactActivityDelegate() {
+    return new ReactActivityDelegate(this, getMainComponentName()) {
+      @Override
+      protected ReactRootView createRootView() {
+       return new RNGestureHandlerEnabledRootView(MainActivity.this);
+      }
+    };
+  }
}

创建createStackNavigator

createStackNavigator是一个返回 React 组件的方法。 它需要 a route configuration object(一个路由配置对象) 和 an options object(一个可选对象) (现在我们忽略下面的内容). 由于 createStackNavigator 函数会返回一个React组件,因此我们可以直接从 App.js 中导出它以用作我们应用程序的根组件。

只有唯一一个路由配置:

如果只有唯一一个路由,则直接对Home进行赋值{ Home: HomeScreen }

import React from "react";
import { View, Text } from "react-native";
import { createStackNavigator, createAppContainer } from "react-navigation";
class HomeScreen extends React.Component {
  render() {
    return (
    <View style={{ flex: 1, alignItems: "center", justifyContent: "center" }}>
       <Text>Home Screen</Text>
    </View>
    );
    }
}
const AppNavigator = createStackNavigator({ Home: HomeScreen });
export default createAppContainer(AppNavigator);

多个路由配置:

import React from 'react';
import { View, Text, Button } from 'react-native';
import { createAppContainer, createStackNavigator, StackActions, NavigationActions } from 'react-navigation'; // Version can be specified in package.json

class HomeScreen extends React.Component {
  render() {
    return (
      <View style={{ flex: 1, alignItems: 'center', justifyContent: 'center' }}>
        <Text>Home Screen</Text>
        <Button
          title="Go to Details"
          onPress={() => {
            this.props.navigation.dispatch(StackActions.reset({
              index: 0,
              actions: [
                NavigationActions.navigate({ routeName: 'Details' })
              ],
            }))
          }}
        />
      </View>
    );
  }  
}

class DetailsScreen extends React.Component {
  render() {
    return (
      <View style={{ flex: 1, alignItems: 'center', justifyContent: 'center' }}>
        <Text>Details Screen</Text>
      </View>
    );
  }  
}

const AppNavigator = createStackNavigator({
  Home: {
    screen: HomeScreen,
  },
  Details: {
    screen: DetailsScreen,
  },
}, {
    initialRouteName: 'Home',
});

export default createAppContainer(AppNavigator);

页面跳转

情况1:navigate

this.props.navigation.navigate('Details')

如果重复多次跳到这个页面,这个页面是不会发生变化的,因为这里已经有这个路由了,你再去访问相同的路由,是不会有任何变化的

情况2:push

 this.props.navigation.push('Details')

如果是直接push的话,就不会去考虑原先有没有这个路由,都是直接再次添加一个新的路由进去的

情况3:返回

返回上一个页面

this.props.navigation.goBack();

或:

this.props.navigation.pop();

返回到堆栈中的第一个页面

 this.props.navigation.popToTop()

传递参数给路由

A跳转到B

A页面点击事件:

  this.props.navigation.push('Details', {
     testId: 123
 })

B页面获取A中带入的参数:

  <Text>{this.props.navigation.getParam('testId')}</Text>

或:

<Text>{this.props.navigation.state.params.testId}</Text>

改变传到B页面的参数:

    this.props.navigation.setParams({
        testId: '321'
   })

配置标题栏

调整标题样式

标题样式有三个关键属性:headerStyle、headerTintColor和headerTitleStyle

  • headerStyle: 标题栏最外层的View样式,一般用来设置标题栏背景颜色
  • headerTintColor: 返回按钮和标题文字颜色
  • headerTitleStyle: 为标题定制fontFamily,fontWeight和其他Text样式属性,我们可以用它来完成。
 static navigationOptions = {
    title: 'Home',
    headerStyle: {
      backgroundColor: '#f4511e',
    },
    headerTintColor: 'white',
    headerTintStyle: {
      fontWeight: 'bold',
    }
  };

公用标题栏样式

在APP.js中添加defaultNavigationOptions属性,如下:

import React from 'react';
import { View, Text, Button } from 'react-native';
import { createAppContainer, createStackNavigator, StackActions, NavigationActions } from 'react-navigation'; // Version can be specified in package.json

import HomeScreen from './Router/HomeScreen'
import DetailsScreen from './Router/DetailsScreen'
import News from './Router/News'

const AppNavigator = createStackNavigator({
  Home: {
    screen: HomeScreen,
  },
  Details: {
    screen: DetailsScreen,
  },
  News:{
    screen: News
  }
}, {
    initialRouteName: 'Home',
    defaultNavigationOptions: {
      headerStyle: {
        backgroundColor: 'green',
        },
        headerTintColor: '#fff',
        headerTitleStyle: {
        fontWeight: 'bold',
        },
    }
});

export default createAppContainer(AppNavigator);

这样,所有导航栏样式都公用了, 如果要改变个别导航栏样式,可以在当前页面修改

有时候,你可能需要获取上一个页面带来的参数,那么标题导航可以:

  static navigationOptions = ({ navigation, navigationOptions }) => {
    const { params } = navigation.state;
    return {
      title: params.testId+'news'
    };
  };

改变左侧返回按钮

     headerLeft: (<Text
        onPress={()=>{
          navigation.goBack();
        }}
        style={{color: 'white', paddingLeft: 10}}
        >
        返回
      </Text>)

如果要改变返回按钮的图片,则需添加headerBackImage属性

添加右侧按钮

    headerRight: (<Text
        onPress={()=>{
          navigation.setParams({testId: '改变的新内容'})
        }}
        style={{color: 'white', marginRight: 10}}>
        改变参数
      </Text>)

整合如下:

 static navigationOptions = ({ navigation, navigationOptions }) => {
    const { params } = navigation.state;
    return {
      title: params.testId+'news',
      headerLeft: (<Text
        onPress={()=>{
          navigation.goBack();
        }}
        style={{color: 'white', paddingLeft: 10}}
        >
        返回
      </Text>),
      headerRight: (<Text
        onPress={()=>{
          navigation.setParams({testId: '改变的新内容'})
        }}
        style={{color: 'white', marginRight: 10}}>
        改变参数
      </Text>)
    };
  };

有时候,我们的右侧按钮是要改变当前页面的state值,但是这里我们并不能直接访问到页面的state值,这里我们可以利用setParams和getParam来处理,如下:

import React from 'react';
import { View, Text, Button } from 'react-native';


class DetailsScreen extends React.Component {

  state = {
    count: 0
  }

  static navigationOptions = ({ navigation, navigationOptions }) => {
    const { params } = navigation.state;
    return {
      title: params.testId+'news',
      headerLeft: (<Text
        onPress={()=>{
          navigation.goBack();
        }}
        style={{color: 'white', paddingLeft: 10}}
        >
        返回
      </Text>),
      headerRight: (<Text
        onPress={navigation.getParam('getCount')}
        style={{color: 'white', marginRight: 10}}>
        计数
      </Text>)
    };
  };

  addCount = () => {
    this.setState({
      count: this.state.count+1
    })
  }

  componentDidMount(){
    this.props.navigation.setParams({
      getCount: this.addCount
    })
  }
  render() {
    const { navigation } = this.props;
    console.log(navigation)
    return (
      <View style={{ flex: 1, alignItems: 'center', justifyContent: 'center' }}>
        <Text>Details Screen</Text>
        <Text>计数大小: {this.state.count}</Text>
        <Text>{navigation.getParam('testId')}</Text>
        <Text>{navigation.state.params.testId}</Text>
        <Text onPress={()=>{
          navigation.setParams({
            testId: '321'
          })
        }}>
          改变参数
        </Text>
        <Text onPress={()=>{
          this.props.navigation.navigate('News')
        }}>News Screen</Text>
        <Text onPress={()=>{
          this.props.navigation.goBack();
        }}>返回goback</Text>
         <Text onPress={()=>{
          this.props.navigation.pop();
        }}>返回pop</Text>

      </View>
    );
  }
}

export default DetailsScreen

在componentDidMount中setParams一个方法,然后就可以在标题栏中调用了

自定义导航栏

import React from 'react';
import { View, Text, Button } from 'react-native';


class TitleBox extends React.Component {
  render() {
    return (
      <Text>自定义标题</Text>
    )
  }
}

class News extends React.Component {
  static navigationOptions = {
    headerTitle: <TitleBox/>
  };
  render() {
    return (
      <View style={{ flex: 1, alignItems: 'center', justifyContent: 'center' }}>
        <Text>News Screen</Text>
        <Text onPress={()=>{
          this.props.navigation.popToTop()
        }}>返回首页</Text>
      </View>
    );
  }
}

export default News

不需要导航栏

 static navigationOptions = {
    header: null
 };

底部导航

属性:

activeTintColor -活动选项卡的标签和图标颜色。
activeBackgroundColor -活动选项卡的背景色。
inactiveTintColor -"非活动" 选项卡的标签和图标颜色。
inactiveBackgroundColor -非活动选项卡的背景色。
showLabel -是否显示选项卡的标签, 默认值为 true。
showIcon - 是否显示 Tab 的图标,默认为false。
style -选项卡栏的样式对象。
labelStyle -选项卡标签的样式对象。
tabStyle -选项卡的样式对象。
allowFontScaling -无论标签字体是否应缩放以尊重文字大小可访问性设置,默认值都是 true。
adaptive - Should the tab icons and labels alignment change based on screen size? Defaults to true for iOS 11. If false, tab icons and labels align vertically all the time. When true, tab icons and labels align horizontally on tablet.
safeAreaInset - 为 <SafeAreaView> 组件重写 forceInset prop, 默认值:{ bottom: 'always', top: 'never' }; top | bottom | left | right 的可选值有: 'always' | 'never'。
import React from 'react';
import { createAppContainer, createBottomTabNavigator } from 'react-navigation'; // Version can be specified in package.json

import HomeScreen from './Router/HomeScreen'
import Test from './Router/block'

const TabNavigator = createBottomTabNavigator(
  {
    Main: HomeScreen,
    Test:Test
  },
  {
    initialRouteName: 'Main',
    tabBarOptions: {
      activeTintColor: 'gold',
      inactiveTintColor: 'gray',
      style: {
        height: 50,
      }
    },
  }
);



const AppContainer = createAppContainer(TabNavigator)

class App extends React.Component {
  render() {
    return (
      <AppContainer/>
    )
  }
}

export default App;


如果应用了底部导航,有些模块可能不止一个页面,这该如何处理呢?如下:

import React, {Component} from 'react';
import { View, Text, Image } from 'react-native';
import { createAppContainer, createStackNavigator, createBottomTabNavigator } from 'react-navigation'; // Version can be specified in package.json

import HomeScreen from './Router/HomeScreen'
import DetailsScreen from './Router/DetailsScreen'
import News from './Router/News'
import Test from './Router/block'

const AppNavigator = createStackNavigator({
  Home: {
    screen: HomeScreen,
  },
  Details: {
    screen: DetailsScreen,
  },
  News:{
    screen: News
  }
},
{
    initialRouteName: 'Home',
    defaultNavigationOptions: {
      headerStyle: {
        backgroundColor: 'green',
        },
        headerTintColor: '#fff',
        headerTitleStyle: {
        fontWeight: 'bold',
        },

    }
}
);


const TabNavigator = createBottomTabNavigator(
  {
    Main: {
      screen: AppNavigator,
      navigationOptions: ({ navigation }) => {

        return {
          tabBarLabel:'主页面',
          tabBarIcon: ({ focused }) => {
            return (
              <Image
              style={{width: 30, height:30}}
              source={
                focused
                  ? require('./images/ic_home_entertainment_p.png')
                  : require('./images/ic_home_entertainment_n.png')
              }
            />
            )
          }
        }
      }
    },
    Test:{
      screen: Test,
        navigationOptions: {
            // 底部导航
          tabBarLabel:'测试页面',
          tabBarIcon: ({ focused }) => {
         return (
            <Image
             style={{width: 30, height:30}}
             source={
            focused
             ? require('./images/ic_home_home_p.png')
            : require('./images/ic_home_home_n.png')
           }
         />
        )
  }
      }
    }
  },
  {
    initialRouteName: 'Main',
    tabBarOptions: {
      activeTintColor: 'gold',
      inactiveTintColor: 'gray',
      style: {
        height: 50,
      }
    },
    defaultNavigationOptions: ({ navigation }) => {
      const { routeName } = navigation.state;

      return {
        gesturesEnabled: false
      }
    }
  }
);


const AppContainer = createAppContainer(TabNavigator)

class App extends Component {
  render() {
    return (
      <AppContainer/>
    )
  }
}

export default App;

在这里插入图片描述

具体代码链接:https://gitee.com/hope93/react-navigation

  • 1
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
React Native 中,可以使用第三方库来实现路由拦截。一个常用的库是 React Navigation,它提供了强大的导航和路由管理功能。 要实现路由拦截,可以使用 React Navigation 提供的导航守卫功能。导航守卫可以在路由变化前或后执行自定义的逻辑。 以下是一个简单的示例,演示如何在 React Native 中使用 React Navigation 实现路由拦截: 1. 首先,确保已经安装了 React Navigation: ``` npm install @react-navigation/native ``` 2. 安装所需的导航器(例如 Stack Navigator): ``` npm install @react-navigation/stack ``` 3. 创建一个名为 `NavigationService.js` 的新文件,用于导航拦截逻辑: ```javascript import { NavigationActions } from '@react-navigation/compat'; let navigator; function setTopLevelNavigator(navigatorRef) { navigator = navigatorRef; } function navigate(routeName, params) { navigator.dispatch( NavigationActions.navigate({ routeName, params, }) ); } // 添加其他需要的导航方法 export default { navigate, setTopLevelNavigator, }; ``` 4. 在根组件中设置导航器并引用 `NavigationService.js`: ```javascript import { NavigationContainer } from '@react-navigation/native'; import { createStackNavigator } from '@react-navigation/stack'; import NavigationService from './NavigationService'; const Stack = createStackNavigator(); function App() { return ( <NavigationContainer ref={navigatorRef => { NavigationService.setTopLevelNavigator(navigatorRef); }}> <Stack.Navigator> {/* 添加其他屏幕 */} </Stack.Navigator> </NavigationContainer> ); } export default App; ``` 5. 在需要拦截的组件中使用 `NavigationService.js`: ```javascript import NavigationService from './NavigationService'; // 在需要拦截的地方调用 `NavigationService.navigate` 方法 NavigationService.navigate('ScreenName'); ``` 通过这种方式,你可以在路由变化前后执行自定义的逻辑,例如验证用户权限、处理特定的跳转逻辑等。需要注意的是,这只是一个简单的示例,你可以根据具体的需求进行定制和扩展。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值