React Native

环境搭建

选择开发平台是Windows,目标平台是Andriod

依赖:

Node(v14.8.0)、JDK(jdk-11.0.14_windows-x64_bin.exe)和 Android Studio(android-studio-2021.1.1.23-windows.exe)

搭建顺序:

  1. 安装Andriod Studio
  2. 安装Android SDK(Show Package Details)

    1. SDK PlatformsAndroid SDK Platform 30, Intel x86 Atom_64 System Image
    2. SDK ToolsAndroid SDK Build-Tools 30.0.2,NDK (Side by side)20.1.5948944
  3. 配置ANDRIOD_SDK_ROOT环境变量

    1. ANDROID_SDK_ROOTC:\Users\kevin lee\AppData\Local\Android\Sdk
    2. ANDROID_HOMEC:\Users\kevin lee\AppData\Local\Android\Sdk
  4. 添加工作目录到环境变量Path

    1. %ANDROID_SDK_ROOT%\platform-tools
    2. %ANDROID_SDK_ROOT%\emulator
    3. %ANDROID_SDK_ROOT%\tools
    4. %ANDROID_SDK_ROOT%\tools\bin
  5. 开启模拟器(AVD)

文档:https://www.react-native.cn/docs/environment-setup

项目创建

顺序:

  1. 创建项目
  2. 启动模拟器
  3. 编译并运行React Native应用

命令行:

  1. npx react-native init txclass --version 0.61

启动项目:

  1. npx react-native run-android

项目依赖

项目需要另外下载安装路由相关的依赖

  1. @react-native-community/masked-view@0.1.6 #遮罩层
  2. @react-navigation/bottom-tabs@5.0.2 #底部tab按钮
  3. @react-navigation/native@5.0.2 #路由本地主程序
  4. @react-navigation/stack@5.0.2 #点击跳转页面的栈
  5. react-native-gesture-handler@1.5.6 #路由跳转综合管理工具
  6. - 以上依赖的相关依赖 -
  7. react-native-reanimated@1.7.0 #动画
  8. react-native-safe-area-context@0.7.2 #安全区域上下文
  9. react-native-screens@2.0.0-beta.2 #屏幕相关
  10. react-native-swiper@1.5.14 #轮播图
  11. react-native-vector-icons@6.6.0 #图标
  12. - 连接原生库 -
  13. npx react-native link

package.json

  1. //测试成功 默认
  2. {
  3. "name": "txclass",
  4. "version": "0.0.1",
  5. "private": true,
  6. "scripts": {
  7. "android": "react-native run-android",
  8. "ios": "react-native run-ios",
  9. "start": "react-native start",
  10. "test": "jest",
  11. "lint": "eslint ."
  12. },
  13. "dependencies": {
  14. "@react-native-community/masked-view": "^0.1.6",
  15. "@react-native-community/toolbar-android": "^0.2.1",
  16. "@react-navigation/bottom-tabs": "^5.0.2",
  17. "@react-navigation/native": "^5.0.2",
  18. "@react-navigation/stack": "^5.0.2",
  19. "react": "17.0.2",
  20. "react-native": "0.68.0",
  21. "react-native-gesture-handler": "^1.5.6",
  22. "react-native-gradle-plugin": "0.0.6",
  23. "react-native-reanimated": "^2.7.0",
  24. "react-native-safe-area-context": "^0.7.2",
  25. "react-native-screens": "^2.0.0-beta.2",
  26. "react-native-swiper": "^1.5.14",
  27. "react-native-vector-icons": "^6.7.0",
  28. "react-native-webview": "^11.18.1"
  29. },
  30. "devDependencies": {
  31. "@babel/core": "^7.12.9",
  32. "@babel/runtime": "^7.12.5",
  33. "@react-native-community/eslint-config": "^2.0.0",
  34. "babel-jest": "^26.6.3",
  35. "eslint": "^7.32.0",
  36. "jest": "^26.6.3",
  37. "metro-react-native-babel-preset": "^0.67.0",
  38. "react-test-renderer": "17.0.2"
  39. },
  40. "jest": {
  41. "preset": "react-native"
  42. }
  43. }

核心组件

文档: https://www.react-native.cn/docs/components-and-apis

通过 React Native,您可以使用 JavaScript来访问移动平台的 API,以及使用 React组件来描述 UI的外观和行为:一系列可重用、可嵌套的代码。

React Native 还包括一组基本的,随时可用的原生组件,您可以使用它们来构建您的应用程序。这些是 React Native核心组件

视图(Views

AndroidiOS开发中,一个视图UI的基本组成部分:

  • 屏幕上的一个小矩形元素、可用于显示文本、图像或响应用户输入。
  • 甚至应用程序最小的视觉元素(例如一行文本或一个按钮)也都是各种视图。
  • 某些类型的视图可以包含其他视图。全部都是视图。

React Native 具有许多核心组件,从表单控件到活动指示器,应有尽有。主要使用以下核心组件:

REACT NATIVE UI COMPONENT ANDROID VIEW IOS VIEW WEB ANALOG 说明
<View> <ViewGroup> <UIView> A non-scrollling <div> A container that supports layout with flexbox, style, some touch handling, and accessibility controls
<Text> <TextView> <UITextView> <p> Displays, styles, and nests strings of text and even handles touch events
<Image> <ImageView> <UIImageView> <img> Displays different types of images
<ScrollView> <ScrollView> <UIScrollView> <div> A generic scrolling container that can contain multiple components and views
<TextInput> <EditText> <UITextField> <input type="text"> Allows the user to enter text

原生组件

Android开发中是使用 KotlinJava来编写视图;在 iOS开发中是使用 SwiftObjective-C 来编写视图。

React Native 中,则使用 React组件通过 JavaScript来调用这些视图。在运行时,React Native 为这些组件创建相应的 AndroidiOS视图。

由于 React Native 组件就是对原生视图的封装,因此使用 React Native 编写的应用外观、感觉和性能与其他任何原生应用一样。我们将这些平台支持的组件称为原生组件

点击跳转

TouchableNativeFeedback

在 Android 设备上,这个组件利用原生状态来渲染触摸的反馈。目前它只支持一个单独的 View 实例作为子节点。

TouchableWithoutFeedback

除非你有一个很好的理由,否则不要用这个组件。所有能够响应触屏操作的元素在触屏后都应该有一个视觉上的反馈(然而本组件没有任何视觉反馈),这也是为什么一个”web”应用总是显得不够”原生”的主要原因之一。

注意TouchableWithoutFeedback只支持一个子节点(不能没有子节点也不能多于一个)。如果你希望包含多个子组件,可以用一个 View来包装它们。

触摸屏点击事件定义:

  1. import { StyleSheet, TouchableWithoutFeedback, Text, View } from "react-native";
  2. const TouchableWithoutFeedbackExample = () => {
  3. const [count, setCount] = useState(0);
  4. const onPress = () => {
  5. setCount(count + 1);
  6. };
  7. return (
  8. <View>
  9. <View>
  10. <Text>Count: {count}</Text>
  11. </View>
  12. //嵌套组件 绑定onPress事件
  13. <TouchableWithoutFeedback onPress={onPress}>
  14. <View>
  15. <Text>Touch Here</Text>
  16. </View>
  17. </TouchableWithoutFeedback>
  18. </View>
  19. );
  20. }

刷新控制

ScrollView组件refreshControl属性里定义,函数返回的是一个刷新组件RefreshControl

  1. import {
  2. ScrollView,
  3. RefreshControl,
  4. } from 'react-native';
  5. const App = () => {
  6. const [refreshing, setRefreshing] = React.useState(false);
  7. const onRefresh = React.useCallback(() => {
  8. setRefreshing(true);
  9. }, []);
  10. return (
  11. <ScrollView
  12. refreshControl={
  13. <RefreshControl
  14. refreshing={refreshing}
  15. onRefresh={onRefresh}
  16. />
  17. }
  18. >
  19. <Text>Pull down to see RefreshControl indicator</Text>
  20. </ScrollView>
  21. );
  22. }

网页访问

WebView

创建一个原生的 WebView,可以用于访问一个网页。还可以直接嵌入 html 代码.

  1. //安装
  2. npm i -S react-native-webview
  3. //关联
  4. npx react-native link react-native-webview
  5. //安装安卓依赖android/gradle.properties and adding 2 lines:
  6. android.useAndroidX=true
  7. android.enableJetifier=true
  8. //引入
  9. import WebView from 'react-native-webview';
  10. //使用
  11. class MyWeb extends Component {
  12. render() {
  13. return (
  14. <WebView
  15. source={{uri: 'https://ke.qq.com/course/'+ courseId}}
  16. startInLoadingState={true}
  17. />
  18. );
  19. }
  20. }

APIs

样式抽象

StyleSheet

StyleSheet提供了一种类似 CSS 样式表的抽象。

  1. //写法
  2. import { StyleSheet, Text, View } from "react-native";
  3. const App = () => (
  4. <View style={styles.container}>
  5. <Text style={styles.title}>React Native</Text>
  6. </View>
  7. );
  8. const styles = StyleSheet.create({
  9. container: {
  10. flex: 1,
  11. ...
  12. },
  13. title: {
  14. marginTop: 16,
  15. ...
  16. }

从代码质量角度:

  • 从渲染函数中移除具体的样式内容,可以使代码更清晰易读。
  • 给样式命名也可以对渲染函数中的组件增加语义化的描述。

实例方法:

create():给对象创建 StyleSheet样式引用。

  1. static create(obj: object): object

compose():合并两种样式

  1. static compose(style1: object, style2: object): object | array<object>
  1. //示例
  2. const App = () => (
  3. <View style={container}>
  4. <Text style={text}>React Native</Text>
  5. </View>
  6. );
  7. const page = StyleSheet.create({
  8. container: {
  9. flex: 1,
  10. padding: 24,
  11. backgroundColor: '#fff',
  12. },
  13. text: {
  14. fontSize: 30,
  15. color: '#000'
  16. },
  17. });
  18. const lists = StyleSheet.create({
  19. listContainer: {
  20. flex: 1,
  21. backgroundColor: '#61dafb',
  22. },
  23. listItem: {
  24. fontStyle: 'italic',
  25. fontWeight: 'bold'
  26. },
  27. });
  28. const container = StyleSheet.compose(page.container, lists.listContainer);
  29. const text = StyleSheet.compose(page.text, lists.listItem);

屏幕宽高

Dimensions

本模块用于获取设备屏幕的宽高。

  1. import { Dimensions } from 'react-native';
  2. const windowWidth = Dimensions.get('window').width;
  3. const windowHeight = Dimensions.get('window').height;

动画

Animated

Animated库旨在使动画变得流畅,强大并易于构建和维护.

Animated侧重于输入和输出之间的声明性关系,以及两者之间的可配置变换,此外还提供了简单的 start/stop方法来控制基于时间的动画执行。

创建动画最基本的工作流程是先创建一个 Animated.Value ,将它连接到动画组件的一个或多个样式属性,然后使用Animated.timing()通过动画效果展示数据的变化

下面的例子演示了一个根据动画值fadeAnim来淡入淡出的视图:

  1. import { Animated } from "react-native";
  2. class AniImage extends Component{
  3. render() {
  4. const { styles, uri } = this.props;
  5. this.animatedValue = new Animated.Value(0);
  6. const imgAnimation = this.animatedValue.interpolate({
  7. //输入范围(0-100)
  8. inputRange: [0, 100],
  9. //输出范围(0-1)
  10. outputRange: [0, 1]
  11. });
  12. return (
  13. <AniImage.Image
  14. onLoadEnd={() => {
  15. Animated.timing(this.animatedValue, {
  16. //最终希望的值是100 对应的是opacity
  17. toValue: 100,
  18. //需要500毫秒完成动画
  19. duration: 500,
  20. //启用一个驱动程序兼容
  21. useNativeDriver: true
  22. }).start();
  23. }}
  24. />
  25. );
  26. }
  27. }
  28. //外部使用该组件时写法
  29. import AniImage from '../AniImage';
  30. <AniImage styles={styles.imgView} uri={data.course_img}></AniImage>

访问网络

很多移动应用都需要从远程地址中获取数据或资源。你可能需要给某个 REST API 发起 POST 请求以提交用户数据,又或者可能仅仅需要从某个服务器上获取一些静态内容。

使用Fetch

  1. fetch('https://mywebsite.com/endpoint/', {
  2. method: 'POST',
  3. headers: {
  4. Accept: 'application/json',
  5. 'Content-Type': 'application/json',
  6. //or
  7. //'Content-Type': 'application/x-www-form-urlencoded'
  8. },
  9. body: JSON.stringify({
  10. firstParam: 'yourValue',
  11. secondParam: 'yourOtherValue'
  12. })
  13. });

注意:

fetch在默认情况下,iOSAndriod会阻止所有 http的请求,以督促开发者使用 https

暂时解决办法:将localhost改为主机ip地址

导航

文档: https://reactnavigation.org/docs/5.x/getting-started

React Navigation 提供了简单易用的跨平台导航方案,在 iOSAndroid上都可以进行翻页式、tab选项卡式和抽屉式的导航布局。

Web浏览器中,您可以使用锚 ( <a>) 标签链接到不同的页面。当用户点击一个链接时,该 URL被推送到浏览器历史堆栈。当用户按下后退按钮时,浏览器会从历史堆栈顶部弹出该项目,因此活动页面现在是之前访问过的页面。React Native 没有像 Web浏览器那样内置的全局历史堆栈概念——这就是 React Navigation 进入故事的地方。

安装

  1. npm install @react-navigation/native
  2. npm install react-native-screens react-native-safe-area-context

react-native-screens包需要一个额外的配置步骤才能在 Android 设备上正常工作。编辑MainActivity.java位于android/app/src/main/java/<your package name>/MainActivity.java.

将以下代码添加到MainActivity类的主体中:

  1. @Override
  2. protected void onCreate(Bundle savedInstanceState) {
  3. super.onCreate(null);
  4. }

复制并确保在此文件顶部添加导入语句:

  1. import android.os.Bundle;

复制需要进行此更改以避免与 View状态相关的崩溃在 Activity重新启动时不一致。

需要将整个应用程序包装在NavigationContainer. 通常你会在你的入口文件中这样做,例如index.jsor App.js

  1. import * as React from 'react';
  2. import { NavigationContainer } from '@react-navigation/native';
  3. export default function App() {
  4. return (
  5. <NavigationContainer>{/* Rest of your app code */}</NavigationContainer>
  6. );
  7. }

安装本机堆栈导航器

  1. npm install @react-navigation/native-stack

创建本机堆栈导航器

createStackNavigator是一个函数,它返回一个包含 2 个属性的对象:ScreenNavigator. 它们都是用于配置导航器的 React 组件。Navigator应该包含元素作为其子元素,Screen以定义路由的配置。

NavigationContainer是一个管理我们的导航树并包含导航状态的组件。该组件必须包装所有导航器结构。通常,我们会在应用程序的根目录中渲染这个组件,该组件通常是从App.js.

  1. import { NavigationContainer } from '@react-navigation/native';
  2. import { createStackNavigator } from '@react-navigation/stack';
  3. const Stack = createStackNavigator();
  4. function App() {
  5. return (
  6. <NavigationContainer>
  7. <Stack.Navigator>
  8. <Stack.Screen name="Home" component={HomeScreen} />
  9. <Stack.Screen name="Details" component={DetailsScreen} />
  10. </Stack.Navigator>
  11. </NavigationContainer>
  12. );
  13. }

页面跳转

navigate()

  1. <Button
  2. title="Go to Details"
  3. onPress={() => navigation.navigate('Details')}
  4. />

底部标签导航

屏幕底部有一个简单的标签栏,可让您在不同的路线之间切换。路由是延迟初始化的——它们的屏幕组件在它们第一次获得焦点之前不会被挂载。

  1. //安装
  2. npm install @react-navigation/bottom-tabs
  1. //使用
  2. import { createBottomTabNavigator } from '@react-navigation/bottom-tabs';
  3. const Tab = createBottomTabNavigator();
  4. function MyTabs() {
  5. return (
  6. <Tab.Navigator>
  7. <Tab.Screen name="Home" component={HomeScreen} />
  8. <Tab.Screen name="Settings" component={SettingsScreen} />
  9. </Tab.Navigator>
  10. );
  11. }

Tab.Navigator的属性:

screenOptions:用于导航器中屏幕的默认选项。是一个函数

  1. <Tab.Navigator
  2. screenOptions={({ route }) => {
  3. tabBarIcon: () => {}
  4. }}
  5. >
  6. <Tab.Screen name="Home" component={HomeScreen} />
  7. <Tab.Screen name="Settings" component={SettingsScreen} />
  8. </Tab.Navigator>

图标

文档: https://github.com/oblador/react-native-vector-icons

使用react-native-vector-icons图标库来集成项目中使用,合适于按钮,logotabBar

  1. //安装
  2. npm install -S react-native-vector-icons@6.6.0

安卓配置:

使用 Gradle(推荐)
这种方法的优点是在构建时从这个模块中复制字体,以便字体和 JS 始终保持同步,从而使升级变得轻松。

  1. //编辑 android/app/build.gradle ( NOT android/build.gradle ) 并添加以下内容:
  2. apply from: "../../node_modules/react-native-vector-icons/fonts.gradle"
  3. //要自定义要复制的文件,请添加以下内容:
  4. project.ext.vectoricons = [
  5. iconFontNames: [ 'MaterialIcons.ttf', 'EvilIcons.ttf' ] // Name of the font files you want to copy
  6. ]
  7. apply from: "../../node_modules/react-native-vector-icons/fonts.gradle"
  1. //手动设置:
  2. //将 Fonts 文件夹中的内容复制到 android/app/src/main/assets/fonts (注意小写字体文件夹)。

使用

  1. //导入图标库
  2. import Ionicons from 'react-native-vector-icons/Ionicons';
  3. //定义底部Tab组件
  4. function BottomTab() {
  5. //呈现一个标签栏,让用户在多个屏幕之间切换
  6. const Tab = createBottomTabNavigator();
  7. return (
  8. <Tab.Navigator
  9. screenOptions={({ route }) => ({
  10. tabBarIcon: ({ focused, color, size }) => {
  11. let iconName;
  12. switch (route.name) {
  13. case '首 页':
  14. iconName = 'ios-home';
  15. break;
  16. case '列 表':
  17. iconName = 'ios-list';
  18. break;
  19. }
  20. return (
  21. <Ionicons
  22. name={iconName}
  23. size={size}
  24. color={color}
  25. />
  26. );
  27. }
  28. })}
  29. tabBarOptions={{
  30. activeTintColor: '#23b8ff',
  31. inactiveTintColor: '#999'
  32. }}
  33. >
  34. <Tab.Screen name="首 页" component={HomePage}></Tab.Screen>
  35. <Tab.Screen name="列 表" component={ListPage}></Tab.Screen>
  36. </Tab.Navigator>
  37. );
  38. }

轮播图

react-native-swiper是一个能用于做轮播效果的三方组件

文档:https://www.npmjs.com/package/react-native-swiper

  1. //安装
  2. npm i react-native-swiper@1.5.14 --save
  3. //使用
  4. import Swiper from 'react-native-swiper'
  5. const styles = StyleSheet.create({
  6. wrapper: {},
  7. slide1: {
  8. flex: 1,
  9. justifyContent: 'center',
  10. alignItems: 'center',
  11. backgroundColor: '#9DD6EB'
  12. },
  13. slide2: {
  14. ...
  15. },
  16. slide3: {
  17. ...
  18. },
  19. text: {
  20. color: '#fff',
  21. fontSize: 30,
  22. fontWeight: 'bold'
  23. }
  24. })
  25. export default class SwiperComponent extends Component {
  26. render() {
  27. return (
  28. <Swiper style={styles.wrapper} showsButtons={true}>
  29. <View style={styles.slide1}>
  30. <Text style={styles.text}>Hello Swiper</Text>
  31. </View>
  32. <View style={styles.slide2}>
  33. <Text style={styles.text}>Beautiful</Text>
  34. </View>
  35. <View style={styles.slide3}>
  36. <Text style={styles.text}>And simple</Text>
  37. </View>
  38. </Swiper>
  39. )
  40. }
  41. }

案例

案例:腾讯课堂

基于ReactNative开发的腾讯课堂移动端手机App应用

技术:

  • React Native
  • Android Studio

环境搭建:

  • Node(v14.8.0)
  • JDK(jdk-11.0.14_windows-x64_bin.exe)
  • Android Studio(android-studio-2021.1.1.23-windows.exe)

后端接口:

模拟了一个后端数据,目录在server里,进入目录终端命令npm run dev启动

  • 请求课堂(轮播图,推荐,分类,课程)(参数field)数据:/getCourseDatas
  • 请求课程分类数据:/getCourseFields
  • 请求课程列表数据:/getCourses

搭建顺序:

  1. 安装Andriod Studio
  2. 安装Android SDK(Show Package Details)

    1. SDK PlatformsAndroid SDK Platform 30, Intel x86 Atom_64 System Image
    2. SDK ToolsAndroid SDK Build-Tools 30.0.2,NDK (Side by side)20.1.5948944
  3. 配置ANDRIOD_SDK_ROOT环境变量

    1. ANDROID_SDK_ROOTC:\Users\kevin lee\AppData\Local\Android\Sdk
    2. ANDROID_HOMEC:\Users\kevin lee\AppData\Local\Android\Sdk
  4. 添加工作目录到环境变量Path

    1. %ANDROID_SDK_ROOT%\platform-tools
    2. %ANDROID_SDK_ROOT%\emulator
    3. %ANDROID_SDK_ROOT%\tools
    4. %ANDROID_SDK_ROOT%\tools\bin
  5. 开启模拟器(AVD)
  6. 终端输入命令启动项目

项目启动:

  1. npx react-native run-android

项目目录:

  1. ├─App.js - app入口文件/导入react/导入安卓Txclass组件
  2. ├─package.json
  3. ├─ios
  4. ├─android
  5. ├─andriod_app
  6. | ├─Txclass.js - APP程序/引入RN依赖/底部TAB栏组件/屏幕页面跳转
  7. | ├─utils
  8. | | ├─config.js - 配置文件/API
  9. | | ├─extension.js - 扩展函数方法集合/数据过滤/导航器跳转封装/url地址格式化
  10. | | ├─http.js - 封装请求fetch
  11. | | tools.js - 工具/获取设备屏幕宽高的对象
  12. | ├─styles
  13. | | commonStyles.js - 公共样式文件
  14. | ├─server - 后端API服务器
  15. | | ├─index.js
  16. | | ├─package.json
  17. | | ├─data
  18. | | | ├─courseDatas.json
  19. | | | ├─courseField.json
  20. | | | ├─recomCourse.json
  21. | | | swiper.json
  22. | ├─pages - 屏幕页面/数据请求/视图绑定
  23. | | ├─Detail.js - 详情页
  24. | | ├─Home.js - 首页
  25. | | List.js - 列表页
  26. | ├─models - 前端请求模型/请求函数封装
  27. | | ├─Index.js - 首页
  28. | | List.js - 列表页
  29. | ├─components - 组件集合
  30. | | ├─RecomCourseList - 推荐列表
  31. | | | ├─CourseItem.js
  32. | | | ├─index.js
  33. | | | styles.js
  34. | | ├─PageLoading - 页面切换加载图标
  35. | | | ├─index.js
  36. | | | styles.js
  37. | | ├─MyRefreshControl - 自封装的RefreshControl
  38. | | | index.js
  39. | | ├─MainTitle - 标题
  40. | | | ├─index.js
  41. | | | styles.js
  42. | | ├─Logo
  43. | | | ├─index.js
  44. | | | styles.js
  45. | | ├─ListTab - tablist
  46. | | | ├─index.js
  47. | | | ├─styles.js
  48. | | | TabItem.js
  49. | | ├─IndexSwiper - 首页轮播图
  50. | | | ├─index.js
  51. | | | ├─styles.js
  52. | | | SwiperItem.js
  53. | | ├─CourseList - 课程列表
  54. | | | ├─CourseItem.js
  55. | | | ├─index.js
  56. | | | styles.js
  57. | | ├─Content - 文本内容
  58. | | | ├─index.js
  59. | | | styles.js
  60. | | ├─AniImage - 渐入渐出的自封装动画
  61. | | | index.js
  62. | ├─assets - 静态资源文件
  63. | | ├─img
  64. | | | ├─loading.gif
  65. | | | logo.png

源码地址: https://gitee.com/kevinleeeee/rn-txclass-android-demo