React Native从入门到实战--需求分析技术分解模块设计、基于react-navigation的APP导航框架搭建、react-navigation高级应用之动态实现底部&顶部导航器

接着上一次https://www.cnblogs.com/webor2006/p/15042441.html继续开启RN学习之旅,目前RN的基础已经学得差不多了,接下来准备进入项目的综合操练环节,将前面零散的知识串起来。

需求分析技术分解模块设计:

需求背景:

先来简述一下该APP的产生背景,对于Github应该人人皆知对吧, 而它里面有一个可以查看你感兴趣编程语言中比较热的开源项目的功能,就是它:

其中“Trending”是趋势的意思,当然就是来看最近时间哪些开源项目比较火呗。

其中它可以分几个类别进行筛选,第一个是根据时间:

还可以根据语言种类:

所以这些是整个APP的主功能,要是不用跨平台技术,想要拥有Android、IOS两个相关APP,可想其开发成本是多大,所以接下来从0开始来通过编写这么一个项目来夯实咱们的RN技能。

App要具有哪些功能?

基础功能:

  • Trending的客户端
  • 能搜索Github上的项目
  • 有离线缓存

拓展功能:

  • 支持50多种编程语言
    这么多编程语言很显然需要支持订阅取消功能,来根据自己感兴趣的爱好来操作。还需要支持语言的排序功能。
  • 项目收藏
  • 项目分享
  • APP主题风格切换
  • APP统计功能

技术栈:

既然是学习,那做这个项目的目的就是为了拓展自己的RN技能,所以这里把整个APP的技术栈提前贴出来,感性的认识一下:

基础:

  • JavaScript
  • ES6/ES7/ES8/ES9
  • Node.js/NPM
  • React
  • Android
  • IOS
  • 开发工具
    1、WebStorm:用来进行RN的编写;
    2、Android Studio
    3、XCode
  • 调试
    1、chrome-devtools
    2、YellowBox/RedBox
    3、Developer Menu

布局:

  • Flexbox
  • Style/CSS 

组件:

导航:

列表:

  • FlatList
  • SectionList

图片:

第三方组件:

  • RN组件:
  • Native组件: 

自定义组件:

  • NavigationBar
  • Dialog
  • Item
  • SafeAreaViewPlus
  • ...

网络和存储:

  • AsyncStorage
  • Fetch
  • 离线缓存框架

框架:

Redux:

  • react-redux
  • redux-thunk
  • react-navigation-redux-helpers

Flux 

高级:

Native Modules:

  • 图片裁剪
  • 统计SDK
  • 分享SDK

React Native混合开发:

  • RN+Android混合开发
  • RN+IOS混合开发

全面屏适配指南:

  • IOS全面屏适配
  • Android全面屏适配

React Native更新升级: 

  • 手动更新
  • react-native-git-upgrade

打包发布/更新:

  • CodePush热更新
  • Android打包发布
  • IOS打包发布 

效果展示:

接下来提前预览一下最终成品的效果。

最热tab:

其中顶部包含一个搜索的功能:

趋势:

收藏:

我的: 

 

工程结构简览:

这里把最终工程的一个结构也提前发出来,包层次也是比较清晰的:

下面简单对其包层次进行一个说明。

action:

存放所有模块的action,至于它干嘛的,到时用到再说。 

common:

这个不用多说,通用的一些js都会往里面放。

expand:

就是本地存储相关的js都汇集于此。

model:

这里没啥好说的,每个项目都会有它。

navigator:

导航器相关的都存放在此。

page:

所有的页面存放于此,可见这个APP的页面还是不少的。

reducer:

这里面存放的都是对于Redux的处理。

res:

store:

这是为Redux所设计的。

util:

基于react-navigation的APP导航框架搭建:

欢迎页:

工程创建:

接下来则正式进入项目的实现阶段,先来创建一个RN的工程:

react-native init Github_RN --version 0.62.2

其中由于我本机的环境原因,用最新版的RN运行会有问题,所以指定了一个稍老一点的版本,具体原因可以翻阅我之前的环境搭建篇有详细的描述,创建完之后记得先在设备上运行一下确保环境是没问题。

接下来用WebStorm来打开它:

构建欢迎页:

接下来则来构建咱们的项目欢迎页:

修改APP启动的默认页:

对于默认页的配置是在这:

 

所以这里将其改为咱们自己的欢迎页既可:

此时效果如下:

加上css样式:

接下来给欢迎简单设置一下样式,让其文字居中既可,比较简单,直接贴代码:

 

此时的效果:

其中发现自己在编写css样式时,大脑里一片空白, 造成这样的原因其实很简单,一是练得少,毕竟不是自己工作中的内容,二是前端的知识不牢,所以有必要对前端的整个知识体系进行一个系统的学习,打算新建个专栏来搞定。

停留几秒进入主界面:

通常欢迎页都类似于一个广告页面,停留几秒之后则会进入到首页对吧,那在RN中如何来实现这样的功能呢?这里就需要使用到定时器了,这块在之前https://www.cnblogs.com/webor2006/p/14609259.html也学习过了:

 

而这个定时器的初始化可以放到这个方法中:

其中由于跳转页面需要用到导航器的功能,这块暂且先给个TODO,之后再来填充,不过这里还差一个小点,就是创建了timer之后,需要在页面离开时进行销毁,如下:

 

其中这两个页面的生命周期如果不太清楚的也可以翻阅https://www.cnblogs.com/webor2006/p/14609259.html

底部导航:

效果:

关于各种导航器的基础知识可以参考https://www.cnblogs.com/webor2006/p/15042441.html

实现:

安装矢量图标和导航器库:

要想构建导航器之前,先得添加依赖,这里直接从咱们之前学习导航器基础时的工程中拷过来了:

准备四个Tab页面:

为了看到效果,先提前准备四个tab切换时显示的页面,如下:

 

里面几个页面内容都很简单,都是占了个位,这里以TrendingPage为例贴一个页面,其它页面的内容只是改了个文案,就不一一贴出来了:

import React, { Component } from "react";
import { StyleSheet, Text, View } from "react-native";

export default class TrendingPage extends Component {
  render() {
    return (
      <View style={styles.container}>
        <Text style={styles.welcome}>TrendingPage</Text>
      </View>
    );
  }
}

const styles = StyleSheet.create({
  container: {
    flex: 1,
    justifyContent: "center",
    alignItems: "center",
    backgroundColor: "#F5FCFF",
  },
  welcome: {
    fontsize: 20,
    textAlign: "center",
    margin: 10,
  },
});

准备home承载页面:

对于四个tab页面的承载肯定还得有一个页面,这里就是home了,这里也是简单先新建一个:

 

创建导航器:

这里需要用到StackNavigator和SwitchNavigator,其中SwitchNavigator是由StackNavigator组成,关于这块的基础就不过多强调了,下面直接贴一下代码,模板代码:

import { createAppContainer, createSwitchNavigator } from "react-navigation";
import { createStackNavigator } from "react-navigation-stack";
import HomePage from "../page/HomePage";
import WelcomePage from "../page/WelcomePage";

const InitNavigator = createStackNavigator({
  WelcomePage: {
    screen: WelcomePage,
    navigationOptions: {
      header: null,//隐藏头部
    },
  },
});
const MainNavigator = createStackNavigator({
  HomePage: {
    screen: HomePage,
    navigationOptions: {
      header: null,//隐藏头部
    },
  },
});
export default createAppContainer(createSwitchNavigator({
  Init: InitNavigator,
  Main: MainNavigator,
}, {
  navigationOptions: {
    header: null,//隐藏头部
  },
}));

此时还需要回到index.js中来配置一下,目前咱们是写死了跳到欢迎页面了:

需改为咱们的导航器:

处理欢迎页的跳转逻辑:

目前对于欢迎页这块是不是还有一个TODO木有处理呢?

这里刚好就可以使用上导航器来跳到咱们的HomePage了,如下:

其中,传的"Main"是在创建导航器上进行配置的:

运行看一下效果:

由于之前还有其它的一些导航跳转,所以这里将跳转的细节封装到一个工具类中进行统一维护,如下:

创建首页底部导航器:

1、先显示一个Tab

接下来则来回到首页搭建底部Tab导航栏,先来定义一个Tab:

然后调用一下该函数:

运行看一下,发现在ios模拟器中报错了。。“unrecognized font family 'Material Icons'”

但是我看“whatshot”这个矢量图标在MaterialIcons源码有定义呀:

为啥会报错呢,度娘了一下https://blog.csdn.net/weixin_42565137/article/details/104470146,在这个地方加入这些内容:

再重新运行,就正常了:

2、补全其它Tab:

有了第一个tab的正确显示,其它的tab就依葫芦画瓢了:

_tabNavigator() {
    return createAppContainer(
      createBottomTabNavigator({
        PopularPage: {
          screen: PopularPage,
          navigationOptions: {
            tabBarLabel: "最热",
            tabBarIcon: ({ tintColor, focused }) => (
              <MaterialIcons
                name={"whatshot"}
                size={26}
                style={{ color: tintColor }}
              />
            ),
          },
        },
        TrendingPage: {
          screen: TrendingPage,
          navigationOptions: {
            tabBarLabel: "趋势",
            tabBarIcon: ({ tintColor, focused }) => (
              <Ionicons
                name={"md-trending-up"}
                size={26}
                style={{ color: tintColor }}
              />
            ),
          },
        },
        FavoritePage: {
          screen: FavoritePage,
          navigationOptions: {
            tabBarLabel: "收藏",
            tabBarIcon: ({ tintColor, focused }) => (
              <MaterialIcons
                name={"favorite"}
                size={26}
                style={{ color: tintColor }}
              />
            ),
          },
        },
        MyPage: {
          screen: MyPage,
          navigationOptions: {
            tabBarLabel: "我的",
            tabBarIcon: ({ tintColor, focused }) => (
              <Entypo
                name={"user"}
                size={26}
                style={{ color: tintColor }}
              />
            ),
          },
        },
      }),
    );
  }

效果如下:

顶部导航: 

效果:

也就是在最热这个TAB上实现一个顶部Tab,也比较简单。 

实现:

import React, { Component } from "react";
import { StyleSheet, Text, View } from "react-native";
import { createMaterialTopTabNavigator } from "react-navigation-tabs";
import { createAppContainer } from "react-navigation";

export default class PopularPage extends Component {
  render() {
    const TabNavigator = createAppContainer(createMaterialTopTabNavigator(
      {
        PopularTab1: {
          screen: PopularTab,
          navigationOptions: {
            title: "Tab1",
          },
        },
        PopularTab2: {
          screen: PopularTab,
          navigationOptions: {
            title: "Tab2",
          },
        },
      },
    ));
    return (
      <View style={styles.container}>
        <TabNavigator />
      </View>
    );
  }
}

class PopularTab extends Component {
  render() {
    return <View style={styles.container}>
      <Text>PopularTab</Text>
    </View>;
  }
}

const styles = StyleSheet.create({
  container: {
    flex: 1,
    justifyContent: "center",
    alignItems: "center",
    backgroundColor: "#F5FCFF",
  },
  welcome: {
    fontSize: 20,
    textAlign: "center",
    margin: 10,
  },
});

此时运行你会发现看不到效果。。其实是跟这个样式有关:

再运行:

此时修改一下css:

效果如下:

可以看到,整体导航器的使用都差不多,多多练习其实也不难。 

react-navigation高级应用之动态实现底部&顶部导航器:

动态底部导航器:

接下来将咱们的底部导航器改活,目前咱们的这种构建是不支持动态来显示导航器的个数的,另外动态的另一层含义就是像这样的界面:

这块算是比较高级的应用了,接下来一步步来进行构建。

1、将导航器的创建代码抽离:

这里将整个导航器的构建代码抽离到一个单独的js文件中,来模拟服务器动态下发tabs场景:

里面的tab数据代码:

import PopularPage from "../page/PopularPage";
import MaterialIcons from "react-native-vector-icons/MaterialIcons";
import TrendingPage from "../page/TrendingPage";
import Ionicons from "react-native-vector-icons/Ionicons";
import FavoritePage from "../page/FavoritePage";
import MyPage from "../page/MyPage";
import Entypo from "react-native-vector-icons/Entypo";

const TABS = {//在这里配置页面的路由
  PopularPage: {
    screen: PopularPage,
    navigationOptions: {
      tabBarLabel: "最热",
      tabBarIcon: ({ tintColor, focused }) => (
        <MaterialIcons
          name={"whatshot"}
          size={26}
          style={{ color: tintColor }}
        />
      ),
    },
  },
  TrendingPage: {
    screen: TrendingPage,
    navigationOptions: {
      tabBarLabel: "趋势",
      tabBarIcon: ({ tintColor, focused }) => (
        <Ionicons
          name={"md-trending-up"}
          size={26}
          style={{ color: tintColor }}
        />
      ),
    },
  },
  FavoritePage: {
    screen: FavoritePage,
    navigationOptions: {
      tabBarLabel: "收藏",
      tabBarIcon: ({ tintColor, focused }) => (
        <MaterialIcons
          name={"favorite"}
          size={26}
          style={{ color: tintColor }}
        />
      ),
    },
  },
  MyPage: {
    screen: MyPage,
    navigationOptions: {
      tabBarLabel: "我的",
      tabBarIcon: ({ tintColor, focused }) => (
        <Entypo
          name={"user"}
          size={26}
          style={{ color: tintColor }}
        />
      ),
    },
  },
};

2、引用抽离的类:

然后为了能在首页中进行这样的引用:

则需要定义组件如下:

然后此时在首页中可以这样引用了:

是不是代码瞬间变得干净多了,此时咱们就可以动态的来改变其个tab的值,比如:

小技巧:

目前咱们在运行时,是不是会看到一些烦人的黄色警告?

其实是有办法禁止显示的,如下:

也就是用“console.disableYellowBox”来进行控制。

动态修改底部导航器的主题:

接下来再来实现通过页面动态来修改底部导航栏的主题的效果,这个实现稍麻烦一点,下面一点点进行实现。

1、定制tabBarComponent:

其实实现原理就是在我们创建导航器时,可以进行这么一个配置:

也就是:

而TabBarComponent的逻辑如下:

2、页面中增加测试设置代码:

咱们在Tab页面中就可以进行BottomTabBar的样式设定了,如下:

此时你会发现,毫无效果。。这是因为咱们在渲染的时候木有对theme进行重新赋值,这样修改一下:

再运行此时就可以动态修改主题颜色了:

好,接下来在其它页面也调用一下:

此时再运行,你会发现一个问题:

看到木有,居然当前Tab的颜色木有统一。。这是为啥呢?这里需要在咱们的render()方法中打一个日志来定位:

好,你来看一下日志结果就明白了:

哦,每次选中tab时都会进行渲染,那很明显每次读取的都是当前页面所设置的主题呀,应该只有最后一次设置的主题色来进行渲染才对,所以这里做一个小小的优化,就是在设置主题时增加一个时间的参数,如下:

其它页面也雷同,这里就不一一贴代码了,然后关键是在render中需要加一个条件判断了:

 

再运行:

这样就完美了。

动态顶部导航器:

最后咱们再来对“最热”中的顶部导航进行动态化。

1、先准备tab的动态数据:

当然这些数据应该是从服务端下发的,这里先写死掉。

2、动态读取Tab数据:

所以定义一个动态生成的函数,其逻辑也不难:

其中有一个非常非常常用的知识点需要提一下,就是给组件传参:

 

然后在组件读取可以这样:

此时运行看一下效果:

3、设置tab的样式:

现在所有tab都挤到一个屏幕内了,很难看,所以接下来给tab设置一下样式:

然后应用一下这些样式:

此时运行看效果:

4、解决动态导航器跳转外部导航器的问题:

接下来解决一个问题,就是最热里面的tab页面跳转到一个详情页的问题,这里有一定的技术。

1、准备详情页面:

并配置一下这个页面的路由信息:

2、编写跳转逻辑:

由于所有的路由跳转都封装到一个工具类中,同样的,这个详情页的跳转也一样,如下:

其中有句话可能不太理解:

这是因为导航器在项目中可能会有多个,而像咱们这个场景应该是得要获取首页的导航器,也就是:

这样才能跳到详情页,所以咱们需要在HomePage页面将导航器传递到这个工具类中,如下:

其中一定要理清,为啥这个详情页属于外层导航器页面哟,由于我们的HomePage页面是嵌在动态导航器中,而详情页是在动态导航器外面创建的,当然详情页的导航器就属于动态导航器的外层喽,有点绕,多多练习就会掌握这技巧的。

3、最热顶部Tab子页面跳转详情:

接下来咱们在最热的子TAB中可以加一个按钮,如下:

此时运行:

总结:

先学到这,算是一个项目的环境搭建,不过内容也挺多的,感觉RN的学习成本还是蛮高的,唯有大练练习才能攻克它,另外这次所有的学习都是基于IOS平台来展示了,为啥木运行在Android上呢,因为,在我Android真机跑不起来了。。也不晓得是哪抽筋了,上次学习导航器都还挺正常的,所以开发RN吧,个人感觉就是一些库版本不一样可能就造成整个工程就运行不了,或者这平台能运行,另一平台又有问题之类的,当然关于库版本的问题开发任何项目都存在,像Android,一个工程如果你IDE或者sdk,或者gradle版本不一样都有可能编译结果不一样对吧,也很正常,下一次,第一就来解决这个项目在我Android机子上跑不起来的问题,学跨平台的技术,必须得要在多平台上看一下效果,这样才有跨平台的意义,所以原则上我每次学习的成果展示必须在android和ios上展示,这篇就例外了,篇幅有点长,累了,不想整了~~

posted on 2021-11-13 07:12  cexo  阅读(284)  评论(0编辑  收藏  举报

导航