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
<Button
onPress={()=>Alert.alert('title','content',[
{text:'no',onPress:()=>alert('no'),style:'cancel'},
{text:'ok',onPress:()=>alert('ok'),style:'default'},
{text:'cancel',onPress:()=>alert('cancel')}
])}
title='可以吗' color={'blue'}
></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 (
<View style={styles.container}>
<StatusBar
hidden={statusbarstate}
backgroundColor={'pink'} //android才有效
barStyle={'light-content'}
></StatusBar>
<Switch
style={{transform:'scale(1.5)'}}
trackColor={{true:'green',false:'pink'}}
thumbColor={statusbarstate?'#f60':'#fff'}
value={statusbarstate}
onValueChange={toggle}
></Switch>
</View>
)
}
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 (
<View style={styles.container}>
<ActivityIndicator color={'red'} size={'large'}></ActivityIndicator>
{/* 以下只在android有效 数字size */}
<ActivityIndicator color={'blue'} size={100}></ActivityIndicator>
</View>
)
}
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 (
<View style={styles.container}>
<TextInput
style={styles.input}
placeholder='please passwd'
placeholderTextColor={'#ccc'}
secureTextEntry={true}
/>
<TextInput
style={styles.input}
placeholder='please tel'
placeholderTextColor={'#ccc'}
keyboardType='number-pad'
/>
<TextInput
style={styles.input}
placeholder='please text'
placeholderTextColor={'#ccc'}
multiline={true}
numberOfLines={5}
textAlignVertical='top'
/>
</View>
)
}
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 (
<View style={styles.container}>
<TouchableHighlight onPress={()=>console.log('Hightlight')}>
<View style={styles.item}>
<Text>hello react native</Text>
</View>
</TouchableHighlight>
<TouchableOpacity onPress={()=>console.log('Opacity')}>
<View style={styles.item}>
<Text>hello react native</Text>
</View>
</TouchableOpacity>
<TouchableWithoutFeedback onPress={()=>console.log('WithoutFeedback')}>
<View style={styles.item}>
<Text>hello react native</Text>
</View>
</TouchableWithoutFeedback>
</View>
)
}
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 (
// 刘海屏 手机顶部 中间有摄像头
<SafeAreaView style={styles.container}>
<ScrollView style={{backgroundColor:'#fc0'}} horizontal={true} >
<Text style={styles.item}>vue</Text>
<Text style={styles.item}>react</Text>
<Text style={styles.item}>angular</Text>
<Text style={styles.item}>uniapp</Text>
<Text style={styles.item}>reactNative</Text>
<Text style={styles.item}>typescript</Text>
<Text style={styles.item}>umi</Text>
</ScrollView>
<ScrollView
contentContainerStyle={{margin:10}}
showsVerticalScrollIndicator={false} //滚动条
>
<Text style={styles.item}>vue 64 actionable tasks: 5 executed, 59 up-to-date
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"...
</Text>
{/* 解决 ScrollView 在 Android 下,滚动不到底的问题 */}
<View style={{height:Platform.OS==='ios'?0:100}}></View>
</ScrollView>
</SafeAreaView>
)
}
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 = () => (
<SafeAreaView style={styles.container}>
<SectionList
sections={DATA}
keyExtractor={(item, index) => item + index}
renderItem={({item}) => (
<View style={styles.item}>
<Text style={styles.title}>{item}</Text>
</View>
)}
renderSectionHeader={({section: {title}}) => (
<Text style={styles.header}>{title}</Text>
)}
ItemSeparatorComponent={()=>{
//声明项目之间的分隔符
return <View style={{borderBottomWidth:1,borderBottomColor:'red'}}></View>
}}
ListEmptyComponent={()=>{
//列表数据为空时,展示的组件
return <Text>empty</Text>
}}
//下拉刷新
refreshing={false}
onRefresh={()=>alert('下拉刷新')}
//上拉刷新
onEndReachedThreshold={0.1} //声明触底的比率,0.1表示距离底部还有10%
onEndReached={()=>alert('to bottom')}
ListHeaderComponent={()=>{
return <Text>Header</Text>
}}
ListFooterComponent={()=>{
return <Text>Footer</Text>
}}
/>
</SafeAreaView>
);
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 }) => (
<View style={styles.item}>
<Text style={styles.title}>{title}</Text>
</View>
);
const App = () => {
return (
<SafeAreaView style={styles.container}>
<FlatList
data={DATA}
renderItem={({ item }) => <Item title={item.title} />}
keyExtractor={item => item.id}
horizontal={true}
initialScrollIndex={0}//初始滚动索引
initialNumToRender={1}//指定初始渲染数据的数量,一般数量要填满一屏幕
numColumns={0} //指定列数,数据项必须登高-无法支持瀑布流
inverted={true} //列表反转
// extraData={1} //设置高亮div
ItemSeparatorComponent={()=>{
//声明项目之间的分隔符
return <View style={{borderBottomWidth:1,borderBottomColor:'red'}}></View>
}}
ListEmptyComponent={()=>{
//列表数据为空时,展示的组件
return <Text>empty</Text>
}}
//下拉刷新
refreshing={false}
onRefresh={() => alert('下拉刷新')}
//上拉刷新
onEndReachedThreshold={0.1} //声明触底的比率,0.1表示距离底部还有10%
onEndReached={() => alert('to bottom')}
ListHeaderComponent={() => {
return <Text>Header</Text>
}}
ListFooterComponent={() => {
return <Text>Footer</Text>
}}
/>
</SafeAreaView>
);
};
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 (
<SafeAreaView style={styles.container}>
<Animated.View
style={[
styles.fadingContainer,
{
// Bind opacity to animated value
opacity: fadeAnim,
},
]}>
<Text style={styles.fadingText}>Fading View!</Text>
</Animated.View>
<View style={styles.buttonRow}>
<Button title="Fade In View" onPress={fadeIn} />
<Button title="Fade Out View" onPress={fadeOut} />
</View>
</SafeAreaView>
);
};
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 (
<SafeAreaView style={styles.container}>
<Animated.View
style={[
styles.fadingContainer,
{
// Bind opacity to animated value
opacity: fadeAnim,
},
]}>
<Text style={styles.fadingText}>Fading View!</Text>
</Animated.View>
<View style={styles.buttonRow}>
<Button title="Fade In View" onPress={fadeIn} />
<Button title="Fade Out View" onPress={fadeOut} />
</View>
<View style={styles.scan}>
<Animated.View
style={[
styles.scanBorder,
{
transform:[{translateY:scan}]
},
]}>
</Animated.View>
</View>
</SafeAreaView>
);
};
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 (
// <WebView
// source={{ uri: 'https://m.baidu.com' }}
// style={{ marginTop: 20 }}
// />
<WebView
originWhitelist={['*']}
source={{ html: '<h1>Hello world</h1>' }}
/>
);
}
}
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 (
<View style={[styles.container,{backgroundColor:this.state.color}]}>
<Picker
selectedValue={this.state.color}
mode={'dropdown'} //仅在安卓有效
style={{height:50,width:150,backgroundColor:'green'}}
onValueChange={(itemValue, itemIndex) =>{
this.change(itemValue)
}}>
<Picker.Item label="red" value="red" />
<Picker.Item label="skyblue" value="skyblue" />
</Picker>
</View>
);
}
}
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 (
<ScrollView>
<Swiper showsButtons={true} autoplay={true} style={styles.swiper}>
<Image style={styles.image} source={require('./assets/img/2.png')}></Image>
<Image style={styles.image} source={require('./assets/img/3.png')}></Image>
</Swiper>
</ScrollView>
);
}
}
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 (
<ScrollView>
<Button title='save' onPress={this.save}></Button>
<Button title='get' onPress={this.get}></Button>
</ScrollView>
);
}
}
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 (
<ScrollView>
</ScrollView>
);
}
}
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 <ActivityIndicator></ActivityIndicator>
}
//useCameraDevice获取相机所有设备(front或back)前置后置,后面其他配置官网有
//isActive相机是否处于活跃状态(布尔值),这里先写死
const device = useCameraDevice("back", {
physicalDevices: ["ultra-wide-angle-camera"]
})
if (!device) {
//如果没有就返回
return <Text>Camera device not found</Text>
}
return (
<View style={{ flex: 1 }}>
<Camera
style={[styles.abusfell]}
device={device}
isActive={true}>
</Camera>
</View>
)
}
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 (
<View>
<Button title='cramers' onPress={cramers}></Button>
<Button title='photo' onPress={photo}></Button>
<Image style={{width:200,height:200}} source={{uri:img}}></Image>
</View>
);
}
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()
<Stack.Navigator
…属性
作用于整个导航(包含多个屏幕)
<Stack.Screen
.属性
仅仅作用于当前屏幕
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 (
<NavigationContainer>
<Index></Index>
</NavigationContainer>
);
}
import { Text, View,StyleSheet,Button } from 'react-native'
import React, { Component } from 'react'
import { createStackNavigator } from '@react-navigation/stack';
function Home(props){
return (
<View>
<Text>Home</Text>
<Button title='goNews' onPress={()=>props.navigation.navigate('News')}></Button>
</View>
)
}
function News(props){
return (
<View>
<Text>News</Text>
<Button title='goHome' onPress={()=>props.navigation.navigate('Home')}></Button>
</View>
)
}
const Stack = createStackNavigator();
export default class index extends Component {
render() {
return (
<Stack.Navigator
initialRouteName='News'
// headerMode={'none'}
>
<Stack.Screen
options={{
title:'首页',headerStyle:{backgroundColor:'skyblue'},
headerRight:()=><Text>share</Text>
}}
name='Home' component={Home}
/>
<Stack.Screen name='News' component={News}/>
</Stack.Navigator>
)
}
}
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 (
<View>
<Text>Home</Text>
</View>
)
}
function News(props){
return (
<View>
<Text>News</Text>
</View>
)
}
const Tab = createBottomTabNavigator()
export default class index extends Component {
render() {
return (
<Tab.Navigator
screenOptions={({route})=>({
tabBarIcon:({focused,color,size})=>{
let iconName
if(route.name==='Home'){
iconName="首页"
}else if(route.name==='News'){
iconName="新闻"
}
return <Button title={iconName} size={size} color={color} onPress={()=>{}}></Button>
}
})}
tabBarOptions={{
activeTintColor:'skyblue',
inactiveTintColor:'grey'
}}
>
<Tab.Screen name='Home' component={Home}/>
<Tab.Screen name='News' component={News}/>
</Tab.Navigator>
)
}
}
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 (
<View>
<Text>Home</Text>
</View>
)
}
function News(props){
return (
<View>
<Text>News</Text>
</View>
)
}
const Tab = createBottomTabNavigator()
export default class index extends Component {
render() {
return (
<Tab.Navigator
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 <Ionicons name={iconName} size={size} color={color} onPress={()=>{}}></Ionicons>
}
})}
tabBarOptions={{
activeTintColor:'skyblue',
inactiveTintColor:'grey'
}}
>
<Tab.Screen name='Home' component={Home}/>
<Tab.Screen name='News' component={News}/>
</Tab.Navigator>
)
}
}
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 (
<View>
<Text>Home</Text>
<Button title='open' onPress={()=>props.navigation.openDrawer()}></Button>
<Button title='toggle' onPress={()=>props.navigation.toggleDrawer()}></Button>
</View>
)
}
function News(props){
return (
<View>
<Text>News</Text>
<Button title='toggle' onPress={()=>props.navigation.toggleDrawer()}></Button>
<Button title='goHome' onPress={()=>props.navigation.navigate('Home')}></Button>
</View>
)
}
const Drawer = createDrawerNavigator();
export default class Index extends Component {
render() {
return (
<Drawer.Navigator
initialRouteName='Home'
drawerStyle={{
width:180,
backgroundColor:'skyblue'
}}
drawerPosition='right'
drawerType='slide'
drawerContentOptions={{
activeTintColor:'red',
itemStyle:{
marginVertical:20
}
}}
>
<Drawer.Screen
options={{
title:'首页',
drawerIcon:({focused,color,size})=>{
let iconName
iconName=focused?'home':'home-outline'
return <Ionicons name={iconName} size={size} color={color} onPress={()=>{}}></Ionicons>
}
}}
name='Home' component={Home}
/>
<Drawer.Screen name='News' component={News}/>
</Drawer.Navigator>
)
}
}
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 (
<View style={styles.full}>
<Text>Home</Text>
</View>
)
}
function News(props){
return (
<View style={styles.full}>
<Text>News</Text>
</View>
)
}
const Tab = createMaterialTopTabNavigator();
export default class index extends Component {
render() {
return (
<Tab.Navigator
tabBarPosition='bottom'
// tabBarOptions={{}} //旧版
screenOptions={{ //新版
tabBarStyle:{
borderWidth:1,
borderColor:'red'
},
tabBarLabelStyle:{},
tabBarActiveTintColor:'red',
tabBarInactiveTintColor:'#666',
tabBarShowIcon:true
}}
>
<Tab.Screen name='Home' component={Home}
options={{
title:'home',
tabBarIcon:({focused,color})=>{
return <Ionicons name={'home-outline'} color={color}/>
}
}}/>
<Tab.Screen name='News' component={News} options={{title:'news'}}/>
</Tab.Navigator>
)
}
}
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 (
<View>
<Text>Home</Text>
<Button title='goNews' onPress={()=>props.navigation.navigate('News',{msg:'hello world'})}></Button>
</View>
)
}
function News(props){
let {msg}=props.route.params
return (
<View>
<Text>News</Text>
<Text>{msg}</Text>
<Button title='goHome' onPress={()=>props.navigation.navigate('Home')}></Button>
</View>
)
}
const Stack = createNativeStackNavigator();
export default class index extends Component {
render() {
return (
<Stack.Navigator
>
<Stack.Screen
options={{
title:'首页',headerStyle:{backgroundColor:'skyblue'},
headerRight:()=><Text>share</Text>
}}
name='Home' component={Home}
/>
<Stack.Screen name='News' component={News}/>
</Stack.Navigator>
)
}
}
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
<resources>
<string name="app_name">app</string>
</resources>
iOS I
编辑ios/项目名称/Info.plist文件,定位到CFBundleDisplayName
<key>CFBundleDisplayName</key>
<string>KooTeam</string>
项目源代码 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
。