安装nodejs
– nodejs的版本应该>=12(推荐安装LTS版本)
– npm config set registry https://registry.npm.taobao.org
至于安卓环境大家自行百度(这里也需要用安卓环境,过于复杂就不多说了,需要使用一下Android Studio配一下安卓环境)
安装Yarn
npm install -g yarn
安装reactNative脚手架
npm install -g react-native-cli
初始化项目
使用新命令,新版react-native所有原始的"react-native"命令前面都需要添加"npx"如下:
npx react-native init Demo
如果碰到了以下情况
$ react-native init AwesomeProject
...
/usr/local/lib/node_modules/react-native-cli/index.js:302
cli.init(root, projectName);
^
TypeError: cli.init is not a function
at run (/usr/local/lib/node_modules/react-native-cli/index.js:302:7)
at createProject (/usr/local/lib/node_modules/react-native-cli/index.js:249:3)
at init (/usr/local/lib/node_modules/react-native-cli/index.js:200:5)
at Object.<anonymous> (/usr/local/lib/node_modules/react-native-cli/index.js:153:7)
at Module._compile (node:internal/modules/cjs/loader:1256:14)
at Module._extensions..js (node:internal/modules/cjs/loader:1310:10)
at Module.load (node:internal/modules/cjs/loader:1119:32)
at Module._load (node:internal/modules/cjs/loader:960:12)
at Function.executeUserEntryPoint [as runMain] (node:internal/modules/run_main:81:12)
at node:internal/main/run_main_module:23:47
使用 npm -g list 查看已安装的 react-native 库
$ npm -g list
/usr/local/lib
├── 。。。
├── react-native-cli@2.0.1
├── 。。。
卸载 react-native -cli 库
npm uninstall -g react-native-cli
npm uninstall -g react-native // 如果有,也一起卸载了
使用 npx react-native init 重新初始化项目
npx react-native init AwesomeProject
成功
cd 项目名
npm android
//本人电脑使用下面命令启动成功的
npm run android
如果运行项目以后碰到如下报错
Installing APK 'app-debug.apk' on 'BAH3-W59 - 10' for :app:debug
Installed on 1 device.
Deprecated Gradle features were used in this build, making it incompatible with Gradle 8.0.
You can use '--warning-mode all' to show the individual deprecation warnings and determine if they come from your own scripts or plugins.
See https://docs.gradle.org/7.5.1/userguide/command_line_interface.html#sec:command_line_warnings
说明Gradle版本不兼容,这里建议降低gradle的build版本,改为1.2.3
第二种方式升级你的React-Native至最新版本。(这种方式尝试过,没有测试出效果,依旧会提示)
打开 React Native 的项目, 修改Android/build.gradle 配置, 降低 gradle 的 build 为1.2.3版本.
buildscript {
repositories {
jcenter()
mavenLocal()
}
dependencies {
classpath 'com.android.tools.build:gradle:1.2.3' // 修改1.2.3
classpath 'de.undercouch:gradle-download-task:2.0.0'
// NOTE: Do not place your application dependencies here; they belong
// in the individual module build.gradle files
}
}
这个时候还是会报错,需要重新设置 Gradle 的 Wrapper , 修改为2.2版本.
Gradle version 2.2 is required. Current version is 2.14.1
修改Gradle的Wrapper版本,需要修改android/griddle/wrapper/grade-wrapper.properties文件:
distributionUrl=https://services.gradle.org/distributions/gradle-2.2-all.zip
安装完输入rnc可以快速生成RN的类组件
安装完输入rnf可以快速生成RN的函数组件
模拟器调试
– 模拟器都是安装到电脑上的,虚拟的手机界面
– 模拟器一般随着Android Studio和Xcode一起安装
– 启动应用,模拟器会随着一起启动
点击模拟器(使模拟器获取焦点)
快捷键ctrl+m
点选debug
自动跳转到浏览器上
真机调试
– 打开USB调试模式
– 通过USB线将电脑和手机连起来
– 启动应用,在手机上安装应用
查看连接状态
adb devices
出现以下情况
C:\Users\22560>adb devices
List of devices attached
127.0.0.1:5555 offline
emulator-5554 device
可以发现我们想要连接的雷电模拟器的5555端口目前没有连接,只有emulator-5554被连接了,此时我们需要关闭这个连接,让5555端口连接上,可以继续往下操作
执行端口号监控
不用特意明白下面两行代码什么意思,只需要知道执行下面两行代码可以关闭5554端口,连接上5555端口就行了
// adb -s 关闭的连接名 tcpip 指定连接的端口号
adb -s emulator-5554 tcpip 5555
// adb connect 连接的ip地址
adb connect 127.0.0.1
查看效果
C:\Users\22560>adb devices
List of devices attached
127.0.0.1:5555 device
emulator-5554 offline
如果使用的是模拟器调试的话,发现ctrl+m不能打开调试窗口的话,可以去下面的窗口打个d再返回模拟器就可以调出窗口了
StyleSheet是RN中声明样式的API
没有继承性
样式名采用小驼峰命名
所有尺寸都是没有单位
有些特殊样式名
案例代码
import React, { Component } from 'react'
// 1.导入StyleSheet(安装完上面的插件后可以通过rncs快速创建)
import { Text, View, StyleSheet } from 'react-native'
export default class index extends Component {
render () {
return (
<View>
<Text style={{ fontSize: 30 }}> textInComponent </Text>
{/* 后面的样式会覆盖前面的 */}
<Text style={[{ color: 'red' }, { color: 'blue' }]}> textInComponent </Text>
{/* 3.使用StyleSheet */}
<Text style={[styles.h1]}>Hello RN</Text>
<Text style={[styles.h2]}>Hello RN</Text>
</View>
)
}
}
const styles = StyleSheet.create({
// 2.声明StyleSheet的样式
h1:{
fontSize:40,
fontWeight: 'bold'
},
h2:{
fontSize:30,
fontWeight: 'bold'
}
})
flexDirection属性使用的示例代码
import React, { Component } from 'react'
import { Text, StyleSheet, View,ScrollView } from 'react-native'
export default class index extends Component {
render () {
return (
<View>
<Text style={[styles.h2]}> 主轴方向 </Text>
{/* View类似于div标签,只能显示固定区域内容,不可滚动,如果需要滚动需要引入scrollrow */}
<ScrollView>
<Text style={[styles.h3]}>flexDirection:'column'(默认)</Text>
<View style={[styles.container]}>
<Text style={[styles.itemBase]}>刘备</Text>
<Text style={[styles.itemBase]}>关羽</Text>
<Text style={[styles.itemBase]}>张飞</Text>
</View>
<Text style={[styles.h3]}>flexDirection:'column-reverse'</Text>
<View style={[styles.container,styles.flexColumnReverse]}>
<Text style={[styles.itemBase]}>刘备</Text>
<Text style={[styles.itemBase]}>关羽</Text>
<Text style={[styles.itemBase]}>张飞</Text>
</View>
<Text style={[styles.h3]}>flexDirection:'row'</Text>
<View style={[styles.container,styles.flecRow]}>
<Text style={[styles.itemBase]}>刘备</Text>
<Text style={[styles.itemBase]}>关羽</Text>
<Text style={[styles.itemBase]}>张飞</Text>
</View>
<Text style={[styles.h3]}>flexDirection:'row-reverse'</Text>
<View style={[styles.container,styles.flexRowReverse]}>
<Text style={[styles.itemBase]}>刘备</Text>
<Text style={[styles.itemBase]}>关羽</Text>
<Text style={[styles.itemBase]}>张飞</Text>
</View>
</ScrollView>
</View>
)
}
}
const styles = StyleSheet.create({
container: {
height: 150,
margin: 10,
borderWidth: 1,
borderColor: '#ddd'
},
h2: {
fontSize: 30,
marginHorizontal: 10
},
h3: {
fontSize: 24,
marginHorizontal: 10
},
itemBase: {
height: 30,
borderWidth: 1,
borderColor: 'red',
backgroundColor: '#dff',
padding: 2,
textAlign: 'center'
},
flexColumn:{
flexDirection: 'column',
},
flexColumnReverse:{
flexDirection: 'column-reverse',
},
flecRow:{
flexDirection: 'row',
},
flexRowReverse:{
flexDirection: 'row-reverse',
}
})
两种方式:
响应式布局案例代码
import React, { Component } from 'react'
// 引入DimenSions
import { Text, StyleSheet, View, Dimensions } from 'react-native'
// 响应式获取手机宽高
export default class index extends Component {
render () {
return (
<View style={[styles.container]}>
<View style={[styles.itemBase]}>
<Text style={[styles.h3]}> 扫一扫 </Text>
</View>
<View style={[styles.itemBase]}>
<Text style={[styles.h3]}> 付款码 </Text>
</View>
<View style={[styles.itemBase]}>
<Text style={[styles.h3]}> 卡包 </Text>
</View>
<View style={[styles.itemBase]}>
<Text style={[styles.h3]}> 出行 </Text>
</View>
</View>
)
}
}
const styles = StyleSheet.create({
container: {
flexDirection: 'row',
flexWrap: 'wrap',
},
itemBase:{
justifyContent:'center',
alignItems: 'center',
backgroundColor:'#00b38a',
width:Dimensions.get('window').width/3, //获取屏幕总宽度,除以4就是每个宽度
height:Dimensions.get('window').height/7,
borderWidth:1,
borderColor:'yellow',
// fontSize:30 //在RN没有样式继承,这个属性不会给子元素text标签,因此不会生效,只能重新给text标签加样式
},
h3:{
fontSize:30
}
})
RN中的核心组件,是对原生组件的封装
RN组件
作用 | RN组件 | 安卓视图 | ios视图 | HTML标签 |
---|---|---|---|---|
展示区块 | View | ViewGroup | UIView | div |
展示图片 | Image | ImageView | UIImageView | img |
展示文本 | Text | TextView | UITextView | p |
… | … | … | … | … |
import {
View, // 视图组件
Text, // 文本组件
Alert, //警告框组件
Button, //按钮组件
Switch, //开关组件
ActivityIndicator, //加载指示器组件
TextInput, //输入框组件
Touchable, //触碰组件(共三个)
ScrollView, //滚动视图组件
SectionList, //分组列表组件
FlatList, //高效性能列表组件
Animated, //动画组件
StatusBar, //状态栏组件
Image, //图片组件
TouchableOpacity,
Dimensions,
StyleSheet,
ImageBackground
} from 'react-native'
import React, { Component } from 'react'
import {
View, // 视图组件
Text, // 文本组件
Alert, //警告框组件
Button, //按钮组件
StyleSheet,
} from 'react-native'
export default class alert01 extends Component {
// 定义方法(这个方法里面定义两个按钮,分别为确认或者取消)
createTwoButton = () => {
Alert.alert(
'警告标题',
'警告内容',
[
{
text: '取消',
onPress: () => {
console.log('点击了取消按钮')
},
style: 'cancel'
},
{
text: '确认',
onPress: () => {
console.log('点击了确认按钮')
},
style: 'default'
}
]
)
}
// 定义三个按钮
createTwoButtonAlert = () => {
Alert.alert(
'更新提升',
'发现新版本,是否现在更新',
[
{
text: '稍后再试',
onPress: () => {
console.log('稍后提醒我')
},
style: 'destructive' //style有的手机能看到样式,有的看不到,这个可以省略
},
{
text: '取消',
onPress: () => {
console.log('点击了取消按钮')
},
style: 'cancel'
},
{
text: '确认',
onPress: () => {
console.log('点击了确认按钮')
},
style: 'default'
}
]
)
}
render () {
return (
<View style={[styles.container]}>
{/* 按钮的title属性为展示的内容,onPress为点击事件,color为按钮背景色 */}
<Button title='alart'
onPress={() => {
alert("我是一个按钮")
}} />
{/* 使用alert组件 */}
<Button title='Alert.alert' onPress={() => {
Alert.alert("我是按钮2")
}}
color={'red'}
>
</Button>
<Button title='带确认和取消的按钮' onPress={
this.createTwoButton
}
color={'blue'}
>
</Button>
<Button title='带三个按钮的' onPress={
this.createTwoButtonAlert
}
color={'tomato'}
>
</Button>
</View>
)
}
}
const styles = StyleSheet.create({
container: {
flex: 1,
justifyContent: 'space-around',
alignItems: 'center'
}
})
import React, { Component } from 'react'
import { Text, StyleSheet, View, Switch, StatusBar } from 'react-native'
export default class SwitchAndStatusBar extends Component {
// 定义一个函数,点击开关按钮控制状态条显隐
constructor() {
super()
this.state = {
hideStatusBar: false
}
}
// 通过改变这个状态触发开关的功能和状态栏显隐
toggleStatusBar = () => {
this.setState({
hideStatusBar: !this.state.hideStatusBar
})
}
render () {
return (
<View style={[styles.container]}>
{/*StatusBar: 状态条:hidden:控制状态条显隐,backgroundColor状态栏背景色(仅在安卓应用下有效),barStyle有三个值(代表状态栏图标的样式) */}
<StatusBar
hidden={this.state.hideStatusBar}
backgroundColor={'red'}
barStyle={'dark-content'}
></StatusBar>
{/* Switch:开关按钮,trackColor定义开关状态颜色,thumbColor定义小圆点颜色,value按钮状态值(默认按钮不可用,只有定义了状态通过切换状态才可以) */}
<Switch
trackColor={{
false: 'red',
true: 'green',
}}
thumbColor={'blue'}
value={this.state.hideStatusBar}
onValueChange={
this.toggleStatusBar
}
></Switch>
</View>
)
}
}
const styles = StyleSheet.create({
container: {
flex: 1,
justifyContent: 'center',
alignItems: 'center'
}
})
import React, { Component } from 'react'
// Platform平台(可以判断是安卓还是ios设备)
import { Text, StyleSheet, View, ActivityIndicator, Platform } from 'react-native'
// ActivityIndicator(加载指示器组件)
// 安卓和ios显示样式不一样(切记)
export default class ActivityIndicators extends Component {
xj () {
// 用来判断当前设备
if (Platform.OS === 'android') {
console.log('Platform',Platform);
alert('当前是安卓应用')
}
}
// 组件渲染完毕就执行
componentDidMount () {
this.xj()
}
render () {
return (
<View style={[styles.container]}>
{/* ActivityIndicator加载指示器:color:圆圈的颜色,size:圆圈尺寸(参数只有两个,也可以使用0-100数字指定大小) */}
{/*指示器默认是白色圆圈,切记看不到效果的可以加个背景色或者给指示器换个颜色就能看到了*/}
<ActivityIndicator color={'blue'} size={'small'} />
<ActivityIndicator color={'red'} size={'large'} />
{/* 数字指定大小,只能在安卓应用下起作用,ios不起作用 */}
<ActivityIndicator color={'#ccc'} size={70} />
<ActivityIndicator color={'pink'} size={100} />
</View>
)
}
}
const styles = StyleSheet.create({
container: {
flex: 1,
justifyContent: 'center',
// alignItems: 'center'
}
})
import React, { Component } from 'react'
import { Text, StyleSheet, View, Image, Dimensions } from 'react-native'
export default class image extends Component {
render () {
return (
<View style={[styles.container]}>
{/* source指定图片路径,require加载本地图片,uri加载网络图片/base64 */}
<Image style={[styles.Item1]} source={require('./1.jpg')}></Image>
<Image style={[styles.Item1]} source={{ uri: 'https://img1.bdstatic.com/static/searchdetail/img/logo-2X_2dd9a28.png' }}></Image>
<Image
style={styles.Item1}
source={{
uri: 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADMAAAAzCAYAAAA6oTAqAAAAEXRFWHRTb2Z0d2FyZQBwbmdjcnVzaEB1SfMAAABQSURBVGje7dSxCQBACARB+2/ab8BEeQNhFi6WSYzYLYudDQYGBgYGBgYGBgYGBgYGBgZmcvDqYGBgmhivGQYGBgYGBgYGBgYGBgYGBgbmQw+P/eMrC5UTVAAAAABJRU5ErkJggg==',
}}
/>
</View>
)
}
}
const styles = StyleSheet.create({
container: {
flex: 1,
justifyContent: 'center',
alignItems: 'center'
},
Item1: {
height: 200,
width: Dimensions.get('window').width,
marginVertical: 20
}
})
import React, { Component } from 'react'
import { Text, StyleSheet, View, TextInput, Dimensions, Button } from 'react-native'
export default class textInput extends Component {
// 1.通过状态获取输入框内容
constructor() {
super()
this.state = {
username: '',
password: '',
phone: ''
}
}
dologin = () => {
// 获取输入框内容
console.log(this.state.username, this.state.password, this.state.phone)
}
render () {
return (
<View style={[styles.container]}>
{/* 直接写没效果,必须先给个样式 */}
{/* 这里的value不能直接绑定修改,react为单向数据,不能双向绑定,只能通过onChangeText事件去改value的值,回调函数默认参数为输入框的值 */}
<TextInput
style={[styles.input]}
placeholder='请输入用户名'
value={this.state.username}
onChangeText={(val) => {
this.setState({
username: val
})
}}>
</TextInput>
{/* secureTextEntry代表不以明文格式显示(即密码格式) */}
<TextInput
style={[styles.input]}
placeholder='请输入密码'
value={this.state.password}
secureTextEntry={true}
onChangeText={(val) => {
this.setState({
password: val
})
}}
/>
{/* keyboardType键盘的类型,number-pad数字键盘 */}
<TextInput
style={[styles.input]}
placeholder='请输入手机号'
keyboardType='number-pad'
value={this.state.phone}
onChangeText={(val) => {
this.setState({
phone: val
})
}}
/>
{/* multiline值为true代表开启多行输入,numberOfLines限制行数为5行,textAlignVertical提示语在最顶部显示 */}
<TextInput
style={[styles.input]}
placeholder='请输入自我介绍'
multiline={true}
numberOfLines={5}
textAlignVertical='top'
/>
<View>
<Button title='登录' onPress={this.dologin}></Button>
</View>
</View>
)
}
}
const styles = StyleSheet.create({
container: {
flex: 1,
justifyContent: 'center',
alignItems: 'center'
},
input: {
width: Dimensions.get('window').width - 20,
margin: 10,
borderWidth: 1,
borderColor: 'red',
paddingHorizontal: 5
}
})
import React, { Component } from 'react'
import { Text, StyleSheet, View, TouchableHighlight, TouchableOpacity, TouchableWithoutFeedback } from 'react-native'
export default class Touchable extends Component {
render () {
return (
<View style={[styles.container]}>
<TouchableHighlight
onPress={() => alert('触碰高亮显示')}
>
<View style={[styles.Items]}>
<Text>
触碰高亮显示
</Text>
</View>
</TouchableHighlight>
<TouchableOpacity
onPress={() => alert('触碰透明度变化')}
>
<View style={[styles.Items]}>
<Text>
触碰透明度变化
</Text>
</View>
</TouchableOpacity>
<TouchableWithoutFeedback
onPress={() => alert('触碰无响应')}
>
<View style={[styles.Items]}>
<Text>
触碰无响应
</Text>
</View>
</TouchableWithoutFeedback>
</View>
)
}
}
const styles = StyleSheet.create({
container: {
flex: 1,
justifyContent: 'center',
alignItems: 'center'
},
Items: {
marginBottom: 20,
padding: 10,
borderWidth: 1,
borderColor: 'red'
}
})
当屏幕是刘海屏时,scrollview不会区分,直接显示,导致刘海屏那部分看不到效果,这时可以考虑使用安全视图SafeAreaView,这个可以自动识别是否为刘海屏,如果是的话不会在刘海屏显示,而是往下移一层
import React, { Component } from 'react'
import { Text, StyleSheet, View, ScrollView, Platform } from 'react-native'
export default class scrollView extends Component {
render () {
return (
<View>
{/* horizontal水平滚动,showsHorizontalScrollIndicator={false}隐藏水平方向滚动条 */}
<ScrollView
style={{ backgroundColor: '#dfb' }}
horizontal={true}
showsHorizontalScrollIndicator={false}
>
<Text style={[styles.nav]}>新闻</Text>
<Text style={[styles.nav]}>娱乐</Text>
<Text style={[styles.nav]}>体育</Text>
<Text style={[styles.nav]}>财经</Text>
<Text style={[styles.nav]}>军事</Text>
<Text style={[styles.nav]}>新闻</Text>
<Text style={[styles.nav]}>时尚</Text>
<Text style={[styles.nav]}>科技</Text>
</ScrollView>
{/* ScrollView属性:contentContainerStyle样式可以继承给子组件(可以对其内组件加样式),showsVerticalScrollIndicator={false}隐藏垂直方向的滚动条 */}
<ScrollView
style={[styles.scrollview]}
contentContainerStyle={{ margin: 30 }}
showsVerticalScrollIndicator={false}
>
<Text style={[styles.text]}> Lorem ipsum dolor sit amet consectetur, adipisicing elit. Amet dicta, enim molestias possimus ipsa unde labore eligendi quia omnis reiciendis similique consectetur nihil quam ab cupiditate dolores totam,
laudantium hic sunt incidunt non nemo. Quidem maiores ex error quaerat dolores molestiae magnam
fugiat laborum mollitia earum provident soluta natus iusto recusandae, optio excepturi! Laboriosam
est cumque, ea inventore molestias quaerat! Aliquid delectus vero et tempora inventore blanditiis
adipisci pariatur magnam expedita accusantium, distinctio quis? Fuga blanditiis, molestias commodi
reprehenderit dolores ipsum voluptatem, pariatur sit, consectetur impedit tempore cupiditate? Mollitia,
error veniam. Itaque porro vel rem nulla repellat. Eligendi, vitae laborum. </Text>
{/* 这里有个bug,在安卓环境scrollview显示不到最下面内容,在ios环境可以完全展示,解决方式如下 */}
<View style={{ height: Platform.OS === 'ios' ? 0 : 120 }}></View>
</ScrollView>
</View>
)
}
}
const styles = StyleSheet.create({
text: {
fontSize: 50
},
scrollview: {
backgroundColor: 'pink',
marginHorizontal: 20
},
nav: {
margin: 20,
height: 50,
fontSize: 30
}
})
import React, { Component } 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'],
},
]
class App extends Component {
constructor() {
super()
this.state = {
isFresh: false,
}
}
loaddata = () => {
this.setState({
isFresh: true
})
// 模拟请求数据
setTimeout(() => {
this.setState({
isFresh: false
})
alert('下拉刷新')
}, 3000)
}
render () {
return (
// SafeAreaView避免刘海屏
<SafeAreaView style={styles.container}>
<SectionList
// sections定义的数据,keyExtractor唯一索引,renderItem渲染项目item渲染的组件,renderSectionHeader分组的头ItemSeparatorComponent声明项目间的分隔符
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, borderBlockColor: 'red' }}></View>
}}
// 列表数据为空时候的展示组件,看这个效果需要把DATA数据先注释
ListEmptyComponent={() => {
return <Text style={{ fontSize: 30 }}>空空如也</Text>
}}
// 下拉刷新,refreshing标记刷新状态(必须添加,否则报错),值为true那么刷新小动画会一直存在onRefresh下拉事件
refreshing={this.state.isFresh}
onRefresh={this.loaddata}
// 上拉刷新(onEndReachedThreshold:设定触底比例,下面这个代表距离底部的距离就是列表的10%就触发)onEndReached上拉事件
onEndReachedThreshold={0.1}
onEndReached={() => {
alert('到底了')
}}
// 声明列表的头部组件
ListHeaderComponent={() => {
return <Text style={{ fontSize: 40 }}>头部组件</Text>
}}
// 声明列表的尾部组件
ListFooterComponent={() => {
return <Text style={{ fontSize: 40 }}>尾部组件</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
import React, { Component } from 'react'
import {
SafeAreaView,
View,
FlatList,
StyleSheet,
Text,
StatusBar,
TouchableOpacity
} from 'react-native'
export default class flatlist extends Component {
constructor() {
super()
this.state = {
isLoadding: false,
list: [
{ id: '1', title: '头条' },
{ id: '2', title: '娱乐' },
{ id: '3', title: '体育' },
{ id: '4', title: '军事' },
{ id: '5', title: '科技' },
{ id: '6', title: '财经' },
{ id: '7', title: '时尚' },
{ id: '8', title: '社会' }
],
seletedId: null
}
}
renderItem = ({ index, item }) => {
console.log('item', item)
const backgroundColor = item.id === this.state.seletedId ? '#dfb' : '#f9c2ff'
return (
<TouchableOpacity style={[styles.item, { backgroundColor }]} onPress={() => {
this.setState({
seletedId: item.id
})
}}>
<Text style={styles.title}>{item.title}{item.id}</Text>
</TouchableOpacity>
)
}
loadData = () => {
this.setState({
isLoadding: true
})
// 模拟网络请求
setTimeout(() => {
// 模拟请求数据
alert('刷新请求数据')
this.setState({
isLoadding: false
})
}, 3000)
}
render () {
return (
<SafeAreaView style={[styles.container]}>
<FlatList
data={this.state.list}
renderItem={this.renderItem}
keyExtractor={item => item.id}
// 将列表更改为水平方向 true水平/false垂直
horizontal={false}
// 指定默认置顶(默认滚动到某个位置,初始滚动索引)
initialScrollIndex={1}
// 默认先加载前四条再加载后面的(类似于懒加载,常用于第一屏默认加载)
initialNumToRender={4} //指定初始渲染数据的数量,一般数量要填满一屏幕
// 展示多列(参数为number几列),只能展示相同高度的元素,不支持瀑布流
// numColumns={3}
// 反转,数据反转显示
// inverted={true}
// 除了data数据外还有其他数据输入放到extraData
// extraData={this.state.seletedId}
ItemSeparatorComponent={() => {
// 声明项目之间的分隔符
return <View style={[styles.itemSeporetor]}></View>
}}
ListEmptyComponent={() => {
// 列表数据为空展示的组件
return <View style={{ fontSize: 30 }}>空空如也</View>
}}
// 下拉刷新
refreshing={this.state.isLoadding}
onRefresh={this.loadData}
// 上拉刷新
onEndReachedThreshold={0.01}
onEndReached={() => {
alert("到底了")
}}
// 声明列表的头部组件
ListHeaderComponent={() => {
return <Text style={{ fontSize: 40 }}>头部组件</Text>
}}
// 声明列表的尾部组件
ListFooterComponent={() => {
return <Text style={{ fontSize: 40 }}>尾部组件</Text>
}}
>
</FlatList>
</SafeAreaView>
)
}
}
const styles = StyleSheet.create({
container: {
// flex: 1,
marginTop: StatusBar.currentHeight || 0,
},
item: {
backgroundColor: '#f9c2ff',
padding: 30,
marginVertical: 8,
marginHorizontal: 16,
},
title: {
fontSize: 32,
},
})
如何创建动画
import React, { useEffect, useRef } from 'react'
import {
Animated,
Text,
View,
StyleSheet,
Button,
SafeAreaView,
} from 'react-native'
const App = () => {
// fadeAnim将用作不透明度的值。初始值:0
const fadeAnim = useRef(new Animated.Value(0)).current
const moveAnim = 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("我显示了")
])
}
const fadeOut = () => {
// Will change fadeAnim value to 0 in 3 seconds
Animated.timing(fadeAnim, {
toValue: 0,
duration: 3000,
useNativeDriver: true,
}).start(() => {
// 动画结束的回调
alert("我隐藏了")
})
}
scanMove = () => {
// 将moveAnim的初始值重新设置为0
moveAnim.setValue(0)
Animated.timing(moveAnim, {
toValue: 200,
duration: 3000,
useNativeDriver: true
}).start(() => {
scanMove()
})
}
useEffect(() => {
scanMove()
}, [])
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.scancontain]}>
<Animated.View
style={[styles.border, {
transform: [{
translateY: moveAnim
}]
}]}
>
</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,
},
scancontain: {
height: 200,
width: 200,
borderWidth: 1,
borderColor: 'red'
},
border: {
borderWidth: 1,
borderColor: 'red'
}
})
export default App
介绍一下常用的
第三方组件 | 作用 |
---|---|
WebView | 相当于内置浏览器 |
Picker | 下拉框 |
Swiper | 展示轮播效果 |
AsyncStorage | 持久化存储系统 |
Geolocation | 获取定位信息 |
Camera | 调用摄像头 |
// 直接指定uri地址
import React, { Component } from 'react';
import { WebView } from 'react-native-webview';
class MyWeb extends Component {
render() {
return (
<WebView
source={{ uri: 'https://m.baidu.com' }} //直接打开软件进百度网页
style={{ marginTop: 20 }}
/>
);
}
}
export default MyWeb
// 直接渲染html代码
import React, { Component } from 'react';
import { WebView } from 'react-native-webview';
class MyInlineWeb extends Component {
render() {
return (
<WebView
originWhitelist={['*']}
source={{ html: 'Hello world
' }}
/>
);
}
}
export default MyInlineWeb
import React, { Component } from 'react'
import { Text, StyleSheet, View } from 'react-native'
import { Picker } from '@react-native-picker/picker'
export default class picker extends Component {
constructor() {
super()
this.state = {
color: "white"
}
}
render () {
return (
<View style={[styles.container, { backgroundColor: this.state.color }]}>
<Picker
selectedValue={this.state.color}
// 如果默认显示或者选中后显示结果为"...",就给style加一下宽高,可能的原因就是没有空间显示出来
style={{ height: 100, width: 200 }}
onValueChange={(itemValue, itemIndex) => {
console.log('itemValue', itemValue)
this.setState({
color: itemValue
})
}}
>
<Picker.Item label="白色" value="white" />
<Picker.Item label="红色" value="red" />
</Picker>
</View>
)
}
}
const styles = StyleSheet.create({
container: {
flex: 1,
justifyContent: 'center',
alignItems: "center"
}
})
import React, { Component } from 'react'
import { Text, Image, StyleSheet, View, Dimensions, ScrollView } from 'react-native'
import Swiper from 'react-native-swiper'
export default class swiper extends Component {
render () {
return (
<ScrollView>
{/* 写完下面代码发现没效果是因为图片超出屏幕导致不能显示,需要将外层的view组件改成scrollview组件就可以正常显示了 */}
<Swiper
style={[styles.wrapper]}
showsButtons={true} //是否显示左右箭头
autoplay={true} //设置自动播放
>
<Image
style={[styles.slideImage]}
source={{ uri: 'https://t7.baidu.com/it/u=2168645659,3174029352&fm=193&f=GIF' }}
>
</Image>
<Image
style={[styles.slideImage]}
source={{ uri: 'https://img1.bdstatic.com/static/searchdetail/img/logo-2X_2dd9a28.png' }}
>
</Image>
<Image
style={[styles.slideImage]}
source={{ uri: 'https://tenfei02.cfp.cn/creative/vcg/800/new/VCG41N1210205351.jpg' }}
>
</Image>
</Swiper>
</ScrollView>
)
}
}
const styles = StyleSheet.create({
wrapper: {
height: 200
},
slideImage: {
height: 200,
width: Dimensions.get("window").width
}
})
import React, { Component } from 'react'
import { Text, StyleSheet, View, Button } from 'react-native'
import AsyncStorage from '@react-native-async-storage/async-storage'
export default class storage extends Component {
xj = async (value) => {
await AsyncStorage.setItem('mytest', value)
}
xj2 = async () => {
const value = await AsyncStorage.getItem('mytest')
if (value != null) {
alert(value)
}
}
render () {
return (
<View style={[styles.container]}>
{/* 存储和获取数据 */}
<Button title='存储' onPress={() => { this.xj('Hello RN1') }}> </Button>
<Button title='获取' onPress={this.xj2}> </Button>
</View>
)
}
}
const styles = StyleSheet.create({
container: {
flex: 1,
justifyContent: 'center',
alignItems: 'center',
}
})
// 安装完找到android/app/src/main/AndroidMainfest.xml,在这个文件第4行下面插入下面代码,就获取到定位权限了
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
import React, { Component } from 'react'
import { Text, StyleSheet, View } from 'react-native'
import Geolocation from '@react-native-community/geolocation'
import AsyncStorage from '@react-native-async-storage/async-storage'
export default class geolocation extends Component {
componentDidMount () {
// 如果本地存储中没有位置信息,就需要获取地理位置信息
if (AsyncStorage.getItem('coords') === undefined || AsyncStorage.getItem('coords') === '') {
// 组件加载获取地理位置信息
// getCurrentPosition的回调函数默认三个参数(成功,失败,配置项[timeout(超时时间ms),maximumAge(最大值时间),enableHighAccuracy(高精度)])
Geolocation.getCurrentPosition(
info => {
//成功回调函数,这里面就包含地理位置信息
// 获取地理位置成功后将其保存下来,避免每次打开都弹出获取信息
AsyncStorage.setItem('coords', JSON.stringify(info.coords))
},
error => console.log(error), //失败回调函数
{
timeout: 5000, //超时时间
maximumAge: 10000, //最大时间
enableHighAccuracy: true //启用高精度
}
)
}
}
render () {
return (
<View>
<Text> textInComponent </Text>
</View>
)
}
}
const styles = StyleSheet.create({})
这个Camera比较麻烦,没做笔记,所以没有代码演示了,抱歉
组件代码
import React, { Component } from 'react'
import { Text, StyleSheet, View, ActivityIndicator } from 'react-native'
export default class oneself extends Component {
render () {
return (
<View style={[styles.container]}>
<View style={[styles.loading]}>
<ActivityIndicator color={"white"}>
</ActivityIndicator>
<Text style={[styles.loadingtitle]}> 加载中... </Text>
</View>
</View>
)
}
}
const styles = StyleSheet.create({
container: {
flex: 1,
justifyContent: 'center',
alignItems: 'center'
},
loading:{
backgroundColor:'#999',
height:100,
width:150,
borderRadius:20,
padding:20
},
loadingtitle:{
textAlign:'center',
color:'white',
}
})
使用方式
import React, { Component } from 'react'
import { Text, StyleSheet, View } from 'react-native'
//导入自定义组件
import Oneself from './oneself'
export default class index extends Component {
render () {
return (
<View style={[styles.container]}>
// 使用自定义组件
<Oneself></Oneself>
</View>
)
}
}
const styles = StyleSheet.create({
container: {
flex: 1,
justifyContent: 'center',
alignItems: 'center'
},
})
简介
基础组件
安装
链接
RN 0.60后安卓环境自动链接路由(Android无需任何操作)
ios下需要手动链接路由(npx pod-install ios)
添加头部组件
添加导航容器
我们需要在入口文件中,把整个应用,包裹在导航容器(NavigationContainer)中(例如:在index.js或App.js文件中)
示例代码:
import 'react-native-gesture-handler' //这行代码本人放到了index.js里面,下面所有代码还是在App.js里面
import * as React from 'react'
import { NavigationContainer } from '@react-navigation/native'
export default function App(){
return (
<NavigationContainer>
{/*具体的应用代码*/}
</NavigationContainer>
)
}
总结以上内容
index.js
/**
* @format
*/
import 'react-native-gesture-handler';
import { AppRegistry } from 'react-native'
import App from './App'
import { name as appName } from './app.json'
AppRegistry.registerComponent(appName, () => App)
App.js
import React, { Component } from 'react'
import { NavigationContainer } from '@react-navigation/native'
import { Text, View } from 'react-native'
// 下面的注释都是练习的各部分代码片段
// import Index from './src_01_StyleSheet/index';
// import Index from './src_02_StyleSheet/index'
// import Index from './src_03_StyleSheet/index'
// import Index from './src-zujian/SwitchAndStatusBar'
// import Index from './src-zujian/ActivityIndicator'
// import Index from './src-zujian/Image'
// import Index from './src-zujian/TextInput'
// import Index from './src-zujian/Touchable'
// import Index from './src-zujian/ScrollView'
// import Index from './src-zujian/SectionList'
// import Index from './src-zujian/FlatList'
// import Index from './src-zujian/Animated'
// import Index from './src_other_zujian/picker'
// import Index from './src_other_zujian/swiper'
// import Index from './src_other_zujian/storage'
// import Index from './src_other_zujian/geolocation'
// import Index from './src-zujian/1' //自定义组件使用
// import Index from './src_router/demo01-stack'
import Index from './src_router/demo02-BottomTabs'
export default class App extends Component {
render () {
return (
<NavigationContainer>
<Index></Index>
</NavigationContainer>
)
}
}
总体来说就是
1.在终端安装
yarn add @react-navigation/native@^5.x
yarn add react-native-reanimated react-native-gesture-handler react-native-screens react-native-safe-area-context @react-native-community/masked-view
2.执行完以上命令后在index.js最上面一行加入下面这个导入命令
import 'react-native-gesture-handler'
3.最后在App.js加入以下代码
import * as React from 'react'
import { NavigationContainer } from '@react-navigation/native'
export default function App(){
return (
<NavigationContainer>
{/*具体的应用代码*/}
</NavigationContainer>
)
}
执行完以上三步,基本配置完成,可以看下面的继续学习
官网
简介
安装
使用
导航属性
Stack代码演示
import React, { Component } from 'react'
import { Text, StyleSheet, View, Button, TouchableOpacity } from 'react-native'
// 导入stack
import { createStackNavigator } from '@react-navigation/stack'
// 创建stack
const Stack = createStackNavigator()
// 创建组件
// 组件默认接收接收prop
const HomeScreen = (prop) => {
return (
<View style={[styles.container]}>
<Text style={[styles.text]}>HomeScreen</Text>
{/* 组件默认的prop内包含navigation.navigate,通过navigation.navigate可以实现导航跳转 */}
<Button title="点击跳转新闻页面" onPress={() => prop.navigation.navigate('News')}></Button>
</View>
)
}
const NewsScreen = (prop) => {
return (
<View style={[styles.container]}>
<Text style={[styles.text]}>NewsScreen</Text>
<Button title="点击跳转首页" onPress={() => prop.navigation.navigate('Home')}></Button>
</View>
)
}
export default class index extends Component {
render () {
return (
// initialRouteName代表初始化默认页面
// headerMode代表默认标题,none代表没有,float: IOS头部效果 screen: Androd头部效果
<Stack.Navigator initialRouteName='News' headerMode={'screen'}>
{/* name和component为重要必填属性,component为组件 */}
{/* 只有一个option属性,接收多个参数 */}
{/* - title 声明页面标题
- headerTitleStyle 声明标题的样式
- headerStyle 声明页头样式
- headerLeft 声明左侧内容
- headerRight 声明右侧内容(例如分享按钮)
- headerTintColor 声明标题颜色 */}
<Stack.Screen name='Home' component={HomeScreen}
options={{
title: '首页',
headerStyle: {
backgroundColor: "tomato" //标题栏背景色
},
headerRight: () => {
return (
// 这里实现右侧分享按钮
<TouchableOpacity onPress={() => { alert("Hello") }}>
<Text>分享</Text>
</TouchableOpacity>
)
}
}}
></Stack.Screen>
<Stack.Screen name='News' component={NewsScreen}></Stack.Screen>
</Stack.Navigator>
)
}
}
const styles = StyleSheet.create({
container: {
flex: 1,
justifyContent: 'center',
alignItems: 'center'
},
text: {
fontSize: 40
}
})
矢量图标库
React-native-vector-icons(图标组件库)
安装
将图标链接到应用(环境问题较多)
https://github.com/oblador/react-native-vector-icons
Android/app/build.gradle最后一行放入链接
apply from: file("../../node_modules/react-native-vector-icons/fonts.gradle")
使用
引入
需要到具体的图标库官网查看
例如:Ionicons , FontAwesome , AntDesign
示例代码
import React, { Component } from 'react'
import { Text, StyleSheet, View, Button } from 'react-native'
import { createBottomTabNavigator } from '@react-navigation/bottom-tabs'
import Ionicons from 'react-native-vector-icons/Ionicons'
// 创建组件
// 组件默认接收接收prop
const HomeScreen = (prop) => {
return (
<View style={[styles.container]}>
<Text style={[styles.text]}>HomeScreen</Text>
</View>
)
}
const NewsScreen = (prop) => {
return (
<View style={[styles.container]}>
<Text style={[styles.text]}>NewsScreen</Text>
</View>
)
}
// 创建tab
const Tab = createBottomTabNavigator()
export default class index extends Component {
render () {
return (
// screenOptions是一个回调函数,函数默认有个参数,route代表当前导航的所有信息
// tabBarIcon代表底部导航图标,也是回调函数
//默认接受的参数里面的focused:代表判断当前菜单是否处于活跃状态,即是否获取焦点,color:设置当前导航颜色,size:设置字体大小
<Tab.Navigator
screenOptions={({ route }) => {
return (
{
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}></Ionicons>
}
}
)
}}
tabBarOptions={{
activeTintColor: 'tomato', // 选中状态下的颜色
inactiveTintColor: 'gray', // 非选中状态下的颜色
}}
>
{/* name和component为必填 */}
<Tab.Screen name='Home' component={HomeScreen}></Tab.Screen>
<Tab.Screen name='News' component={NewsScreen}></Tab.Screen>
</Tab.Navigator>
)
}
}
const styles = StyleSheet.create({
container: {
flex: 1,
justifyContent: 'center',
alignItems: 'center'
},
text: {
fontSize: 40
}
})
官网
安装
使用
配置
示例代码,这里说一下,代码我没跑起来,报错了,但是代码没问题,好像跟reanimated版本有关,报错内容贴下面了,仅供参考
Error: [Reanimated] `valueUnpacker` is not a worklet, js engine: hermes
ERROR Invariant Violation: Failed to call into JavaScript module method AppRegistry.runApplication(). Module has not been registered as callable. Registered callable JavaScript modules (n = 10): Systrace, JSTimers, HeapCapture, SamplingProfiler, RCTLog, RCTDeviceEventEmitter, RCTNativeAppEventEmitter, GlobalPerformanceLogger, JSDevSupportModule, HMRClient.
A frequent cause of the error is that the application entry file path is incorrect. This can also happen when the JS bundle is corrupt or there is an early initialization error when loading React Native., js engine: hermes
import React, { Component } from 'react'
import { Text, StyleSheet, View, Button } from 'react-native'
import { createDrawerNavigator } from '@react-navigation/drawer'
import Ionicons from 'react-native-vector-icons/Ionicons'
// 创建组件
// 组件默认接收接收prop
const HomeScreen = (prop) => {
return (
<View style={[styles.container]}>
<Text style={[styles.text]}>HomeScreen</Text>
{/* 组件默认的prop内包含navigation.navigate,通过navigation.navigate可以实现导航跳转 */}
<Button title={"打开 Drawer"} onPress={() => prop.navigation.openDrawer()}></Button>
<Button title={"切换 Drawer"} onPress={() => prop.navigation.toggleDrawer()}></Button>
</View>
)
}
const NewsScreen = (prop) => {
return (
<View style={[styles.container]}>
<Text style={[styles.text]}>NewsScreen</Text>
<Button title="点击跳转首页" onPress={() => prop.navigation.navigate('Home')}></Button>
</View>
)
}
// 创建Drawer
const Drawer = createDrawerNavigator()
export default class index extends Component {
render () {
return (
<Drawer.Navigator
// 定义侧边栏样式
drawerStyle={{
width: 180,
backgroundColor: '#bfc'
}}
drawerPosition={'right'} //drawerPosition定义菜单位置
drawerType={"slide"} //滑动效果,不是覆盖了,默认的是覆盖的,permanent:一直存在
drawerContentOptions={{
activeTintColor: '#blue', //当前选中菜单的颜色
itemStyle: { //设置菜单项的样式
marginVertical: 20
}
}}
>
<Drawer.Screen options={{
title: '首页', //设置菜单标题
drawerIcon: ({ 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}></Ionicons>
}
}} name='Home' component={HomeScreen}></Drawer.Screen>
<Drawer.Screen name='News' component={NewsScreen}></Drawer.Screen>
</Drawer.Navigator>
)
}
}
const styles = StyleSheet.create({
container: {
flex: 1,
justifyContent: 'center',
alignItems: 'center'
},
text: {
fontSize: 40
}
})
官网
安装
使用
属性
具体代码演示
import React, { Component } from 'react'
import { Text, StyleSheet, View } from 'react-native'
import { createMaterialTopTabNavigator } from '@react-navigation/material-top-tabs'
import Ionicons from 'react-native-vector-icons/Ionicons'
// 创建组件
// 组件默认接收接收prop
const OrderrunpayScreen = (prop) => {
return (
<View style={[styles.container]}>
<Text style={[styles.text]}>待付款</Text>
</View>
)
}
const OrderPaidScreen = (prop) => {
return (
<View style={[styles.container]}>
<Text style={[styles.text]}>待发货</Text>
</View>
)
}
const OrderSentScreen = (prop) => {
return (
<View style={[styles.container]}>
<Text style={[styles.text]}>待收货</Text>
</View>
)
}
const OrderFinishScreen = (prop) => {
return (
<View style={[styles.container]}>
<Text style={[styles.text]}>待评价</Text>
</View>
)
}
const Tab = createMaterialTopTabNavigator()
export default class index extends Component {
render () {
return (
<Tab.Navigator
tabBarPosition="bottom"
tabBarOptions={{
tabStyle: {
borderWidth: 1,
borderColor: "red"
},
labelStyle: {
fontSize: 20
},
activeTintColor: 'red',
inactiveTintColor: "#666",
showIcon: true
}}
>
<Tab.Screen
options={{
title: '待付款',
tabBarIcon: ({ focused, color }) => {
return (
<Ionicons name='hammer-outlint' size={20} color={color} />
)
}
}}
name="OrderrunpayScreen" component={OrderrunpayScreen}></Tab.Screen>
<Tab.Screen name="OrderPaidScreen" component={OrderPaidScreen} options={{ title: '待发货' }}></Tab.Screen>
<Tab.Screen name="OrderSentScreen" component={OrderSentScreen} options={{ title: '待收获' }}></Tab.Screen>
<Tab.Screen name="OrderFinishScreen" component={OrderFinishScreen} options={{ title: '待评价' }}></Tab.Screen>
</Tab.Navigator>
)
}
}
const styles = StyleSheet.create({
container: {
flex: 1,
justifyContent: 'center',
alignItems: 'center'
},
text: {
fontSize: 40
}
})
官网: https://reactnavigation.org/docs/7.x/nesting-navigators
在一个导航内部,渲染另一个导航
实例:
代码演示
import React, { Component } from 'react'
import { Text, StyleSheet, View, Button } from 'react-native'
import { createStackNavigator } from '@react-navigation/stack'
import { createBottomTabNavigator } from '@react-navigation/bottom-tabs'
const Stack = createStackNavigator()
// 底部导航栏组件
const Tab = createBottomTabNavigator()
const FeedScreen = (prop) => {
return (
<View style={[styles.container]}>
<Text style={[styles.text]}>FeedScreen</Text>
{/* 组件默认的prop内包含navigation.navigate,通过navigation.navigate可以实现导航跳转 */}
<Button title="点击跳转Profile页面" onPress={() => prop.navigation.navigate('Profile')}></Button>
<Button title="点击跳转Settings页面" onPress={() => prop.navigation.navigate('Settings')}></Button>
</View>
)
}
const MessagesScreen = (prop) => {
return (
<View style={[styles.container]}>
<Text style={[styles.text]}>MessagesScreen</Text>
</View>
)
}
const ProfileScreen = (prop) => {
return (
<View style={[styles.container]}>
<Text style={[styles.text]}>ProfileScreen</Text>
</View>
)
}
const SettingsScreen = (prop) => {
return (
<View style={[styles.container]}>
<Text style={[styles.text]}>SettingsScreen</Text>
</View>
)
}
function Home () {
return (
<Tab.Navigator>
<Tab.Screen name="Feed" component={FeedScreen} />
<Tab.Screen name="Messages" component={MessagesScreen} />
</Tab.Navigator>
)
}
export default class index extends Component {
render () {
return (
<Stack.Navigator>
<Stack.Screen
name="Home"
component={Home}
options={{ headerShown: false }}
/>
<Stack.Screen name="Profile" component={ProfileScreen} />
<Stack.Screen name="Settings" component={SettingsScreen} />
</Stack.Navigator>
)
}
}
const styles = StyleSheet.create({
container: {
flex: 1,
justifyContent: 'center',
alignItems: 'center'
},
text: {
fontSize: 40
}
})
官网
传递参数
navigation.navigate('路由名称',{KEY:123})
接收参数
// 类组件
this.props.route.params.KEY
// 函数组件
route.params.KEY
示例代码
import React from 'react'
import { View, Text, StyleSheet, Button } from 'react-native'
import { createStackNavigator } from '@react-navigation/stack'
// 下面两个组件从官网粘贴来的
// 点击HomeScreen的按钮会传递参数
// DetailsScreen页面接收参数并显示到页面上
function HomeScreen ({ navigation }) {
return (
<View style={{ flex: 1, alignItems: 'center', justifyContent: 'center' }}>
<Text>Home Screen</Text>
<Button
title="Go to Details"
onPress={() => {
/* 1. 点击跳转并携带参数 */
navigation.navigate('Details', {
itemId: 86,
otherParam: 'anything you want here',
})
}}
/>
</View>
)
}
function DetailsScreen ({ route, navigation }) {
/* 2. route.params里面就是传递过来的参数 */
const { itemId, otherParam } = route.params
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={() =>
// 每次点击按钮都会回到详情页并随机传递一个值
navigation.push('Details', {
itemId: Math.floor(Math.random() * 100),
})
}
/>
{/* 返回Home组件 */}
<Button title="Go to Home" onPress={() => navigation.navigate('Home')} />
{/* 下面这个是返回上一层 */}
<Button title="Go back" onPress={() => navigation.goBack()} />
</View>
)
}
const Stack = createStackNavigator()
export default function index () {
return (
// 注册组件
<Stack.Navigator>
<Stack.Screen name="Home" component={HomeScreen}></Stack.Screen>
<Stack.Screen name="Details" component={DetailsScreen}></Stack.Screen>
</Stack.Navigator>
)
}
const styles = StyleSheet.create({})
这里是步骤和具体代码
先安装以上三个依赖,再按下面步骤看
user.js为使用数据的组件,其余的都是store的代码
根目录下创建src_redux
import { createStore,applyMiddleware } from "redux";
import reducers from "./reducers";
import reduxThunk from 'redux-thunk'
// 创建store,声明reducer
const store = createStore(
reducers,
// 声明中间件
applyMiddleware(reduxThunk)
)
//导出reducers
export default store
export default {
// 定义类型
COUNTER_INCREMENT: "COUNTER_INCREMENT",
COUNTER_DECREMENT: "COUNTER_DECREMENT"
}
// 引入类型
import actionTypes from './typeuitls'
// 递增
export const increment = (value) => {
return {
type: actionTypes.COUNTER_INCREMENT,
payload: value
}
}
// 递减
export const decrement = (value) => {
return {
type: actionTypes.COUNTER_DECREMENT,
payload: value
}
}
// 引入类型
import actionTypes from './typeuitls'
const initState = {
num: 2
}
// 导出是有两个参数的
export default (state = initState, action) => {
// action.payload就是reducer方法里传的参数
// 通过循环判断类型
console.log('action', action.type)
switch (action.type) {
case actionTypes.COUNTER_INCREMENT:
return {
// 这里是逻辑代码
...state,
num: state.num + action.payload
}
case actionTypes.COUNTER_DECREMENT:
return {
// 这里是逻辑代码
...state,
num: state.num - action.payload
}
default:
return state //当匹配不到值时,将数据原封不动返回
}
}
// 将多个模块合并起来
import { combineReducers } from "redux";
// 引入模块
import Counter from "./Counter";
// import home from "./home" //这里没有home.js,做下笔记,当多个组件存在时就是这样引入的
export default combineReducers({
Counter,
// home
})
import React, { Component } from 'react'
import { NavigationContainer } from '@react-navigation/native'
// 1.引入Redux
import { Provider as StoreProvider } from 'react-redux'
// 2.引入store
import store from './src_redux/store'
import { Text, View } from 'react-native'
import Index from './src_router/demo06-luyouchuancan/index'
export default class App extends Component {
render () {
return (
// 3.传递数据,就是将我们写的store数据挂载到StoreProvider的store属性上
<StoreProvider store={store}>
<NavigationContainer>
<Index></Index>
</NavigationContainer>
</StoreProvider>
)
}
}
import React, { Component } from 'react'
import { Text, StyleSheet, View, Button } from 'react-native'
// 1.导入redux
import { connect } from 'react-redux'
// 2.引入在store定义的逻辑
import { increment, decrement } from './reducers/actionTypes'
// 3.使用全局状态
const mapStateToProps = (state) => {
return {
num: state.Counter.num
}
}
class user extends Component {
render () {
return (
// 这里使用方法
<View style={[styles.container]}>
<Button title='-' onPress={() => { this.props.decrement(1) }}></Button>
<Text> {this.props.num} </Text>
<Button title='+' onPress={() => { this.props.increment(1) }}></Button>
</View>
)
}
}
// 4.将全局状态挂载并使用高阶函数形式将user包裹一下(参数一:定义的使用全局状态的函数,参数二:定义的Reducers)
export default connect(mapStateToProps, { increment, decrement })(user)
const styles = StyleSheet.create({
container: {
flex: 1,
flexDirection: 'row',
justifyContent: 'center',
alignItems: 'center'
}
})
在src_redux/reducers/typeuitls.js添加登录成功或者失败的类型
export default {
// 定义类型
COUNTER_INCREMENT: "COUNTER_INCREMENT",
COUNTER_DECREMENT: "COUNTER_DECREMENT",
// 登录成功/失败
LOGIN_SUCCESS: "LOGIN_SUCCESS",
LOGIN_FAILD: "LOGIN_FAILD"
}
后续不写了,主要就是还是写两个reducer方法,分别为登录成功或者失败,通过调用方法修改isLogin(默认为false)的值,通过判断值确定是否登录,然后在别的页面通过判断isLogin这个值使用三元运算符,如果为true就显示页面,否则不显示页面