内容简介:React Navigation提供了一种在屏幕之间切换并管理导航历史记录的方式。 如果您的应用程序只使用一个 stack navigator ,则它在概念上类似于Web浏览器处理导航状态的方式 - 当用户与它进行交互时,应用程序会从导航堆栈中新增和删除页面,这会导致用户看到不同的页面。 Web浏览器和 React Navigation 工作原理的一个主要区别是:React Navigation 的 stack navigator 提供了在 Android 和 iOS 设备上,在堆栈中的路由之间导航时你期望
React Navigation提供了一种在屏幕之间切换并管理导航历史记录的方式。 如果您的应用程序只使用一个 stack navigator ,则它在概念上类似于Web浏览器处理导航状态的方式 - 当用户与它进行交互时,应用程序会从导航堆栈中新增和删除页面,这会导致用户看到不同的页面。 Web浏览器和 React Navigation 工作原理的一个主要区别是:React Navigation 的 stack navigator 提供了在 Android 和 iOS 设备上,在堆栈中的路由之间导航时你期望的 手势和动画 。
-
安装
yarn add react-navigation # or with npm # npm install --save react-navigation 复制代码
react-native link react-native-gesture-handler 复制代码
npm install 复制代码
然后把依赖引入到Android项目中:
第一步: setting.gradle
文件中添加
include ':react-native-gesture-handler' project(':react-native-gesture-handler').projectDir = new File(rootProject.projectDir, '../node_modules/react-native-gesture-handler/android') 复制代码
第二步:在Android/app/文件夹下的 build.gradle
文件中添加
implementation project(':react-native-gesture-handler') 复制代码第三步:
修改Application
第四步:修改Activity
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 { /** * Returns the name of the main component registered from JavaScript. * This is used to schedule rendering of the component. */ @Override protected String getMainComponentName() { return "demo"; } @Override protected ReactActivityDelegate createReactActivityDelegate() { return new ReactActivityDelegate(this, getMainComponentName()) { @Override protected ReactRootView createRootView() { return new RNGestureHandlerEnabledRootView(MainActivity.this); } }; } } 复制代码
-
路由的种类
createStackNavigator 为你的应用程序提供一种在每个新屏幕放置在堆栈顶部的屏幕之间转换的方法。 默认情况下,stack navigator 被配置为具有熟悉的iOS和Android外观 & 感觉:新屏幕从iOS右侧滑入,从Android底部淡入。 在iOS上,stack navigator 也可以配置为屏幕从底部滑入的模式样式。
SwitchNavigator 的用途是一次只显示一个页面。 默认情况下,它不处理返回操作,并在你切换时将路由重置为默认状态。 这是我们希望从身份验证流程(登录页面)获得的确切行为。
DrawerNavigator抽屉。
TabNavigator标签栏,可让您在不同路由之间进行切换。 路由被懒加载 - 它们的屏幕组件只有在第一次获取焦点时才会被加载。
-
页面切换
首先需要添加两个页面,在项目的根目录下新建了一个文件夹reactSrc
用来存放react-native代码。下面新建pages
文件夹专门存放页面文件。
pages/home/home.js ↓
import React from 'react' import { Text, Button, View, TouchableNativeFeedback } from 'react-native' export default class Home extends React.Component { render() { return ( <View style={{ flex: 1, alignItems: 'center', justifyContent: 'center' }}> <Text>Home Screen</Text> <TouchableNativeFeedback > <Button title="Go to Details" onPress={() => this.props.navigation.navigate('Details')} /></TouchableNativeFeedback> </View> ) } } 复制代码
pages/detail/detail.js ↓
import React from 'react' import { StyleSheet, Text } from 'react-native' export default class Detail extends React.Component { render() { return ( <Text>Detail</Text> ) } } const style = StyleSheet.create({ webview: { flex: 1 } }) 复制代码
然后修改App.js文件 ↓
import React, { Component } from 'react'; import { createStackNavigator, createAppContainer } from 'react-navigation'; import HomeScreen from './reactSrc/pages/home/home' import DetailsScreen from './reactSrc/pages/detail/detail' const AppNavigator = createStackNavigator({ Home: { screen: HomeScreen, }, Details: { screen: DetailsScreen, }, }, { initialRouteName: 'Home', }); const AppContainer = createAppContainer(AppNavigator); export default class App extends React.Component { render() { return <AppContainer />; } } 复制代码
-
传递参数给路由
将上面两个页面的代码稍加修改:
pages/home/home.js ↓
import React from 'react' import { Text, Button, View, TouchableNativeFeedback } from 'react-native' export default class Home extends React.Component { render() { const itemId = this.props.navigation.getParam('itemId', 'NO-ID'); return ( <View style={{ flex: 1, alignItems: 'center', justifyContent: 'center' }}> <Text>Home Screen</Text> <TouchableNativeFeedback > <Button title={itemId} onPress={() => this.props.navigation.navigate('Details', { itemId: 86, otherParam: 'anything you want here', })} /></TouchableNativeFeedback> </View> ) } } 复制代码
pages/detail/detail.js ↓
import React from 'react' import { View, Text, Button } from 'react-native' export default class Detail extends React.Component { render() { /* 2. Get the param, provide a fallback value if not available */ const { navigation } = this.props; const itemId = navigation.getParam('itemId', 'NO-ID'); const otherParam = navigation.getParam('otherParam', 'some default value'); return ( <View style={{ flex: 1, alignItems: 'center', justifyContent: 'center' }}> <Text>Details Screen</Text> <Text>itemId: {JSON.stringify(itemId)}</Text> <Text>otherParam: {JSON.stringify(otherParam)}</Text> <Button title="Go to Details... again" onPress={() => this.props.navigation.push('Details', { itemId: Math.floor(Math.random() * 100), })} /> <Button title="Go to Home" onPress={() => this.props.navigation.navigate('Home', { itemId: "Back From Detail:" + navigation.getParam('itemId', 'NO-ID') })} /> <Button title="Go back" onPress={() => this.props.navigation.goBack()} /> </View> ); } } 复制代码
一开始进入Home页面,路由里面没有‘itemId’对应的值,所以按钮上显示 NO-ID
。 点击这个按钮进入到Detail页面,Detail页面上显示从Home页面传过来的数据。
点击‘Go to Details... again’ 会新刷新数据。 点击‘Go to Home’会返回Home页,并传回数据。
navigate
调用此方法可跳转到应用程序中的另一个页面.如果已存在,将后退到此路由
goBack
关闭当前页面并返回上一个页面
StackNavigator提供了以下方法:
push
推一个新的路由到堆栈
pop
返回堆栈中的上一个页面
popToTop
跳转到堆栈中最顶层的页面
-
打开全屏模式(对话框)
一个modal就像一个弹出窗口 — 它不是主要导航流程的一部分 — 它通常有一个不同的转换,一个不同的关闭方式,并且打算专注于一个特定的内容或交互。
class HomeScreen extends React.Component { static navigationOptions = ({ navigation }) => { const params = navigation.state.params || {}; return { headerLeft: ( <Button onPress={() => navigation.navigate('MyModal')} title="Info" color="#fff" /> ), /* the rest of this config is unchanged */ }; }; /* render function, etc */ } class ModalScreen extends React.Component { render() { return ( <View style={{ flex: 1, alignItems: 'center', justifyContent: 'center' }}> <Text style={{ fontSize: 30 }}>This is a modal!</Text> <Button onPress={() => this.props.navigation.goBack()} title="Dismiss" /> </View> ); } } const MainStack = createStackNavigator( { Home: { screen: HomeScreen, }, Details: { screen: DetailsScreen, }, }, { /* Same configuration as before */ } ); const RootStack = createStackNavigator( { Main: { screen: MainStack, }, MyModal: { screen: ModalScreen, }, }, { mode: 'modal', headerMode: 'none', } ); 复制代码
说明:我们将一个 stack navigator 嵌套到另一个stack navigator 中。mode配置可以是card(默认)或modal。 在 iOS 上,modal表现为从页面底部划入,并允许用户从页面顶部向下缩小以关闭它。 modal配置对Android没有影响。当我们调用navigate方法时,我们不需要指定除我们想要导航的路由之外的任何东西。 没有必要限定它属于哪个堆栈, React Navigation 尝试在最近的导航器上查找路线,然后在那里执行操作。将页面从HomeScreen切换到MainStack 。我们知道MainStack无法处理路由MyModal,因此它会将其传递到可以处理该路由的RootStack,从而实现页面的跳转。
-
withNavigation
withNavigation是一个高阶组件,它可以将 navigation 这个 prop 传递到一个包装的组件。 当你无法直接将 navigation 这个 prop 传递给组件,或者不想在深度嵌套的子组件中传递它时,它将非常有用。注:一般情况下navigation只会在navigation启动的组件中作为prop传递。
import React from 'react'; import { Button } from 'react-native'; import { withNavigation } from 'react-navigation'; class MyBackButton extends React.Component { render() { return <Button title="Back" onPress={() => { this.props.navigation.goBack() }} />; } } // withNavigation returns a component that wraps MyBackButton and passes in the // navigation prop export default withNavigation(MyBackButton); 复制代码
-
深度链接
处理外部 URI,通过一个URI打开一个React-Native页面。
新建一个页面 pages/person/person.js ↓
import React from 'react' import { View, Text, Button } from 'react-native' export default class Person extends React.Component { render() { return ( <View style={{ flex: 1, alignItems: 'center', justifyContent: 'center' }}> <Text>Person Screen {this.props.navigation.getParam('user', 'NO-USER')}</Text> </View> ); } } 复制代码
App.js
添加 person
页面的路由, person
页面使用独立的栈 ↓
import React, { Component } from 'react'; import { createStackNavigator, createAppContainer, createSwitchNavigator } from 'react-navigation'; import HomeScreen from './reactSrc/pages/home/home' import DetailsScreen from './reactSrc/pages/detail/detail' import PersonScreen from './reactSrc/pages/person/person' const HomeNavigator = createStackNavigator({ Home: { screen: HomeScreen, }, Details: { screen: DetailsScreen, }, }); const MainNavigator = createSwitchNavigator({ HomeNavigator: { screen: HomeNavigator, }, PersonNavigator: { screen: PersonScreen, path: 'person/:user', }, }); const AppContainer = createAppContainer(MainNavigator); export default class App extends React.Component { render() { return <AppContainer uriPrefix='reactdemo://demoproject/' />; } } 复制代码
Android清单文件AndroidManifest.xml中给ReactNative的宿祖Activity加上 intent-filter
,
<?xml version="1.0" encoding="utf-8"?> <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.demo"> <uses-permission android:name="android.permission.INTERNET" /> <application android:name=".MainApplication" android:allowBackup="false" android:icon="@mipmap/ic_launcher" android:label="@string/app_name" android:roundIcon="@mipmap/ic_launcher_round" android:theme="@style/AppTheme"> <activity android:name=".Main2Activity"> <intent-filter> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" /> </intent-filter> </activity> <activity android:name=".MainActivity" android:configChanges="keyboard|keyboardHidden|orientation|screenSize" android:label="@string/app_name" android:windowSoftInputMode="adjustResize"> <intent-filter> <action android:name="android.intent.action.VIEW"/> <category android:name="android.intent.category.DEFAULT"/> <category android:name="android.intent.category.BROWSABLE"/> <data android:host="demoproject" android:scheme="reactdemo"/> </intent-filter> </activity> <activity android:name="com.facebook.react.devsupport.DevSettingsActivity" /> </application> </manifest> 复制代码
我新建了一个安卓原生界面 Main2Activity
,上面有两个按钮分别演示两种跳转方法(这里使用了安卓的anko库): Main2Activity.kt ↓
package com.demo import android.content.Intent import android.net.Uri import android.support.v7.app.AppCompatActivity import android.os.Bundle import kotlinx.android.synthetic.main.activity_main2.* import org.jetbrains.anko.startActivity class Main2Activity : AppCompatActivity() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_main2) button2.setOnClickListener { val intent = Intent() intent.action = Intent.ACTION_VIEW intent.data = Uri.parse("reactdemo://demoproject/person/:John") startActivity(intent) } button1.setOnClickListener { startActivity<MainActivity>() } } } 复制代码
activity_main2.xml ↓
<?xml version="1.0" encoding="utf-8"?> <android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" tools:context=".Main2Activity"> <Button android:id="@+id/button1" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginBottom="8dp" android:text="跳ReactNativeActivity" app:layout_constraintBottom_toTopOf="@+id/button2" app:layout_constraintLeft_toLeftOf="parent" app:layout_constraintRight_toRightOf="parent" app:layout_constraintTop_toTopOf="parent" /> <Button android:id="@+id/button2" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginTop="8dp" android:text="URI跳" app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintLeft_toLeftOf="parent" app:layout_constraintRight_toRightOf="parent" app:layout_constraintTop_toTopOf="parent" /> </android.support.constraint.ConstraintLayout> 复制代码
附:Android打包
在android/app/build.gradle文件写了注释:
/** * The react.gradle file registers a task for each build variant (e.g. bundleDebugJsAndAssets * and bundleReleaseJsAndAssets). * These basically call `react-native bundle` with the correct arguments during the Android build * cycle. By default, bundleDebugJsAndAssets is skipped, as in debug/dev mode we prefer to load the * bundle directly from the development server. Below you can see all the possible configurations * and their defaults. If you decide to add a configuration block, make sure to add it before the * `apply from: "../../node_modules/react-native/react.gradle"` line. * * project.ext.react = [ * // the name of the generated asset file containing your JS bundle * bundleAssetName: "index.android.bundle", * * // the entry file for bundle generation * entryFile: "index.android.js", * * // whether to bundle JS and assets in debug mode * bundleInDebug: false, * * // whether to bundle JS and assets in release mode * bundleInRelease: true, * * // whether to bundle JS and assets in another build variant (if configured). * // See http://tools.android.com/tech-docs/new-build-system/user-guide#TOC-Build-Variants * // The configuration property can be in the following formats * // 'bundleIn${productFlavor}${buildType}' * // 'bundleIn${buildType}' * // bundleInFreeDebug: true, * // bundleInPaidRelease: true, * // bundleInBeta: true, * * // whether to disable dev mode in custom build variants (by default only disabled in release) * // for example: to disable dev mode in the staging build type (if configured) * devDisabledInStaging: true, * // The configuration property can be in the following formats * // 'devDisabledIn${productFlavor}${buildType}' * // 'devDisabledIn${buildType}' * * // the root of your project, i.e. where "package.json" lives * root: "../../", * * // where to put the JS bundle asset in debug mode * jsBundleDirDebug: "$buildDir/intermediates/assets/debug", * * // where to put the JS bundle asset in release mode * jsBundleDirRelease: "$buildDir/intermediates/assets/release", * * // where to put drawable resources / React Native assets, e.g. the ones you use via * // require('./image.png')), in debug mode * resourcesDirDebug: "$buildDir/intermediates/res/merged/debug", * * // where to put drawable resources / React Native assets, e.g. the ones you use via * // require('./image.png')), in release mode * resourcesDirRelease: "$buildDir/intermediates/res/merged/release", * * // by default the gradle tasks are skipped if none of the JS files or assets change; this means * // that we don't look at files in android/ or ios/ to determine whether the tasks are up to * // date; if you have any other folders that you want to ignore for performance reasons (gradle * // indexes the entire tree), add them here. Alternatively, if you have JS files in android/ * // for example, you might want to remove it from here. * inputExcludes: ["android/**", "ios/**"], * * // override which node gets called and with what additional arguments * nodeExecutableAndArgs: ["node"], * * // supply additional arguments to the packager * extraPackagerArgs: [] * ] */ project.ext.react = [ entryFile: "index.js" ] apply from: "../../node_modules/react-native/react.gradle" …… 复制代码
react.gradle
文件被引入,为每个编译版本都注册了任务,然后下面是提供了一些可自定义的参数。当然它们都有默认值。默认在Debug模式下是不打bundle包的,在Release模式下才会打。并且官方推荐在Debug模式下从 development server 直接加载bundle包。
默认参数下会在"$buildDir/intermediates/assets/debug"下生成名为 index.android.bundle
的文件
但是网上都是推荐把这个文件生成到app/src/main/assets/文件夹下面:
首先创建一个assets文件夹 然后在React-Native项目的根目录下执行:
react-native bundle --platform android --dev false --entry-file index.js --bundle-output android/app/src/main/assets/index.android.bundle --assets-dest android/app/src/main/res/ 复制代码
然后文件就会自动生成了,然后直接打包就可以了。
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持 码农网
猜你喜欢:- RecyclerView使用指南(一)—— 基本使用
- 如何使用Meteorjs使用URL参数
- 使用 defer 还是不使用 defer?
- 使用 Typescript 加强 Vuex 使用体验
- [译] 何时使用 Rust?何时使用 Go?
- UDP协议的正确使用场合(谨慎使用)
本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。
Linux内核设计的艺术
新设计团队 / 机械工业出版社华章公司 / 2011-6-20 / 79.00元
关于Linux内核的书已经不计其数,但这本书却是独树一帜的,它的内容代表着Linux内核研究成果的世界顶尖级水平,它在世界范围内首次提出并阐述了操作系统设计的核心指导思想——主奴机制,这是所有操作系统研究者的一笔宝贵财富。本书可能也代表着同类图书的顶尖水平,是一本真正能引导我们较为容易地、极为透彻地理解Linux内核的经典之作,也可能是当前唯一能从本质上指引我们去设计和开发拥有自主知识产权的操作系......一起来看看 《Linux内核设计的艺术》 这本书的介绍吧!