react native入门到实战(有可能是全站最详细的RN教程)
https://www.bilibili.com/video/BV1Pt4y1n7bD
P1 P1.01.简介
React Native 是 Facebook 在 React.js Conf 2015 上推出了开源框架
React Native(简称 RN)是 React 的一个原生(Native)扩展
它允许我们通过 React 语法,来开发 ios 和 Android 原生应用
官网:https://reactnative.dev/
Github:https://github.com/facebook/react-native
中文网:https://www.reactnative.cn/
原生开发 原生 App Android | iOS | Windows
混合开发 混合App React Native | Weex | Flutter
H5 开发 Web App HTML,CSS,JavaScript
React Native的不足
it_刖不成熟;项目版本更新维护较频繁,学习成本高;试错成本高,有些问题较少解决方案,易耽误开发进度。
性能差
整体性能仍不如原生;兼容性差
·涉及底层的功能,需要针对 Android 和 ios 双端单独开发;
P2 P2.02.基础环境搭建
P3 P3.03.搭建安卓环境
P4 P4.04.搭建 iOS 环境
安装 Watchman
安装 Xcode
安装CocoaPods
P5 P5.05.初始化项目
模拟器调试
点击模拟器(使模拟器获取焦点)
快捷键 ctrl+m / adb shell input keyevent 82 逍遥模拟器
点选 debug
·自动跳转到浏览器
环境和软件版本
操作系统:Windows 10
开发工具:VS Code
React Native 版本:0.63.3
React 版本:16.13.1
P6 P6.06.StyleSheet
RN 中的样式与CSS的不同
没有继承性
样式名采用小驼峰命名
所有尺寸都是没有单位
有些特殊的样式名
marginHorizontal(水平外边距),marginVertical(垂直外边距)
快捷键rnc rncc rnfc
P7 P7.07.Flexbox(上)
flexDirection
声明主轴方向:row(Web默认)Icolumn(RN默认)
justifyContent
声明项目在主轴上的对齐方式
alignltems
声明项目在交叉轴上的对齐方式
P8 P8.08.Flexbox(中)
P9 P9.09.Flexbox()
P10 P10.10.响应式布局
响应式布局
Flexbox
Dimensions
P11 P11.11.组件简介
.RN 中的核心组件,是对原生组件的封装
原生组件:Android 或 ios 内的组件
核心组件:RN 中最常用的,来在 react-native 的组件
核心组件
基础组件
交互控件
列表视图
ios 独有组件
Android 独有组件
其他
View视图组件
Text文本组件
Alert警告框组件
Button按钮组件
Switch开关组件
StatusBar状态栏组件
ActivityIndicator加载指示器组件
Image图片组件
Textinput输入框组件
Touchable触碰组件(共三个)
ScrollView滚动视图组件
SectionList分组列表组件
FlatList高性能列表组件
Animated动画组件
P12 P12.12.Alert和Button
P13 P13.13.Switch和StatuBar
/**
* Sample React Native App
* https://github.com/facebook/react-native
*
* @format
*/
import React, { useState } from 'react';
import {
SafeAreaView, //安全 刘海屏
ScrollView, //滚动内容区域
StatusBar, //状态栏
StyleSheet, //样式表
View, //块 视图
Image,
TouchableOpacity,
Text,
TextInput,
FlatList,
Dimensions,
Switch
} from 'react-native';
//适应所有屏幕
let {width,height,scale}=Dimensions.get('window') // 1
let wuli=width*scale/1000 //2
function App(): React.JSX.Element {
let [statusbarstate,setStatusbarstate]=useState(false)
let toggle=()=>{
setStatusbarstate(!statusbarstate)
}
return (
hidden={statusbarstate} backgroundColor={'pink'} //android才有效 barStyle={'light-content'} >
style={{transform:'scale(1.5)'}} trackColor={{true:'green',false:'pink'}} thumbColor={statusbarstate?'#f60':'#fff'} value={statusbarstate} onValueChange={toggle} >
)
}
const styles = StyleSheet.create({
container:{
// width:1000*wuli, //3 ui*wuli
width,
height,
backgroundColor:'skyblue',
justifyContent:'center',
alignItems:'center'
}
});
export default App;
P14 P14.14.ActivityIndicator
/**
* Sample React Native App
* https://github.com/facebook/react-native
*
* @format
*/
import React, { useState } from 'react';
import {
SafeAreaView, //安全 刘海屏
ScrollView, //滚动内容区域
StatusBar, //状态栏
StyleSheet, //样式表
View, //块 视图
Image,
TouchableOpacity,
Text,
TextInput,
FlatList,
Dimensions,
Switch,
ActivityIndicator,
Platform
} from 'react-native';
//适应所有屏幕
let {width,height,scale}=Dimensions.get('window') // 1
let wuli=width*scale/1000 //2
function App(): React.JSX.Element {
if(Platform.OS=='android'){
}else if(Platform.OS=='ios'){
}
return (
{/* 以下只在android有效 数字size */}
)
}
const styles = StyleSheet.create({
container:{
// width:1000*wuli, //3 ui*wuli
width,
height,
backgroundColor:'skyblue',
justifyContent:'center',
alignItems:'center'
}
});
export default App;
P15 P15.15.Image
Image 组件
作用
加载图片
加载方式
本地路径
图片的 URI 地址
图片的 Base64 字符串
reactnative.dev/docs/image
P16 P16.16.Textlnput
/**
* Sample React Native App
* https://github.com/facebook/react-native
*
* @format
*/
import React, { useState } from 'react';
import {
SafeAreaView, //安全 刘海屏
ScrollView, //滚动内容区域
StatusBar, //状态栏
StyleSheet, //样式表
View, //块 视图
Image,
TouchableOpacity,
Text,
TextInput,
FlatList,
Dimensions,
Switch,
ActivityIndicator,
Platform
} from 'react-native';
//适应所有屏幕
let {width,height,scale}=Dimensions.get('window') // 1
let wuli=width*scale/1000 //2
function App(): React.JSX.Element {
return (
style={styles.input} placeholder='please passwd' placeholderTextColor={'#ccc'} secureTextEntry={true} /> style={styles.input} placeholder='please tel' placeholderTextColor={'#ccc'} keyboardType='number-pad' /> style={styles.input} placeholder='please text' placeholderTextColor={'#ccc'} multiline={true} numberOfLines={5} textAlignVertical='top' /> ) } const styles = StyleSheet.create({ container:{ // width:1000*wuli, //3 ui*wuli width, height, backgroundColor:'skyblue', // justifyContent:'center', // alignItems:'center' }, input:{ width:width-20, marginHorizontal:10, borderWidth:2, borderColor:'red', backgroundColor:'#fff', paddingHorizontal:10, marginVertical:10 } }); export default App; P17 P17.17.Touchable 组件 Touchable 组件 TouchableHighlight触碰后,高亮显示 TouchableOpacity触碰后,透明度降低(模糊显示) TouchableWithoutFeedback触碰后,无任何响应 /** * Sample React Native App * https://github.com/facebook/react-native * * @format */ import React, { useState } from 'react'; import { SafeAreaView, //安全 刘海屏 ScrollView, //滚动内容区域 StatusBar, //状态栏 StyleSheet, //样式表 View, //块 视图 Image, Text, TextInput, FlatList, Dimensions, Switch, ActivityIndicator, Platform, TouchableHighlight, TouchableOpacity, TouchableWithoutFeedback } from 'react-native'; //适应所有屏幕 let {width,height,scale}=Dimensions.get('window') // 1 let wuli=width*scale/1000 //2 function App(): React.JSX.Element { return ( ) } const styles = StyleSheet.create({ container:{ // width:1000*wuli, //3 ui*wuli width, height, backgroundColor:'skyblue', // justifyContent:'center', // alignItems:'center' }, item:{ padding:20, margin:20, borderWidth:1/scale, borderColor:'red' } }); export default App; P18 P18.18.ScrollView和SafeAreaView 解决 ScrollView 在 Android 下,滚动不到底的问题 /** * Sample React Native App * https://github.com/facebook/react-native * * @format */ import React, { useState } from 'react'; import { SafeAreaView, //安全 刘海屏 ScrollView, //滚动内容区域 StatusBar, //状态栏 StyleSheet, //样式表 View, //块 视图 Image, Text, TextInput, FlatList, Dimensions, Switch, ActivityIndicator, Platform, TouchableHighlight, TouchableOpacity, TouchableWithoutFeedback } from 'react-native'; //适应所有屏幕 let {width,height,scale}=Dimensions.get('window') // 1 let wuli=width*scale/1000 //2 function App(): React.JSX.Element { return ( // 刘海屏 手机顶部 中间有摄像头 contentContainerStyle={{margin:10}} showsVerticalScrollIndicator={false} //滚动条 > info Connecting to the development server...info Starting the app on "127.0.0.1:21503"... info Starting the app on "127.0.0.1:21503"...info Starting the app on "127.0.0.1:21503"...info Starting the app on "127.0.0.1:21503"...info Starting the app on "127.0.0.1:21503"...info Starting the app on "127.0.0.1:21503"...info Starting the app on "127.0.0.1:21503"... info Starting the app on "127.0.0.1:21503"...info Starting the app on "127.0.0.1:21503"...info Starting the app on "127.0.0.1:21503"...info Starting the app on "127.0.0.1:21503"...info Starting the app on "127.0.0.1:21503"... info Starting the app on "127.0.0.1:21503"...info Starting the app on "127.0.0.1:21503"...info Starting the app on "127.0.0.1:21503"... info Starting the app on "127.0.0.1:21503"...info Starting the app on "127.0.0.1:21503"...info Starting the app on "127.0.0.1:21503"... info Starting the app on "127.0.0.1:21503"...info Starting the app on "127.0.0.1:21503"...info Starting the app on "127.0.0.1:21503"... {/* 解决 ScrollView 在 Android 下,滚动不到底的问题 */} ) } const styles = StyleSheet.create({ container:{ // width:1000*wuli, //3 ui*wuli width, height, backgroundColor:'skyblue', // justifyContent:'center', // alignItems:'center' }, item:{ padding:10, margin:20, fontSize:30 } }); export default App; P19 P19.19.SectionList SectionList 可以进行分组 import React from 'react'; import { StyleSheet, Text, View, SafeAreaView, SectionList, StatusBar, } from 'react-native'; const DATA = [ { title: 'Main dishes', data: ['Pizza', 'Burger', 'Risotto'], }, { title: 'Sides', data: ['French Fries', 'Onion Rings', 'Fried Shrimps'], }, { title: 'Drinks', data: ['Water', 'Coke', 'Beer'], }, { title: 'Desserts', data: ['Cheese Cake', 'Ice Cream'], }, ]; const App = () => ( sections={DATA} keyExtractor={(item, index) => item + index} renderItem={({item}) => ( )} renderSectionHeader={({section: {title}}) => ( )} ItemSeparatorComponent={()=>{ //声明项目之间的分隔符 return }} ListEmptyComponent={()=>{ //列表数据为空时,展示的组件 return }} //下拉刷新 refreshing={false} onRefresh={()=>alert('下拉刷新')} //上拉刷新 onEndReachedThreshold={0.1} //声明触底的比率,0.1表示距离底部还有10% onEndReached={()=>alert('to bottom')} ListHeaderComponent={()=>{ return }} ListFooterComponent={()=>{ return }} /> ); const styles = StyleSheet.create({ container: { flex: 1, paddingTop: StatusBar.currentHeight, marginHorizontal: 16, }, item: { backgroundColor: '#f9c2ff', padding: 20, marginVertical: 8, }, header: { fontSize: 32, backgroundColor: '#fff', }, title: { fontSize: 24, }, }); export default App; P20 P20.20.FlatList FlatList import React from 'react'; import { SafeAreaView, View, FlatList, StyleSheet, Text, StatusBar, } from 'react-native'; const DATA = [ { id: 'bd7acbea-c1b1-46c2-aed5-3ad53abb28ba', title: 'First Item', }, { id: '3ac68afc-c605-48d3-a4f8-fbd91aa97f63', title: 'Second Item', }, { id: '58694a0f-3da1-471f-bd96-145571e29d72', title: 'Third Item', }, ]; const Item = ({ title }) => ( ); const App = () => { return ( data={DATA} renderItem={({ item }) => keyExtractor={item => item.id} horizontal={true} initialScrollIndex={0}//初始滚动索引 initialNumToRender={1}//指定初始渲染数据的数量,一般数量要填满一屏幕 numColumns={0} //指定列数,数据项必须登高-无法支持瀑布流 inverted={true} //列表反转 // extraData={1} //设置高亮div ItemSeparatorComponent={()=>{ //声明项目之间的分隔符 return }} ListEmptyComponent={()=>{ //列表数据为空时,展示的组件 return }} //下拉刷新 refreshing={false} onRefresh={() => alert('下拉刷新')} //上拉刷新 onEndReachedThreshold={0.1} //声明触底的比率,0.1表示距离底部还有10% onEndReached={() => alert('to bottom')} ListHeaderComponent={() => { return }} ListFooterComponent={() => { return }} /> ); }; const styles = StyleSheet.create({ container: { flex: 1, marginTop: StatusBar.currentHeight || 0, }, item: { backgroundColor: '#f9c2ff', padding: 20, marginVertical: 8, marginHorizontal: 16, }, title: { fontSize: 32, }, }); export default App; P21 P21.21.Animated(上) 组件必须经过特殊处理才能用于动画 https://reactnative.cn/docs/animated RN中可以直接使用的动画组件 Animated.View Animated.Text Animated.ScrollView Animated.Image 如何创建动画(步骤) 创建初始值 Animated.Value()单个值 Animated.ValueXY()向量值 将初始值绑定的动画组件上 一般将其绑定到某个样式属性下,例如:opacity、translate 通过动画类型API,一帧一帧地更改初始值 Animated.decay()加速效果 Animated.spring()弹跳效果 Animated.timing()时间渐变效果 import React, {useRef} from 'react'; import { Animated, Text, View, StyleSheet, Button, SafeAreaView, } from 'react-native'; const App = () => { // fadeAnim will be used as the value for opacity. Initial Value: 0 const fadeAnim = useRef(new Animated.Value(0)).current; const fadeIn = () => { // Will change fadeAnim value to 1 in 5 seconds Animated.timing(fadeAnim, { toValue: 1,//变的目标值 duration: 5000, useNativeDriver: true,//启用原生 渲染 }).start(()=>{ alert('show text') }); }; const fadeOut = () => { // Will change fadeAnim value to 0 in 3 seconds Animated.timing(fadeAnim, { toValue: 0, duration: 3000, useNativeDriver: true, }).start(); }; return ( style={[ styles.fadingContainer, { // Bind opacity to animated value opacity: fadeAnim, }, ]}> ); }; const styles = StyleSheet.create({ container: { flex: 1, alignItems: 'center', justifyContent: 'center', }, fadingContainer: { padding: 20, backgroundColor: 'powderblue', }, fadingText: { fontSize: 28, }, buttonRow: { flexBasis: 100, justifyContent: 'space-evenly', marginVertical: 16, }, }); export default App; P22 P22.22.Animated(下) import React, { useEffect, useRef, useState } from 'react'; import { Animated, Text, View, StyleSheet, Button, SafeAreaView, } from 'react-native'; const App = () => { // fadeAnim will be used as the value for opacity. Initial Value: 0 const fadeAnim = useRef(new Animated.Value(0)).current; const [scan,setScan]=useState(new Animated.Value(0)) useEffect(()=>{ moveScan() },[]) const moveScan=()=>{ scan.setValue(0) Animated.timing(scan,{ toValue:99, duration:2000, useNativeDriver:true }).start(()=>{ moveScan() }) } const fadeIn = () => { // Will change fadeAnim value to 1 in 5 seconds Animated.timing(fadeAnim, { toValue: 1,//变的目标值 duration: 5000, useNativeDriver: true,//启用原生 渲染 }).start(() => { alert('show text') }); }; const fadeOut = () => { // Will change fadeAnim value to 0 in 3 seconds Animated.timing(fadeAnim, { toValue: 0, duration: 3000, useNativeDriver: true, }).start(); }; return ( style={[ styles.fadingContainer, { // Bind opacity to animated value opacity: fadeAnim, }, ]}> style={[ styles.scanBorder, { transform:[{translateY:scan}] }, ]}> ); }; const styles = StyleSheet.create({ container: { flex: 1, alignItems: 'center', justifyContent: 'center', }, fadingContainer: { padding: 20, backgroundColor: 'powderblue', }, fadingText: { fontSize: 28, }, buttonRow: { flexBasis: 100, justifyContent: 'space-evenly', marginVertical: 16, }, scan: { width:100, height:100, borderWidth:1, borderColor:'red' }, scanBorder: { borderBottomWidth:1, borderBottomColor:'red' } }); export default App; P23 P23.23.WebView 第三方组件 需要单独安装的组件 使用步骤 安装 配置 使用 第三方组件 WebView相当于内置浏览器 Picker下拉框 Swiper展示轮播效果 AsyncStorage持久化存储系统 Geolocation获取定位信息 Camera调用摄像头 WebView 安装 yarn add react-native-webview@11.0.1 配置 https://github.com/react-native-webview/react-native-webview 使用 直接指定 uri 地址 直接渲染 html 代码 example https://github.com/react-native-webview/react-native-webview/blob/master/docs/Getting-Started.md import React, { Component } from 'react'; import { WebView } from 'react-native-webview'; class App extends Component { render() { return ( // // source={{ uri: 'https://m.baidu.com' }} // style={{ marginTop: 20 }} // /> originWhitelist={['*']} source={{ html: ' /> ); } } export default App P24 P24.24.Picker Picker(下拉框) 安装 yarn add @react-native-picker/picker 配置 https://github.com/react-native-picker/picker 注意:不同版本的配置方式不同 使用 ·注意平台之间的差异(Android | ios) 问题 https://github.com/lawnstarter/react-native-picker-select/issues/402 import React, { Component } from 'react'; import { View,StyleSheet } from 'react-native'; import { Picker } from '@react-native-picker/picker'; class App extends Component { state={ color:'red' } change=(value:any)=>{ this.setState({ color:value }) } render() { return ( selectedValue={this.state.color} mode={'dropdown'} //仅在安卓有效 style={{height:50,width:150,backgroundColor:'green'}} onValueChange={(itemValue, itemIndex) =>{ this.change(itemValue) }}> ); } } const styles=StyleSheet.create({ container:{ flex:1 } }) export default App P25 P25.25.Swiper Swiper(轮播效果 安装 yarn add react-native-swiper 使用 https://github.com/leecade/react-native-swiper import React, { Component } from 'react'; import { View,StyleSheet,ScrollView,Image,Dimensions } from 'react-native'; import Swiper from 'react-native-swiper'; const {width}=Dimensions.get('window') class App extends Component { render() { return ( ); } } const styles=StyleSheet.create({ swiper:{ height:300 }, image:{ height:300, width } }) export default App P26 P26.26.AyncStorage(E) it_前端 AsyncStorage 安装 yarn add @react-native-async-storage/async-storage 配置 https://github.com/react-native-async-storage/async-storage 使用 增删改查 自动link 要重新启动 import React, { Component } from 'react'; import { View,StyleSheet,ScrollView,Image,Dimensions,Button } from 'react-native'; import AsyncStorage from '@react-native-async-storage/async-storage'; const {width}=Dimensions.get('window') class App extends Component { save=async ()=>{ try { await AsyncStorage.setItem('token','hello') } catch (error) { } } get=async()=>{ try { let token=await AsyncStorage.getItem('token') if(token!==null){ alert(token) } } catch (error) { } } render() { return ( ); } } const styles=StyleSheet.create({ }) export default App P27 P27.27.AyncStorage(下) 封装AsyncStorage增 set(key,value) 删 delete(key)I clear() 改 update(key,value) 查 get(key) 注意string 和object 三元表达式 + JSON.stringfig/parse P28 P28.28.Geolocation geolocation 级了扣k tion Geolocation一互联网 安装 yarn add@react-native-community/geolocation配置 https://github.com/react-native-geolocation/react-native-geolocation 添加获取定位信息的授权许可 使用 通过手机,获取经纬度信息 E:\code\ReactNative\app\android\app\src\main\AndroidManifest.xml 加权限 看官网 调试 https://fbflipper.com/ https://juejin.cn/post/7262554603489099833 你可以关掉hermes: hermes_enabled => false,或者手动打开localhost:8081。但是接下来还是会有很多坑。 官网 https://github.com/facebook/flipper/issues/5619 旧版 https://github.com/facebook/flipper/releases/download/v0.171.1/Flipper-win.zip https://blog.csdn.net/weixin_44339850/article/details/139768045 重要 https://blog.csdn.net/weixin_54607676/article/details/132433360 重要 import React, { Component } from 'react'; import { View,StyleSheet,ScrollView,Image,Dimensions,Button, Alert } from 'react-native'; import AsyncStorage from '@react-native-async-storage/async-storage'; import Geolocation from '@react-native-community/geolocation'; const {width}=Dimensions.get('window') class App extends Component { componentDidMount(): void { Geolocation.getCurrentPosition( info => console.log(info), error => Alert.alert('error',JSON.stringify(error)), { timeout:20000 } ); } render() { return ( ); } } const styles=StyleSheet.create({ }) export default App P29 P29.29.Camera Camera(摄像头) it_i 安装 npm install react-native-camera--save 配置 https://github.com/react-native-camera/react-native-camera 添加使用摄像头的授权许可 使用 ·拍照、扫码、人脸识别..... 上面的废弃了 新版 https://github.com/mrousavy/react-native-vision-camera https://blog.csdn.net/qq_68937887/article/details/137431607 教程 import React, { useEffect } from 'react'; import { StyleSheet, Text, View, ActivityIndicator } from 'react-native'; import { useCameraPermission, useCameraDevice, Camera } from 'react-native-vision-camera' const App = () => { const { hasPermission, requestPermission } = useCameraPermission() useEffect(() => { //判断是否拥有限权,没有就请求获取 if (!hasPermission) { requestPermission() } }, [hasPermission]) //若不获取限权或未获取,显示加载组件 if (!hasPermission) { return } //useCameraDevice获取相机所有设备(front或back)前置后置,后面其他配置官网有 //isActive相机是否处于活跃状态(布尔值),这里先写死 const device = useCameraDevice("back", { physicalDevices: ["ultra-wide-angle-camera"] }) if (!device) { //如果没有就返回 return } return ( style={[styles.abusfell]} device={device} isActive={true}> ) } const styles = StyleSheet.create({ abusfell: { flex: 1 }, test: { position: "absolute", alignSelf: "center", bottom: 10, width: 75, height: 75, backgroundColor: "red", borderRadius: 75, opacity: 0.4 } }) export default App; P30 P30.30.ImagePicker React-native-image-picker 安装 yarn add react-native-image-picker 配置 https://github.com/react-native-image-picker/react-native-image-picker 与Camera 一直 使用 调用摄像头 访问相册 新版 https://blog.csdn.net/qq564280420/article/details/115698124 import React, { useState } from 'react'; import { StyleSheet, View,Button,Image } from 'react-native'; import {launchCamera, launchImageLibrary} from 'react-native-image-picker'; let url='https://img0.baidu.com/it/u=3290604676,1127049795&fm=253&fmt=auto&app=138&f=PNG?w=500&h=616' const App = () => { let [img,setImg]=useState(url) let cramers=async()=>{ //拍照 逍遥模拟器不行 const result = await launchCamera({ mediaType: 'photo', maxWidth: 1000,// 设置选择照片的大小,设置小的话会相应的进行压缩 maxHeight: 1000, quality: 0.8, },(res)=>{ if(res.didCancel){ return false; } }); } let photo=()=>{ launchImageLibrary({ mediaType: 'photo', maxWidth: 1000,// 设置选择照片的大小,设置小的话会相应的进行压缩 maxHeight: 1000, quality: 0.8, // videoQuality: 'low', // includeBase64: true }, res=>{ if(res.didCancel){ return false; } // 对获取的图片进行处理 setImg(res.assets[0].uri) // console.log(res.assets[0].uri) }) } return ( ); } const styles = StyleSheet.create({}) export default App; P31 P31.31.自定义组件 自定义组件 互联网人 工程师自己写的组件 React 是面向组件开发的(所有内容都是组件)这里的自定义组件是指:具有特定功能的,可以重复使用的公共组件 P32 P32.32.路由与导航简介 简介 2. 基础组件 3. Stack 导航 4. BottomTab 导航 5. Drawer 导航 6. MaterialTopTab 导航 RN 中的路由是通过 React-Navigation 来完成的 React 中通过 React-Router 实现路由 RN 0.44 之前,React-Navigation 在核心中维护,0.44 之后,独立维护 本节使用 React-Navigation 5.x 版本 ·官网:https://reactnavigation.org/ 安装 yarn add @react-navigation/native yarn add react-native-reanimated react-native-gesture-handler react-native-screens react-native-safe-area-context @react-native-community/masked-view 链接 RN 0.60 后安卓环境自动链接路由(Android 无需任何操作) iOs 下需要手动链接路由(npx pod-install ios) 添加头部组件 将如下代码,放到应用的头部(例如:放到 index.js 或 App.js 文件的头部) import 'react-native-gesture-handler' 添加导航容器 我们需要在入口文件中,把整个应用,包裹在导航容器 (NavigationContainer)中(例如:在index.js或App.js文件中) expo.io 跨平台的代码 线上代码 https://reactnavigation.org/docs/5.x/getting-started P33 P33.33.StackNavigator Stack 导航 简介 RN 中默认没有类似浏览器的 history 对象 在 RN 中跳转之前,先将路由声明在 Stack 中安装 yarn add @react-navigation/stack 使用 import {createStackNavigator} from '@react-navigation/stack' const Stack = createStackNavigator() …属性 作用于整个导航(包含多个屏幕) .属性 仅仅作用于当前屏幕 Navigator 属性 initialRouteName初始化路由,即默认加载的路由 headerMode float:ios 头部效果 screen: Android 头部效果 none:不显示头部 screenOptions Screen 属性 options title headerTitleStyle headerStyle headerLeft headerRight headerTintColor yarn add @react-navigation/stack@^5.x import 'react-native-gesture-handler'; import * as React from 'react'; import { NavigationContainer } from '@react-navigation/native'; import { View } from '@ant-design/react-native'; import Index from './src_stack_navigator'; export default function App() { return ( ); } import { Text, View,StyleSheet,Button } from 'react-native' import React, { Component } from 'react' import { createStackNavigator } from '@react-navigation/stack'; function Home(props){ return ( ) } function News(props){ return ( ) } const Stack = createStackNavigator(); export default class index extends Component { render() { return ( initialRouteName='News' // headerMode={'none'} > options={{ title:'首页',headerStyle:{backgroundColor:'skyblue'}, headerRight:()=> }} name='Home' component={Home} /> ) } } const styles=StyleSheet.create({ }) https://reactnavigation.org/docs/5.x/hello-react-navigation P34 P34.34.BottomTabNavigator BottomTab 导航 安装 •yarn add@react-navigation/bottom-tabs https://reactnavigation.org/docs/5.x/bottom-tab-navigator import { Text, View,StyleSheet,Button } from 'react-native' import React, { Component } from 'react' import { createBottomTabNavigator } from '@react-navigation/bottom-tabs' function Home(props){ return ( ) } function News(props){ return ( ) } const Tab = createBottomTabNavigator() export default class index extends Component { render() { return ( screenOptions={({route})=>({ tabBarIcon:({focused,color,size})=>{ let iconName if(route.name==='Home'){ iconName="首页" }else if(route.name==='News'){ iconName="新闻" } return } })} tabBarOptions={{ activeTintColor:'skyblue', inactiveTintColor:'grey' }} > ) } } const styles=StyleSheet.create({ }) P35 P35.35.矢量图标库 React-native-vector-icons(图标组件库) 一互联 安装 npm install--save react-native-vector-icons 将图标链接到应用(环境问题较多) https://github.com/oblador/react-native-vector-icons 使用 需要到具体的图标库官网查看 例如:lonicons、FontAwesome、AntDesign 添加配置 看文档 用yarn 安装 import { Text, View,StyleSheet,Button } from 'react-native' import React, { Component } from 'react' import { createBottomTabNavigator } from '@react-navigation/bottom-tabs' import Ionicons from 'react-native-vector-icons/Ionicons' function Home(props){ return ( ) } function News(props){ return ( ) } const Tab = createBottomTabNavigator() export default class index extends Component { render() { return ( screenOptions={({route})=>({ tabBarIcon:({focused,color,size})=>{ let iconName if(route.name==='Home'){ iconName=focused?'add-circle':'add-circle-outline' }else if(route.name==='News'){ iconName=focused?'person':'person-outline' } return } })} tabBarOptions={{ activeTintColor:'skyblue', inactiveTintColor:'grey' }} > ) } } const styles=StyleSheet.create({ }) P36 P36.36.DrawerNavigator Drawer 导航 安装 npm install @react-navigation/drawer 使用 import{createDrawerNavigator}from'@react-navigation/drawer'; const Drawer = createDrawerNavigator(); 声明Drawer.Navigator 和Drawer.Screen 配置Drawer 导航 Navigator 属性 drawerPosition:菜单显示位置,left(默认)|right drawerType:菜单动画效果,front | back | slide | permanent drawerStyle:菜单样式 backgroundColor,width... drawerContentOptions:选中菜单项样式 activeTintColor:当前选中菜单字体颜色 itemStyle:所有菜单项样式 Screen属性 options title:菜单标题 drawerLabel:替代title,返回复杂的组件。{focused:boolean,color:string} drawerlcon:返回图标的函数。{focused:boolean,color:string,size:number} headerShown:是否显示 header。布尔型,默认 false 不显示 headerLeft:函数,声明 header 左侧的显示内容 headerRight:函数,声明 header 右侧的显示内容 https://reactnavigation.org/docs/5.x/drawer-navigator import { Text, View,StyleSheet,Button } from 'react-native' import React, { Component } from 'react' import { createDrawerNavigator } from '@react-navigation/drawer'; import Ionicons from 'react-native-vector-icons/Ionicons' function Home(props){ return ( ) } function News(props){ return ( ) } const Drawer = createDrawerNavigator(); export default class Index extends Component { render() { return ( initialRouteName='Home' drawerStyle={{ width:180, backgroundColor:'skyblue' }} drawerPosition='right' drawerType='slide' drawerContentOptions={{ activeTintColor:'red', itemStyle:{ marginVertical:20 } }} > options={{ title:'首页', drawerIcon:({focused,color,size})=>{ let iconName iconName=focused?'home':'home-outline' return } }} name='Home' component={Home} /> ) } } const styles=StyleSheet.create({ }) 如果不行 看看 yarn start --reset-cache 6.x https://0daybug.com/posts/3dd5863a/index.html P37 P37.37.MaterialTopTabNavigator MaterialTopTap 导航 支持滑动 安装 •yarn add@react-navigation/material-top-tabs react-native-tab-view Navigator 属性 tabBarPosition:Tab显示位置。默认 top,可以设置 bottom tabBarOptions:包含 tabBar 组件属性的对象 activeTintColor-当前菜单的标题或图标颜色。 inactiveTintColor-非当前菜单的标题或图标颜色。 showlcon-是否显示图标,默认是 false。 showLabel-是否显示文字,默认是 true tabStyle-标签样式对象。 labelStyle-标签文字样式对象。这里指定的颜色,会覆盖activeTintColor和 inactiveTintColor的值。 iconStyle-图标样式对象。 Screen 属性 options:设置 Screen 组件的对象 title-设置显示标题 tabBarlcon-设置标签图标(需要现在 Navigator 中指定 showicon:true)其值为函数,包含两个参数:{focused:boolean,color:string} focused 用来判断标签是否获取焦点,color 为当前标签的颜色tabBarLabel-设置标签文字内容(当未定义时,会使用 title)其值为函数,包含两个参数:{focused:boolean,color:string focused 用来判断标签是否获取焦点,color为当前标签的颜色 https://reactnavigation.org/docs/material-top-tab-navigator 看文档安装2段 依赖 import { Text, View,StyleSheet,Button } from 'react-native' import React, { Component } from 'react' import { createMaterialTopTabNavigator } from '@react-navigation/material-top-tabs'; import Ionicons from 'react-native-vector-icons/Ionicons' function Home(props){ return ( ) } function News(props){ return ( ) } const Tab = createMaterialTopTabNavigator(); export default class index extends Component { render() { return ( tabBarPosition='bottom' // tabBarOptions={{}} //旧版 screenOptions={{ //新版 tabBarStyle:{ borderWidth:1, borderColor:'red' }, tabBarLabelStyle:{}, tabBarActiveTintColor:'red', tabBarInactiveTintColor:'#666', tabBarShowIcon:true }} > options={{ title:'home', tabBarIcon:({focused,color})=>{ return } }}/> ) } } const styles=StyleSheet.create({ full:{ flex:1, justifyContent:'center', alignItems:'center' } }) P38 P38.38.路由嵌套 嵌套 https://reactnavigation.org/docs/nesting-navigators P39 P39.39.路由传参 传递参数 navigation.navigate(‘路由名称’,{KEY:123} 接收参数 类组件 this.props.route.params.KEY函数组件 route.params.KEY https://reactnavigation.org/docs/params import { Text, View,StyleSheet,Button } from 'react-native' import React, { Component } from 'react' import { createNativeStackNavigator } from '@react-navigation/native-stack'; function Home(props){ return ( ) } function News(props){ let {msg}=props.route.params return ( ) } const Stack = createNativeStackNavigator(); export default class index extends Component { render() { return ( > options={{ title:'首页',headerStyle:{backgroundColor:'skyblue'}, headerRight:()=> }} name='Home' component={Home} /> ) } } const styles=StyleSheet.create({ }) P40 P40.40.架构原理-现有架构 JS 线程 JS 代码的执行线程,将源码通过 Metro 打包后,传给 JS 引擎进行解析 Main 线程(UI 线程 或 原生线程) 主要负责原生渲染(Native UI)和调用原生模块(Native Modules) Shadow 线程(Layout 线程) 创建 Shadow Tree 来模拟 React 结构树(类似虚拟 DOM) 再由 Yoga 引擎将 Flexbox 等样式,解析成原生平台的布局方式 P41 P41.41.架构原理-新架构 RN重构背景 之前的版本,存在诸多性能问题受到 Flutter 等后起之秀的压力2018年6月,提出重构计划 三大改动 JavaScript 层: 支持 React 16+ 的新特征 增强 Js 静态类型检查(CodeGen) 引入JSI,允许替换不同的 JavaScript 引擎 Bridge 层: 划分成 Fabric 和 TurboModules 两部分,分别负责 UI 管理与 Native 模块 Native 层: 精简核心模块,将非核心部分拆分出去,作为社区模块,独立更新维护 CodeGen 是 FaceBook 推出的代码生成工具通过 CodeGen,自动将 Flow 或者 TypeScript 等有静态类型的 Js代码翻译成Fabric和TurboModules使用的接口文件。 加入类型约束后的作用 减少了数据类型错误 减少了数据验证的次数,提高了通信性能 JSI (JavaScript Interface) JSI 是一个用C++写成的轻量级框架。其作用主要有两个: 通过 JSI,可以实现 Js 引擎的更换 通过 JsI,可以通过 Js 直接调用 Native Js 对象可以直接获得 C++ 对象(Host Objects)引用,从而允许 Js 与 Native 的直接调用减少不必要的线程通信 省去了序列化和反序列化的成本 减轻了通信压力,提高了通信性能 优化 Bridge层 Fabric Fabric 是整个架构中的新 UI层 简化了之前渲染 Turbo Modules 通过 JsI,可以让 Js 直接调用 Native 模块,实现同步操作 实现 Native 模块按需加载,减少启动时间,提高性能 精简核心模块(Lean Core) 将 react-native 核心包进行瘦身 RN 推出多年,其核心包太过臃肿 有些包在项目中用不到,每次也要引入,造成资源浪费 非必要的包,移到社区模块,单独维护 例如:AsyncStorage、WebView等 原计划2020年第四季度重构完成,现在看来时间会延后 P42 P42.01.项目简介 1. 项目展示 2. 数据接口 3. UI 界面 4. 状态管理 5. 项目优化 P43 P43.02.申请数据接口 后端工程师 例如:Express、Koa 开发的 模拟接口(Mock API) 例如:Rap2 第三方接口 例如:和风天气 申请第三方接口 注册账号 https://id.qweather.com/#/register 和风天气 https://www.juhe.cn/register 聚合数据 创建应用并申请密钥(key) key 是调用接口的凭证 开发集成(开发文档) 请求接口的语法 返回数据的示例 申请数据接口 和风天气 城市信息搜索:https://dev.qweather.com/docs/api/geo/ 3 天预报:https://dev.qweather.com/docs/api/weather/ 生活指数:https://dev.qweather.com/docs/api/indices/ 聚合新闻 ·新闻头条:https://www.juhe.cn/docs/api/id/235 P44 P44.03.调试数据接口 接口调试工具 postman hoppscotch insomnia http://dev.qweather.com/docs/start/ https://dev.qweather.com/docs/api/weather/ P45 P45.04.调用数据接口 封装API P46 P46.05项目路由规划 UI P47 P47.06.首页(上) P48 P48.07.首页(中) P49 P49.08.首页(下) react-native-linear-gradient react-native-linear-gradient 安装 •yarn add react-native-linear-gradient 配置 https://github.com/react-native-linear-gradient/react-native-linear-gradient P50 P50.09新闻页(上) onPress(()=>{},()=>{//最新的回调}) P51 P51.10.新闻页(下) P52 P52.11.用户页(上) P53 P53.12.用户页(中)react-native-animatable react-native-animatable 安装 •yarn add react-native-animatable https://github.com/oblador/react-native-animatable ImageBackground 图片背景组件 P54 P54.13.用户页(下) P55 P55.14.Redux Redux 安装 yarn add redux yarn add react-redux yarn add redux-thunk//支持异步操作 P56 P56.15.路由鉴权 路由鉴权 用户登录 actions reducers connect 已登录,跳到首页 未登录,跳到登录页 P57 P57.16.项目优化 https://github.com/callstack/react-native-paper https://snack.expo.dev/@react-native-paper/github.com-callstack-react-native-paper:example 项目 antd ui 项目优化 使用第三方 UI 组件库 react-native-paper 添加项目logo 看视频 应用logo 在线 android https://icon.wuruihong.com/#/google_vignette 分别将上述目录,复制到 RN 项目对应的位置中 1.Android 替换android/app/src/main/res下对应的内容。 2.ios 替换ios/项目名称/Images.xcassets/AppIcon.appiconset中的内容。 修改项目名称 看视频 查资料 修改应用名称 Android 编辑 android/app/src/main/res/values/strings.xml iOS I 编辑ios/项目名称/Info.plist文件,定位到CFBundleDisplayName 项目源代码 https://github.com/yam126/reactNativeStudio.git 调式 React Native 提供了一个内置的开发者菜单,其中包含多个调试选项。您可以通过摇动设备或使用键盘快捷键访问开发者菜单: iOS 模拟器:按下 Cmd ⌘ + D(或选择 设备 > 摇动) Android 模拟器:按下 Cmd ⌘ + M(macOS)或 Ctrl + M(Windows 和 Linux) 或者,对于 Android 设备和模拟器,您可以在终端中运行 adb shell input keyevent 82。Hello world
' }}