React Navigation

2018-08-22  本文已影响0人  Android_冯星

官方网站

Learn once, navigate anywhere.

React Navigation的诞生,源于React Native社区对基于Javascript的可扩展且使用简单的导航解决方案的需求

只需安装react-navigation的npm package, 就可以开始使用React Navigation了

安装react-navigation

  1. 使用 NPM 安装
    npm install --save react-navigation
    或者使用yarn安装
    yarn add react-navigation

要开始使用React Navigation,您必须先创建一个navigator,React Navigation带有三种默认的navigator。

StackNavigator

'use strict';
import React,{Component} from 'react';

import {
  AppRegistry,
  StyleSheet,
  Text,
  View,
  Button,
  PixelRatio,
} from 'react-native';
//1. 导入文件
import { StackNavigator } from 'react-navigation';

//2. 编写页面
const HomeScreen = ({navigation}) =>(
        <View style={{ flex: 1, alignItems: 'center', justifyContent: 'center' }}>
            <Text>Home Screen</Text>
            //5. 从Home页面跳转到Details页面
            <Button 
                onPress={()=>navigation.navigate('Details')}
                title='Go to Details'
            ></Button>
        </View>
    );

const Details = ()=>(
<View style={{ flex: 1, alignItems: 'center', justifyContent: 'center' }}>
            <Text>Details Screen</Text>
        </View>
    );

//3.创建StackNavigator
const RootNavigator = StackNavigator({
    Home:{
        screen:HomeScreen,
        //4. 添加标题
        navigationOptions:{
            headerTitle:'home',
        },
    },
    Details:{
        screen:Details,
        navigationOptions:{
            headerTitle:'details',
        },
    }
});
export default RootNavigator;
效果图
image.png image.png

TabNavigator

我们将在例子中使用react-native-vector-icons, 如果你的项目中没有安装,请自行安装。

react-native-vector-icons ICONS是矢量图,可以直接使用图片名, 就能加载图片的第三方,使用很方便, 你不需要在工程文件夹里塞各种图片, 节省很多空间,
图片库
图片库
icons 使用

代码
'use strict';
import React,{Component} from 'react';

import {
  AppRegistry,
  StyleSheet,
  Text,
  View,
  Button,
  PixelRatio,
} from 'react-native';
//1. 导入文件
import { createBottomTabNavigator } from 'react-navigation';
import Ionicons from 'react-native-vector-icons/Ionicons';


//2.创建一些页面
const HomeScreen=()=>(
        <View style={{flex:1,alignItems:'center',justifyContent:'center'}}>
            <Text>HomeScreen</Text>
        </View>
    );

const ProfileScreen=()=>(
        <View style={{flex:1,alignItems:'center',justifyContent:'center'}}>
            <Text>ProfileScreen</Text>
        </View>
    );

//3. 添加TabNavigator中
const RootTabs = createBottomTabNavigator({
        Home:{
            screen:HomeScreen,
            navigationOptions:{
                //4. 创建标签
                tabBarLabel:'MyHome',
                //5 .添加图标
                tabBarIcon:({tintColor,focused})=>(
                        <Ionicons 
                            name={focused?'ios-home' : 'md-home'}
                            size={26}
                            style={focused?{ color: tintColor }:{color:'#f00'}}
                        >
                        </Ionicons>
                    ),
            },
        },
        Profile:{
            screen:ProfileScreen,
            navigationOptions:{
                tabBarLabel:'MyProfile',
                tabBarIcon:({tintColor,focused})=>(
                        <Ionicons
                            name={'ios-aperture'}
                            size={26}
                            style={{color:tintColor}}
                        >
                        </Ionicons>
                    ),
            }
        },
    });

//最后导出
export default RootTabs;
效果图
image.png image.png
出现的几个问题
  1. 消除警告
"Method jumpToIndex is deprecated. Please upgrade your code to use jumpTo instead. Change your code from jumpToIndex(1) to `jumpTo('Parties')."

这个警告的意思是把TabNavigator替换成createBottomTabNavigator
问题解决

import { createBottomTabNavigator } from 'react-navigation';

const RootTabs = createBottomTabNavigator({...});

  1. react-native-vector-icons 使用问题

注意:目前npm5存在安装新库时会删除其他库的问题,可能后面会修复导致项目无法正常运行。请尽量使用yarn代替npm操作。

DrawerNavigator

代码
'use strict';
import React,{Component} from 'react';
352152
import {
  AppRegistry,
  StyleSheet,
  Text,
  View,
  Button,
  PixelRatio,
} from 'react-native';

import { DrawerNavigator } from 'react-navigation';

import Ionicons from 'react-native-vector-icons/Ionicons';


const HomeScreen=({navigation})=>(
        <View style={{ flex: 1, alignItems: 'center', justifyContent: 'center' }}>
            <Text>HomeScreen</Text>
            <Button
                 onPress={()=>(navigation.toggleDrawer())} 
                 title="Open Drawer"
            ></Button>
        </View>
    );

const ProfileScreen=()=>(
        <View style={{flex: 1, alignItems: 'center', justifyContent: 'center'}}><Text>ProfileScreen</Text></View>
    );

const RootDrawer =DrawerNavigator({
    Home:{
        screen:HomeScreen,
        navigationOptions:{
            drawerLabel:'MyHome',
            drawerIcon:({tintColor, focused })=>(
                <Ionicons                   
                      name={'ios-home'}
                      size={20}
                      style={{ color: tintColor }}
                ></Ionicons>
                ),
        },
    },
    Profile:{
        screen:ProfileScreen,
        navigationOptions:{
            drawerLabel:'MyProfile',
            drawerIcon:({tintColor})=>(
                <Ionicons 
                    name={'ios-person'}
                    size={20}
                    style={{color:tintColor}}
                ></Ionicons>
                ),
        },
    }
});

export default RootDrawer;
效果图

点击Button会打开侧拉菜单

image.png image.png

嵌套导航

标题仅适用于StackNavigator。 本来想切换tab页面,标题也跟着切换,折腾了半天也没做出来。官方文档说的意思是标题仅适用于StackNavigator

这个例子意思是:StackNavigator导航里面嵌套TabNavigator导航。
把StackNavigator的主页面替换成了TabNavigator两个tab页面,在tab页面点击按钮跳转到StackNavigator导航页面并携带数据。

'use strict';
import React,{Component} from 'react';

import {
  AppRegistry,
  StyleSheet,
  Text,
  View,
  Button,
  PixelRatio,
} from 'react-native';

import { StackNavigator } from 'react-navigation';
import { createBottomTabNavigator } from "react-navigation";

/**
* Home页面
*/
class HomeScreen extends Component{
  static navigationOptions={
    title:'Welcome',
  };

  render(){
    const { navigate } = this.props.navigation;
    return(
        <View>
            <Text>Hello, Navigation!</Text>
            <Button 
                onPress={ ()=>{navigate('Chat',{user:'Lucy'})}}
                title='Chat with Lucy'
            ></Button>
         </View>
      );
  }
}

/**
*   聊天界面
*/
class ChatScreen extends Component{

    static navigationOptions=({navigation})=>({
        title:navigation.state.params.user,
    });
    

    render(){
        const userTitle=this.props.navigation.state.params.user;
        const {params} = this.props.navigation.state;
        return(
            <Text>{params.user}</Text>
            );
    }
}

class RecentChatsScreen extends Component{

    render(){
        return(
            <View>
                <Text>List of recent chats</Text>

                <Button
                    onPress={ () => {this.props.navigation.navigate('Chat',{user:'RecentChatsScreen'})}}
                    title='Chat with Lucy'
                ></Button>
            </View>     
            );
    }
}

class AllContactsScreen extends Component{
    render(){
        return(
            <View>
                <Text>List of all contacts</Text>

                <Button
                    onPress={ () => {this.props.navigation.navigate('Chat',{user:'AllContactsScreen'})}}
                    title='Chat with Lucy'
                ></Button>
            </View>     
            );
    }
}

/**
*   页面嵌套
*/
export const MainScreenNavigator=createBottomTabNavigator({
    Recent:{ 
        screen:RecentChatsScreen,   
        navigationOptions:{
            headerTitle:'My Chat',
        }   
    },
    All:{ 
        screen:AllContactsScreen,
        navigationOptions:{
            headerTitle:'My All',
        }
    },
});


export const SimpleApp=StackNavigator({
  HomeScreen:{
    screen:MainScreenNavigator,
    navigationOptions:{
        title:'My Chats',
        }
  },
  Chat:{
    screen:ChatScreen,
    Navigation:{
    }
  }
});



AppRegistry.registerComponent('MyApp', () => SimpleApp);

需要注意一点

点击按钮打开侧拉侧单下面这种做法是错误的。因为过时了。

<Button
      onPress={() => navigation.navigate('DrawerToggle')}
      title="Open Drawer"
    />

解决办法: 使用最新的API

 onPress={()=>(navigation.toggleDrawer())} 

标题仅适用于StackNavigator。

添加右侧的按钮

'use strict';
import React,{Component} from 'react';

import {
  AppRegistry,
  StyleSheet,
  Text,
  View,
  Button,
  PixelRatio,
  TextInput,
  //屏幕组件与标题的交互 记得导入
  ActivityIndicator,
} from 'react-native';

import { StackNavigator } from 'react-navigation';
import { createBottomTabNavigator } from "react-navigation";

/**
* Home页面
*/
class HomeScreen extends Component{
  static navigationOptions={
    title:'Welcome',
  };

  render(){
    const { navigate } = this.props.navigation;
    return(
        <View>
            <Text>Hello, Navigation!</Text>
            <Button 
                onPress={ ()=>{navigate('Chat',{user:'Lucy'})}}
                title='Chat with Lucy'
            ></Button>
         </View>
      );
  }
}

/**
*   聊天界面
*/
class ChatScreen extends Component{
    static navigationOptions=({navigation})=>{
        console.log(navigation);
        const {state,setParams} = navigation;
        const isInfo = state.params.mode === 'info';
        const {user} = state.params;
        //添加右侧的按钮
        //动态修改标题  和  button的title
        return{
            title: isInfo ? `${user}'s Contact Info` :  `Chat with ${state.params.user}`,
            headerRight:(
                <Button
                    title={isInfo ? 'Done' : `${user}'s info`}
                    onPress={()=>{setParams({mode:isInfo?'none' : 'info'})}}
                ></Button>
                ),
        };
    };
    

    render(){
        console.log(this);
        const userTitle=this.props.navigation.state.params.user;
        const {params} = this.props.navigation.state;
        return(
            <Text>{params.user}</Text>
            );
    }
}

class RecentChatsScreen extends Component{

    render(){
        return(
            <View>
                <Text>List of recent chats</Text>

                <Button
                    onPress={ () => {this.props.navigation.navigate('Chat',{user:'RecentChatsScreen'})}}
                    title='Chat with Lucy'
                ></Button>
            </View>     
            );
    }
}

class AllContactsScreen extends Component{
    render(){
        return(
            <View>
                <Text>List of all contacts</Text>

                <Button
                    onPress={ () => {this.props.navigation.navigate('Chat',{user:'AllContactsScreen'})}}
                    title='Chat with Lucy'
                ></Button>
            </View>     
            );
    }
}

/**
*   页面嵌套
*/
export const MainScreenNavigator=createBottomTabNavigator({
    Recent:{ 
        screen:RecentChatsScreen,   
        navigationOptions:{
            headerTitle:'My Chat',
        }   
    },
    All:{ 
        screen:AllContactsScreen,
        navigationOptions:{
            headerTitle:'My All',
        }
    },
});

/**
*   屏幕组件与标题的交互
*/
class EditInfoScreen extends Component{

    static navigationOptions= ({navigation}) =>{
        // 3 获取navigation state 中 params 属性 使用解构赋值 并设置默认值
        const {params={}} = navigation.state;
        console.log(params);
        console.log(params.handleSave);
        //设置标题右侧按钮 
        let headerRight=(
            <Button 
                title='Save'
                // handleSave 是函数_handlerSave  params.handleSave才会调用函数 
                onPress={params.handleSave? params.handleSave : ()=>null}
            ></Button>
            );
        console.log(params.isSaveing);
        if(params.isSaveing){
            headerRight = <ActivityIndicator/>;
        }
        return {headerRight};
    }

    //2. 编写state属性 存放数据
    state={
        nickName:'fengxing',
    }

    componentDidMount(){
        this.props.navigation.setParams({handleSave:this._handlerSave});
        console.log(this._handlerSave);
    }

    _handlerSave= ()=>{
        console.log('_handlerSave');
        this.props.navigation.setParams({isSaveing:true});

        //saveInfo().then(()=>{
        //  this.props.navigation.setParams({isSaveing:false});
        //});
    }


    render(){
        return(
            //1. 编写组件基本内容 
            <View>
                <TextInput 
                    style={{height: 400, borderColor: 'gray', borderWidth: 1,marginTop:30}}
                    placeholder={'Nickname'}
                    onChangeText={ (nickName) => this.setState({nickName}) }
                    multiline={true}
                    value={this.state.nickName}
                >
                </TextInput>

                <Button 
                    title='点击'
                    onPress = { ()=> this.props.navigation.setParams({isSaveing:false}) }
                    >
                </Button>
            </View>
            );
    }
}


/**
*   输出的视图
*/
export const SimpleApp=StackNavigator({
  HomeScreen:{
    screen:MainScreenNavigator,
    navigationOptions:{
        title:'My Chats',
        }
  },
  Chat:{
    screen:EditInfoScreen,
    Navigation:{
    }
  }
});


AppRegistry.registerComponent('MyApp', () => SimpleApp);

内置导航器

react-navigation包含以下功能来帮助你创建导航器:

StackNavigator

API 定义

StackNavigator(RouteConfigs, StackNavigatorConfig)

RouteConfigs

路由配置对象是从路由名称到路由配置的映射,告诉导航器该路由应该呈现什么。

StackNavigator({

  // For each screen that you can navigate to, create a new entry like this:
  Profile: {

    // `ProfileScreen` is a React component that will be the main content of the screen.
    screen: ProfileScreen,
    // When `ProfileScreen` is loaded by the StackNavigator, it will be given a `navigation` prop.

    // Optional: When deep linking or using react-navigation in a web app, this path is used:
    path: 'people/:name',
    // The action and route params are extracted from the path.

    // Optional: Override the `navigationOptions` for the screen
    navigationOptions: ({navigation}) => ({
      title: `${navigation.state.params.name}'s Profile'`,
    }),
  },

  ...MyOtherRoutes,
});

StackNavigatorConfig

router的选项:

视觉选项:

Screen Navigation Options

title

可当作headerTitle的备用的字符串。 此外,将用作tabBarLabel(如果嵌套在TabNavigator中)或drawerLabel(如果嵌套在DrawerNavigator中)的后备。

header

可以是React元素或给定了HeaderProps然后返回一个React元素的函数,显示为标题。 设置为null隐藏标题。

headerTitle

字符串、React元素或被当作标题的React组件。默认显示title属性的值。当使用一个组件时,它会收到allowFontScalingstylechildren属性。 标题字符串在children中进行传递。

headerTitleAllowFontScaling

标题栏中标题字体是否应该缩放取决于文本大小是否可以设置。 默认为true。

headerBackTitle

iOS上的返回按钮的文字使用的字符串,或者使用null来禁用。 默认为上一个页面的headerTitle

headerTruncatedBackTitle

headerBackTitle不适合在屏幕显示时(一般是因为文字太多),返回按钮使用的标题字符串。 默认是Back

headerRight

显示在标题栏右侧的React元素。

headerLeft

用于在标题栏左侧展示的React元素或组件。当一个组件被渲染时,它会接收到很多的属性(onPress, title, titleStyle 等等, - 请检查 Header.js 的完整列表)

headerStyle

标题栏的样式

headerTitleStyle

标题栏中标题的样式

headerBackTitleStyle

标题栏中返回按钮标题的样式

headerTintColor

标题栏的色调

headerPressColorAndroid

material design中的波纹颜色 (仅支持Android >= 5.0)

gesturesEnabled

是否可以使用手势来关闭此页面。 在iOS上默认为true,在Android上默认为false。

gestureResponseDistance

一个对象,用以覆盖从屏幕边缘开始触摸到手势被识别的距离。 它具有以下属性:

字符串,用来设置关闭页面的手势方向,默认(default)是从做往右,inverted是从右往左

/**
*   输出的视图
*/
export const SimpleApp=StackNavigator({
  HomeScreen:{
    screen:MainScreenNavigator,
    navigationOptions:{
        title:'My Chats',
        }
  },
  Chat:{
    screen:EditInfoScreen,
    Navigation:{
    }
  }
},{
    //定义标题该如何渲染 none 没有标题 float 淡入淡出 screen
    headerMode: 'screen',
    //弹出方式
    mode:'modal',

    navigationOptions: {
        //是否可以使用手势来关闭此页面。 在iOS上默认为true,在Android上默认为false。
        gesturesEnabled: false,
   },
    
    //
    transitionConfig:() => ({
        transitionSpec:{
            duration:300,
            easing:Easing.out(Easing.poly(4)),
            timing: Animated.timing,
        }
    })
});

TabNavigator

API 定义

TabNavigator(RouteConfigs, TabNavigatorConfig)

TabNavigatorConfig

传递到底层路由,用于修改导航逻辑的几个选项:

TabBarBottomtabBarOptions (TabBarBottom为iOS的默认tab bar)

tabBarOptions: {
  activeTintColor: '#e91e63',
  labelStyle: {
    fontSize: 12,
  },
  style: {
    backgroundColor: 'blue',
  },
}

TabBarToptabBarOptions (TabBarTop为Android的默认tab bar)

栗子:

tabBarOptions: {
  labelStyle: {
    fontSize: 12,
  },
  tabStyle: {
    width: 100,
  },
  style: {
    backgroundColor: 'blue',
  },
}

Screen Navigation Options

title

可以用作headerTitletabBarLabel后备的通用标题。(headerTitletabBarLabel未设置时,就会使用title的值替代)

tabBarVisible

tab bar是否可见,缺省是true

swipeEnabled

是否允许tab页之间滑动切换,如果未设置,则使用TabNavigatorConfigswipeEnabled选项

tabBarIcon

用于在tab bar中展示的React元素或一个传入{ focused: boolean, tintColor: string }返回React.Node的函数

tabBarLabel

用于在tab bar中展示的一个字符串或者一个传入{ focused: boolean, tintColor: string }返回React.Node的函数,如果未定义,则使用页面的title属性。如果像隐藏文本,请参阅上一小节中讲到的tabBarOptions.showLabel

tabBarOnPress

tab被点击时的回调函数;参数是一个对象,包含一下属性:

DrawerNavigator

使用...navigate('DrawerOpen')和...navigate('DrawerClose')打开和关闭抽屉

this.props.navigation.navigate('DrawerOpen'); // open drawer
this.props.navigation.navigate('DrawerClose'); // close drawer
上一篇 下一篇

猜你喜欢

热点阅读