ReactNative——导航器react-navigation(堆栈式导航器篇)

react-navigation

安装核心包

yarn add @react-navigation/native

安装@react-navigation/native本身依赖的相关包

react-native-reanimated:动画库

react-native-gesture-handler:手势库

react-native-screens:使用原生代码实现screen容器可以提高性能流畅度

react-native-safe-area-context:可以让我们的组件渲染在一个安全的区域(比如有些移动设备是异性的,刘海屏、挖孔屏等)

@react-native-community/masked-view:堆栈式导航器所依赖的库

yarn add react-native-reanimated react-native-gesture-handler react-native-screens react-native-safe-area-context @react-native-community/masked-view

React Native 0.60以上,链接是自动的,因此不需要运行react原生链接。

但在iOS开发上,则需要安装pod来完成链接

cd ios 
pod install

打开android/app/src/main/java/<your package name>/MainActivity.java

加入以下代码

public class MainActivity extends ReactActivity {
  // ...
  @Override
  protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(null);
  }
  // ...
}

在该文件顶部加入

import android.os.Bundle;

在项目入口文件引入@react-navigation/native

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

如何使用堆栈式导航器

安装核心库

yarn add @react-navigation/stack

比如说写一个home组件

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

class Home extends React.Component {
    render() {
        return (
            <View>
                <Text>Home</Text>
            </View>    
        )
    }
}

export default Home;

再写一个Detail组件

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

class Detail extends React.Component {
    render() {
        return (
            <View>
                <Text>Detail</Text>
            </View>    
        )
    }
}

export default Detail;

然后在navigator下新建个文件夹index.tsx

import React from 'react';
import {NavigationContainer} from '@react-navigation/native'
import {createStackNavigator} from '@react-navigation/stack'
import Home from '@/pages/Home';
import Detail from '@/pages/Detail';

type RootStackPareamList = {
    Home: undefined;
    Detail:undefined;
}


let Stack = createStackNavigator<RootStackPareamList>();
/*{
    Navigator, // 导航器
    Screen // 路由,也就是页面
}
*/

class Navigator extends React.Component {
    render(){
        return (
            <NavigationContainer>
                <Stack.Navigator>
                    <Stack.Screen name="Home" component={Home}/>
                    <Stack.Screen name="Detail" component={Detail}/>
                </Stack.Navigator>
            </NavigationContainer>);
    }
}

export default Navigator;

然后在src/index.tsx

import Navigator from '@/navigator/index';

export default Navigator;

可以发现Android和ios的标题显示不一样,这是因为ios和Android的默认设计风格不一样导致的。

如何统一ios和Android的标题风格呢

使用screanOptions属性就好,在Stack.Screen里也有options属性,这样就可以单独设置某个页面的标题样式了,还有一些常用的属性 如:headerTitle:'首页'

import React from 'react';
import {NavigationContainer} from '@react-navigation/native'
import {createStackNavigator} from '@react-navigation/stack'
import Home from '@/pages/Home';
import Detail from '@/pages/Detail';

type RootStackPareamList = {
    Home: undefined;
    Detail:undefined;
}


const Stack = createStackNavigator<RootStackPareamList>();
/*{
    Navigator, // 导航器
    Screen // 路由,也就是页面
}
*/

class Navigator extends React.Component {
    render(){
        return (
            <NavigationContainer>
                <Stack.Navigator
                    screanOptions={{
                        headerTitleAlign:'center',
                    }}>
                    <Stack.Screen options={{ headerTitleAlign:'left, headerTitle:'首页'}} name="Home" component={Home}/>
                    <Stack.Screen name="Detail" component={Detail}/>
                </Stack.Navigator>
            </NavigationContainer>);
    }
}

export default Navigator;

页面间的跳转如何实现?

import React from 'react';
import {NavigationContainer} from '@react-navigation/native'
import {createStackNavigator} from '@react-navigation/stack'
import Home from '@/pages/Home';
import Detail from '@/pages/Detail';
import {
  createStackNavigator,
  StackNavigationProp,
} from '@react-navigation/stack'; // 自动引入

type RootStackPareamList = {
    Home: undefined;
    Detail:undefined;
}

// 加这一行
export type RootStackNavigation = StackNavigationProp<RootStackPareamList>


const Stack = createStackNavigator<RootStackPareamList>();
/*{
    Navigator, // 导航器
    Screen // 路由,也就是页面
}
*/

class Navigator extends React.Component {
    render(){
        return (
            <NavigationContainer>
                <Stack.Navigator
                    headerMode="float"
                    screanOptions={{
                        headerTitleAlign:'center',
                    }}>
                    <Stack.Screen options={{ headerTitleAlign:'left, headerTitle:'首页'}} name="Home" component={Home}/>
                    <Stack.Screen name="Detail" component={Detail}/>
                </Stack.Navigator>
            </NavigationContainer>);
    }
}

export default Navigator;

tips:

headerMode="float"所有页面共用一个标题栏(ios的默认)

headerMode="none"没有标题栏

headerMode="screen"每个页面都有一个标题栏(Android的默认)

在Home组件中使用

import React from 'react';
import { View, Text, Button } from 'react-native';
import { RootStackNavigation } from '@/navigator/index'

interface IProps {
    navigation:RootStackNavigation;
}

class Home extends React.Component<IProps> {

    onPress = () => {
        const {navigation} = this.props;
        navigation.navigate("Detail");
    }
    
    render() {
        return (
            <View>
                <Text>Home</Text>
                <Button title="跳转到详情页" onPress={this.onPress}/>
            </View>    
        )
    }
}

export default Home;

目前这样跳转是比较生硬的。

如何产生一个跳转的动画效果?

让前一个页面的从左边划走,然后后一个页面从右往左进来,透明度从0到1渐变

可以使用headerStyleInterpolator:HeaderStyleInterpolators.forUIKit,ios就能实现上述效果

使用cardStyleInterpolator:CardStyleInterpolators.forHorizontalIOS,Android也能实现跟ios类似的效果了

<Stack.Navigator
    headerMode="float"
    screanOptions={{
        headerTitleAlign:'center',
        headerStyleInterpolator:HeaderStyleInterpolators.forUIKit,
        cardStyleInterpolator:CardStyleInterpolators.forHorizontalIOS,
    }}>
</Stack.Navigator>

但是可以发现ios是可以通过手势操作关闭详情页得,但是Android是不可以得,因为ios默认开启手势,Android默认不开启

使用gestureEnabled:true,开启手势系统,然后会神奇的发现,Android从左向右滑动还是无法关闭详情页,因为Android默认的手势方向是垂直方向,所以往下滑就能关闭详情页,如何让它像ios那样向右滑动可以关闭呢?

继续设置手势方向为水平即可:gestureDirection:'horizontal',

<Stack.Navigator
    headerMode="float"
    screanOptions={{
        headerTitleAlign:'center',
        headerStyleInterpolator:HeaderStyleInterpolators.forUIKit,
        cardStyleInterpolator:CardStyleInterpolators.forHorizontalIOS,
        gestureEnabled:true,
        gestureDirection:'horizontal',
    }}>
</Stack.Navigator>

仔细观察会发现,Android的显示没有ios美观。

如何针对Android写样式呢?

【安卓改善前效果如下图】

【改善后的Android效果】,左边阴影去掉了,也去掉了标题的下边框阴影

使用headerStyle

<Stack.Navigator
    headerMode="float"
    screanOptions={{
        headerTitleAlign:'center',
        headerStyleInterpolator:HeaderStyleInterpolators.forUIKit,
        cardStyleInterpolator:CardStyleInterpolators.forHorizontalIOS,
        gestureEnabled:true,
        gestureDirection:'horizontal',
        headerStyle: {
            ...Platform:select({
                android: {
                    elevation:0,
                    borderBottomWidth:StyleSheet.hairlineWidth,
                }
            })
        },
    }}>
</Stack.Navigator>

页面跳转间如何传参呢?

这是开发种十分常见的场景,如进入详情页,肯定需要在跳转的时候传递id的

那么需要在src/navigator/index.tsx种修改(就是导航组件的位置,你的项目不一定在这个路径)

设置一下详情页接收参数的类型,因为后续在Detail需要用到这个类型,因此再加个export导出

export type RootStackPareamList = {
    Home: undefined;
    Detail:{
        id:number;
    }
}

然后再Home组件,增加传递参数的逻辑

// home组件里的那个跳转方法
onPress = () => {
    const {navigation} = this.props;
    navigation.navigate("Detail",{
        id:100,
    }); // 这里增加了传参~
}

在Detail组件接收即可

import React from 'react';
import { View, Text } from 'react-native';
import { RootStackParamList } from '@/navigator/index';

interface IProps {
    route:RouteProp<RootStackParamList,'Detail'>;
}

class Detail extends React.Component<IProps> {
    render() {
        const { route } = this.props
        return (
            <View>
                <Text>Detail</Text>
                <Text>{route.params.id}</Text>
            </View>    
        )
    }
}

export default Detail;

后续再写一个标签导航器~

  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值