Skip to content

Latest commit

 

History

History
772 lines (613 loc) · 27.6 KB

章节一.md

File metadata and controls

772 lines (613 loc) · 27.6 KB

章节一、入门

在本章中,将包含以下内容:

  • 在文本和容器上添加样式
  • 使用图片来模仿一个视频播放器
  • 创建一个切换按钮
  • 将数据项作为列表展示
  • 在视窗中添加选项卡
  • 使用 Flexbox 布局来创建个人资料页
  • 设置导航

简介

React Native 是一个快速演进的库。在过去的一年中,它在开源社区中变得非常受欢迎。每隔一周,就会有一个性能更优,组件或者设备 API 更多的新版本产出。

虽然快速演进在大部分时候都是优势,不过有时候也会成为一个缺点。有时新版本会带来一些破坏性更新,这要求我们在更新库版本时,必须非常小心。一般情况下,破坏性变更以及重大变化都会记录在发行说明中,在更新版本的时候,请务必阅读发行说明。最重要的是,我们也要确保所有在项目中的使用的第三方库必须与新版本保持一致。

在本章中,我们将学习库中最常见的组件。阅读本书的前提是已完成 React Native 官方文档入门级别的学习,这也意味着我们不会花时间在安装环境和编写 Hello World 示例上。

为了贯穿整本书的示例,我们将创建一个新的 React Native 应用程序,请确保已正确处理好你的开发环境。推荐参考 React Native 官方网站搭建环境,然后在控制台上执行如下一些命令,创建名为 AnAppName 的应用程序:

$ react-native init --verbose AnAppName # 初始化AnAppName项目
$ cd AnAppName # 进入AnAppName目录
$ react-native run-android # 启动Android开发环境
$ react-native run-ios # 启动iOS开发环境(要求Mac OS)

为文本和容器添加样式

我们有若干组件可供使用,但其中用来创建布局或其他组件的最常见和有用的组件则是容器组件和文本年组建。在这个小节中,我们将学习如何使用容器组件和文本组件,更最重要的是,我们将看到样式是如何在 React Native 中的工作的。

我们将尝试创建一个简单的音乐播放器界面;暂时,我们先不使用图标,后续我们再来添加图标。

前提

请按照介绍中的步骤进行操作,以创建一个名为 ContainersText 的应用程序。

实现

  1. 在项目根目录下创建 src 目录,用来放置我们的 JavaScript 代码。
  2. src 目录中,创建 MainApp.js 文件。
  3. MainApp.js 文件中,创建一个无状态组件,用来模仿一个简单的音乐播放器。目前,它仅能够显示歌曲名称和进度。
import React from 'react';
import { StyleSheet, Text, View } from 'react-native';
  1. 一旦我们导入了对应的依赖,我们可以继续编写组件:
const MainApp = () => {
  const name = '01 - Hey, this is my life';
  return (
    <View style={styles.container}>
      <View style={styles.innerContainer} />
      <Text style={styles.title}>
        <Text style={styles.subtitle}>Playing:</Text> {name}
      </Text>
    </View>
  );
};
  1. 至此,我们已经准备好了我们的组件。接下来我们需要通过一些样式代码来添加颜色和字体样式:
const styles = StyleSheet.create({
  container: {
    margin: 10,
    marginTop: 100,
    backgroundColor: '#e67e22',
    borderRadius: 5
  },
  innerContainer: {
    backgroundColor: '#d35400',
    height: 50,
    width: 150,
    borderTopLeftRadius: 5,
    borderBottomLeftRadius: 5
  },
  title: {
    fontSize: 18,
    fontWeight: '200',
    color: '#fff',
    position: 'absolute',
    backgroundColor: 'transparent',
    top: 12,
    left: 10
  },
  subtitle: {
    fontWeight: 'bold'
  }
});
  1. 为了在其他文件中调用该组件,我们需要将它导出导出,如下:
export default MainApp;
  1. 下一步就是将我们的新组件导入 index.ios.jsindex.android.js 中。在这两个平台,代码都如下所示:
import React, { Component } from 'react';
import { AppRegistry } from 'react-native';
import MainApp from './src/MainApp';
AppRegistry.registerComponent('ContainersText', () => MainApp);
  1. 为了在模拟器中看到程序的变化,我们需要重新加载应用。在 iOS,使用 Command + R 即可,在Android 中,需要摇晃模拟器,呼出菜单按钮,然后点击刷新。

原理分析

让我们回顾下在上一个小节中,我们做了些什么。在步骤 3~6 中,我们创建了包含样式的组件。我们继续挖掘这些步骤中的细节。

在步骤 3 中,我们引入了组件的依赖。我们会使用一个容器组件 View,如果您熟悉 Web 开发,那么可以把 View 理解为 div。可以在其他视图、文本、列表以及我们创建或者从三方库导入的自定义组件中嵌套 View

在步骤 4 中,我们定义了名为 MainApp 的组件。我们约定文件和组件应该使用相同的名称。MainApp 是不包含任何状态的无状态组件,它是一个纯函数且不支持任何生命周期函数。另外,我们定义了一个名为 name 的常量,实际应用中,这个属性应该通过 props 进行传递。在返回值中,我们用 JSX 定义了需要呈现的组件以及对样式的引用。

每个组件都有一个名为 style 的属性,这个属性用来接收我们想附加给组件的样式对象。除文本组件外,样式并不会被继承,所以,我们需要会每个组件设置样式。

在步骤 5 中,我们给组件定义了样式。可以看到,我们使用 StyleSheet API 来定义样式。如前所述,需要定义一个包含样式的对象;通过 StyleSheet API 来创建样式,有利于性能优化,因为样式将在每次渲染时被重用,而不是每次渲染时再创建一个对象。

样式对象中的属性非常简单。如果你是一个 Web 开发者,那么更容易理解这一点,它和 CSS 属性很像。但要注意,并不是完全一样。在 React Native 的样式中,有 margin padding width height borderWidth borderColor borderRadius等等,要查看所有属性,建议查阅 React Native 文档。

在步骤 7 中,我们导入了新实现的组件,并用来作为根组件来引导我们的 APP。

更多

注意步骤 5 中关于标题样式的定义。在 title 中,有一个 backgroundColor=transparent 的样式。我们注释掉这句代码,看看会发生什么:

iOS 中,文本显示了一个非预期的橙色背景。为了解决这个问题,所以需要设置背景色为透明。但问题是,为什么会出现这种情况呢?原因是在 React Native 中,使用父元素的背景来作为文本的背景进行渲染,能够改善渲染性能,因为渲染引擎不需要计算文本每个字母周围的像素,同时也会渲染得更快。

注意

请认真考虑是否有必要将文本背景设置为透明。如果组件内容更新频繁,这将会带来一些性能问题,特别是文本特别长的时候。

使用图像来模拟视频播放器

前提

请先通过 React Native CLI 程序创建一个名为 LoadingImages 的空白 App。如果您还不知道如何创建,请参考本章介绍中的说明进行操作。

实现

  1. 首先,是创建 src 文件夹,并在这个文件夹中,创建 MainApp.js 文件和用来存储图标的图片目录。我们的项目结构如图所示:

  2. MainApp.js 中,引入相关依赖:

import React from 'react';
import { StyleSheet, View, Image } from 'react-native';
  1. 通过 require 来引入需要在组件中使用到的图片。一般情况下,通过定义一个常量来保存图片,可以让我们在不同的地方使用同一个图像。有时候,我们需要重新启动 package server 来正确加载图像,特别是在 Windows 下。
const playIcon = require('./images/play.png');
const volumeIcon = require('./images/sound.png');
const hdIcon = require('./images/hd-sign.png');
const fullScreenIcon = require('./images/full-screen.png');
const remoteImage = {
  uri: 'https://s3.amazonaws.com/crysfel/public/book/new-york.jpg'
};
  1. 使用无状态组件来渲染 JSX。同时,将用到我们在前一步中申明的图片:
const MainApp = () => {
  return (
    <Image source={remoteImage} style={styles.fullscreen}>
      <View style={styles.container}>
        <Image source={playIcon} style={styles.icon} />
        <Image source={volumeIcon} style={styles.icon} />
        <View style={styles.progress}>
          <View style={styles.progressBar} />
        </View>
        <Image source={hdIcon} style={styles.icon} />
        <Image source={fullScreenIcon} style={styles.icon} />
      </View>
    </Image>
  );
};
  1. 一旦有了要呈现的元素,则需要为每个元素定义样式:
const styles = StyleSheet.create({
  fullscreen: {
    flex: 1
  },
  container: {
    position: 'absolute',
    backgroundColor: '#202020',
    borderRadius: 5,
    flexDirection: 'row',
    height: 50,
    padding: 5,
    paddingTop: 16,
    bottom: 30,
    right: 10,
    left: 10,
    borderWidth: 1,
    borderColor: '#303030'
  },
  icon: {
    tintColor: '#fff',
    height: 16,
    width: 16,
    marginLeft: 5,
    marginRight: 5
  },
  progress: {
    backgroundColor: '#000',
    borderRadius: 7,
    flex: 1,
    height: 14,
    margin: 10,
    marginTop: 2
  },
  progressBar: {
    backgroundColor: '#bf161c',
    borderRadius: 5,
    height: 10,
    margin: 2,
    width: 80
  }
});
  1. 为了使用该组件,需要先导出它。仅仅需要一行代码,如下:
export default MainApp;
  1. 最后,将我们的新组件导入到 index.ios.js 和 index.android.js 中:
import React, { Component } from 'react';
import { AppRegistry } from 'react-native';
import MainApp from './src/MainApp';
AppRegistry.registerComponent('LoadingImages', () => MainApp);
  1. 完成!只需要刷新模拟器上的 App,就可以看到如下界面:

原理分析

在步骤 2 中,我们引入了用来渲染本地文件或者是远端服务器图片的 Image 组件。

在步骤 3 中,我们引入了所有的图像。通过 require 加载所有的图像是一种很好的做法,我们仅仅需要引入一次,就可以在我们的组件中使用它们。同时,在每次渲染中,React Native 都将使用同一个图像。如果想显示来自远端的动态图像,那么就需要在每次渲染中去请求。

require 方法接受图片路径作为参数,支持相对路径。如果是远程图片,则需要通过 uri 来指向图片地址。

在步骤 4 中,定义了一个无状态组件。在该组件中,使用 remoteImage 作为背景图像。为了将该图片设置为背景,需要将其他元素定义在 Image 组件内部。正如 CSS 一样,并没有 backgroundUrl 属性。

Imagesource 属性接受一个对象来加载远程图片或图片应用。明确 require 每张图片,是非常重要的,因为当我们发布时,只要 require 的图片才会被自动加入到发布包中。所以,我们应该避免编写如下代码:

const iconName = playing ? 'pause' : 'play';
const icon = require(iconName);

上述代码的发布包中将不会包含相关图片。因此,当我们尝试访问这些图像时将会出错。反之,我们应该采用如下的代码来重构:

const pause = require('pause');
const play = require('playing');
const icon = playing ? pause : play;

这样,在打包应用程序时,将会包含这两个图片,同时,也能动态的选择展示哪个图片。

在步骤 5 中,我们定义了样式。大多数属性都是不言自明的。tintColor 可能会有点特别,这个属性是用来设置图片的颜色的。在此处的代码是将图片颜色设置为白色。我们还在后续的内容中单独讲解 flex 布局,在这里,我们只需要知道 flexDirection: 'row' 表示图标水平对齐。

在步骤 7 中,将 MainApp 导入到 iOSAndroid 的引导程序中。之后,就可以在模拟器中运行我们的 App 了。

更多

在这个配方中,我们使用了 flexbox 布局来水平排列播放器控制按钮。如果你想了解更多有关 Flexbox的内容,请查看后续 使用Flexbox创建个人资料页面。对于更高级的内容,可以阅读第二章“实现复杂的用户界面”。

创建一个切换按钮

按钮是每个 App 中不可或缺的 UI 组件。按钮可以用于导航、触发 API 调用等。在本小节中,我们将创建一个切换按钮,默认是取消选中,当用户点击时,则通过修改样式使之看起来像是被选中的。本小节中,我们将学习如何检测点击事件,使用图片作为 UI,保持按钮状态,并根据组件状态添加样式。

前提

使用 React Native CLI 创建名为 ButtonsAndEvents 的 App。在本小节内容中,会使用到一个图片,请务必下载该小节所需的图片或者随意使用您自己的图片。

实现

  1. 首先,是创建 src 文件夹来存储源码,并在这个文件夹中,创建 MainApp.js 文件和图片目录:

  2. 导入该类的依赖:

import React, { Component } from 'react';
import { StyleSheet, View, Image, Text, TouchableHighlight } from 'react-native';
const heartIcon = require('./images/plain-heart.png');
  1. 在该小节中,我们需要在按下时保持按钮的状态。因此,需要创建一个继承自 Component 的类,如下:
class MainApp extends Component {
  state = { liked: false };
  _onPressBtn = () => {
    // We will define the content on step 6
  };
  render() {
    // We will define the content on step 4
  }
}
  1. render 中,定义组建的内容。此处,需要定义一个图片按钮和一个文本:
render() {
  return (
  <View style={styles.container}>
    <TouchableHighlight
    style={styles.btn}
    underlayColor="#fefefe"
    >
      <Image
      source={heartIcon}
      style={styles.icon}
      />
    </TouchableHighlight>
    <Text style={styles.text}>Do you like this app?</Text>
  </View>
  );
}
  1. 定义一些样式来设置 set dimensions, position, margins, colors 等等:
const styles = StyleSheet.create({
  container: {
    marginTop: 50,
    alignItems: 'center'
  },
  btn: {
    borderRadius: 5,
    padding: 10
  },
  icon: {
    width: 180,
    height: 180,
    tintColor: '#f1f1f1'
  },
  liked: {
    tintColor: '#e74c3c'
  },
  text: {
    marginTop: 20
  }
});
  1. 如果在模拟器中运行,应该能看到如下图所示内容:

  2. 为了响应 tap 事件,我们需要定义 _onPressBtn 的处理函数并将其作为回调函数分配给 onPress 属性:

class MainApp extends Component {
  state = {
    liked: false
  };
  _onPressBtn = () => {
    this.setState({
      liked: !this.state.liked
    });
  };
  render() {
    return (
      <View style={styles.container}>
        <TouchableHighlight onPress={this._onPressBtn} style={styles.btn} underlayColor="#fefefe">
          <Image source={heartIcon} style={styles.icon} />
        </TouchableHighlight>
        <Text style={styles.text}>Do you like this app?</Text>
      </View>
    );
  }
}
  1. 如果此时按下按钮,就算组件状态改变成 ON,也不会在 UI 上看到任何更改。只有当我们给它添加不同状态的样式时,才会看到 UI 有响应:
render() {
  const likedStyles = this.state.liked ? styles.liked : null;
  return (
    <View style={styles.container}>
      <TouchableHighlight
      onPress={this._onPressBtn}
      style={styles.btn}
      underlayColor="#fefefe"
      >
        <Image
        source={heartIcon}
        style={[styles.icon, likedStyles]}
        />
      </TouchableHighlight>
      <Text style={styles.text}>Do you like this app?</Text>
    </View>
  );
}
  1. 差不多完成这个类了,唯一缺少的是导出组件。使用如下代码进行导出:
export default MainApp;
  1. 最后,更新 index.ios.js 以及 index.android.js 来导入和使用我们的新组件:
import React, { Component } from 'react';
import { AppRegistry } from 'react-native';
import MainApp from './src/MainApp';
AppRegistry.registerComponent('ButtonsAndEvents', () => MainApp);

原理分析

在步骤 2 中,导入了 TouchableHighlight 组件,用来处理触摸事件。

当用户触摸活动区域时,区域内容将通过我们设置的 underlayColor 样式高亮显示。

在步骤 3 中,定义了一个有状态组件。在本小节中,state 仅仅包含一个属性,但我们可以根据需要添加更多的状态。在第二章“实现复杂的用户界面”中,我们将在更复杂的场景中看到更多的状态处理。

在步骤 6 中,使用 setState 来更新 liked 属性的值。这个方法正是从 Component 类中继承而来。

在步骤 7 中,根据当前 stateliked 属性来设置图片颜色为红色,通过返回 null 来避免应用任何样式。使用数组来组合多个对象样式对于应用样式非常方便,在内部,组件会将所有样式合并为一个对象。后定义的属性将会覆盖先定义的同名属性。

更多

在一个真实的 App 中,我们将可能使用多种按钮,图标左对齐,带标签,不同的尺寸和颜色等等。此时,强烈建议您创建可复用的组件,以避免在 App 中到处重复代码。在第二章“实现复杂的用户界面”中,我们将创建一个按钮来组件来处理其中的一些场景。

显示列表元素

**列表无处不在!**如用户的历史订单列表、商店中的可用商品、待播放的歌曲列表等;基本上,任何 App 都需要用到列表。

在这个小节中,我们将使用列表组件显示几个 Item。先将一些数据定义成 JSON 文件,然后使用 require 来加载这个文件,最终将其渲染为一个漂亮又简洁的列表布局。

前提

首先,创建一个名为 ListItems 的空 App。为了在列表的每个 Item 中显示 icon 图标,请下载图片资源或使用您自己的 .png 图片资源。

实现

  1. 在项目中创建 src 目录,然后在 src 目录中创建 MainApp.js 以及 sales.json

  2. 我们将要显示的列表数据定义在 sales.json 中,示例数据如下:

[{ "items": 5, "address": "140 Broadway, New York, NY 11101", "total": 38, "date": "May 15, 2016" }]
  1. 为了避免占用大量篇幅,我只定义了一条数据,您可以往数据数组中加入更多内容。使用 Ctrl+C Ctrl+V 来创建更多元素,另外,可以修改其中的一些数值。

  2. 找到 index.ios.jsindex.android.js 文件,移除掉已有的代码,添加如下代码来导入依赖和注册 App:

import React, { Component } from 'react';
import { AppRegistry } from 'react-native';
import MainApp from './src/MainApp';
AppRegistry.registerComponent('ListItems', () => MainApp);
  1. 在上一步中,虽然导入了 MainApp,但实际上并没有定义。打开 src/MainApp.js,然后导入如下依赖:
import React, { Component } from 'react';
import { StyleSheet, View, ListView, Image, Text } from 'react-native';
import data from './sales.json';
const basketIcon = require('./images/basket.png');
  1. 现在需要创建一个类来渲染列表。将销售数据放到 state 中,可以让我们很轻松的插入或删除数据:
class MainApp extends Component {
  constructor(props) {
    super(props);
    var ds = new ListView.DataSource({
      rowHasChanged: (r1, r2) => r1 !== r2
    });
    this.state = {
      dataSource: ds.cloneWithRows(data)
    };
  }
  renderRow(record) {
    // Defined on step 8
  }
  render() {
    // Defined on step 7
  }
}
export default MainApp;
  1. 我们需要在 render 方法中,使用 ListView 组件,并使用 renderRow 方法来渲染每个单独的 Item。dataSource 属性定义了需要在列表中呈现的数组元素:
render() {
  return (
    <View style={styles.mainContainer}>
      <Text style={styles.title}>Sales</Text>
      <ListView
        dataSource={this.state.dataSource}
        renderRow={this.renderRow}/>
    </View>
  );
}
  1. 现在,我们来补充 renderRow 方法的内容。这个方法接收包含所需信息单个对象。我们将要显示三个数据列。第一列中,显示 Icon 图标,第二列中每次销售的商品数量和该订单的发货地址,第三列中将售出日期和总价:
renderRow(record) {
  return (
    <View style={styles.row}>
      <View style={styles.iconContainer}>
        <Image source={basketIcon} style={styles.icon} />
      </View>
      <View style={styles.info}>
        <Text style={styles.items}>{record.items} Items</Text>
        <Text style={styles.address}>{record.address}</Text>
      </View>
      <View style={styles.total}>
        <Text style={styles.date}>{record.date}</Text>
        <Text style={styles.price}>${record.total}</Text>
      </View>
    </View>
  );
}
  1. 当我们定义好 JSX 之后,是时候添加样式了。首先,需要为主容器、标题以及行容器定义颜色、外边距、内边距等等。为了为每个列创建三列布局,需要使用到 flexDirection 中的 row 属性。我们将在本章其他小节中学到更多关于该属性的知识:
const styles = StyleSheet.create({
  mainContainer: {
    flex: 1,
    backgroundColor: '#fff'
  },
  title: {
    backgroundColor: '#0f1b29',
    color: '#fff',
    fontSize: 18,
    fontWeight: 'bold',
    padding: 10,
    paddingTop: 40,
    textAlign: 'center'
  },
  row: {
    borderColor: '#f1f1f1',
    borderBottomWidth: 1,
    flexDirection: 'row',
    marginLeft: 10,
    marginRight: 10,
    paddingTop: 20,
    paddingBottom: 20
  }
});
  1. 当我们刷新模拟器时,我们可以看到如下一些截图:

  2. 现在,在 StyleSheet 的定义中,我们来给 icon 图标添加样式。添加一个黄色圆圈作为背景,并将图标的颜色设定为白色:

iconContainer: {
  alignItems: 'center',
  backgroundColor: '#feb401',
  borderColor: '#feaf12',
  borderRadius: 25,
  borderWidth: 1,
  justifyContent: 'center',height: 50,
  width: 50,
},
icon: {
  tintColor: '#fff',
  height: 22,
  width: 22,
},
  1. 应用这些变更后,我们可以每行的左侧有一个好看的 icon 图标,如下图所示:

  2. 最后,为文本设置样式。需要设置颜色、字体、字号、内边距以及其他一些样式:

info: {
  flex: 1,
  paddingLeft: 25,
  paddingRight: 25,
},
items: {
  fontWeight: 'bold',
  fontSize: 16,
  marginBottom: 5,
},
address: {
  color: '#ccc',
  fontSize: 14,
},
total: {
  width: 80,
},
date: {
  fontSize: 12,
  marginBottom: 5,
},
price: {
  color: '#1cad61',
  fontSize: 25,
  fontWeight: 'bold',
},
  1. 最终结果应该类似下图所示:

原理分析

在步骤 6 中,创建了数据源并添加到了 state 中。ListView.DataSourceListView 组件提供了高性能的数据处理。rowhHasChanged 是一个必须的属性,它是一个用来比较数据元素是否变化的函数。

我们需要调用 cloneWithRows 来将数据填充到数据源,并传递给组件。

如果要添加更多数据,我们应该再次调用 cloneWithRows 包含旧数据和新数据。数据源将计算差异并在必要时重新渲染。

在步骤 7 中,使用 render 方法来渲染列表。步骤 6 中的数据源以及 renderRow 方法是两个必备的属性。

renderRow 是为每个行返回 JSX 的函数。

更多

我们使用 flexbox 创建了一个简单的布局;然而,在本章中还有另外的小节将深入的探讨使用 flexbox 的更多细节。

一旦有了列表,我们就应该有机会去看到每个订单的细节。此时,我们应该使用 TouchableHighlight 组件作为每行的主容器,所以,请继续尝试。如果还不确定如何使用 TouchableHighlight 组件,请参考本章节中“创建一个切换按钮”。

在视窗中添加选项卡

Tabs(选项卡) 是一个非常常见的组件,特别是在 iOS App 中。在本小节中,我们来学习如何在 iOS 中使用选项卡组件。截止目前,还并不支持 Android,如果真的需要在 Android 中使用选项卡,请选用第三方组件库来添加类似功能。

实现

  1. 首先,导入该组件的所有依赖项以及需要使用到的图标:
import React, { Component } from 'react';
import { StyleSheet, View, Image, Text, TabBarIOS } from 'react-native';
const homeIcon = require('./images/home.png');
const favIcon = require('./images/star.png');
const blogIcon = require('./images/notebook.png');
const profileIcon = require('./images/user.png');
  1. 为了选中一个选项卡,应该在 state 中存储当前选中状态,因此我们需要使用类来定义组件,如下:
class MainApp extends Component {
  state = {
    selected: 'home'
  };
  selectTab(id) {
    // Defined on step 5
  }
  renderTab(options) {
    // Defined on step 4
  }
  render() {
    // Defined on step 3
  }
}
  1. render 方法中,我们需要定义选项卡组件以及我们要展示的每个选项卡。此时,我们可以使用包含参数的 renderTab 方法来构建 JSX,这使得我们可以通过调用函数来复用代码:
render() {
  return (
    <TabBarIOS
      tintColor="#42b49a"
      >
      {this.renderTab({title: 'Home', id: 'home', icon: homeIcon})}
      {this.renderTab({title: 'Favorites', id: 'favorites', icon: favIcon})}
      {this.renderTab({title: 'Blog', id: 'blog', icon: blogIcon})}
      {this.renderTab({title: 'Profile', id: 'profile', icon: profileIcon})}
    </TabBarIOS>
  );
}
  1. 对于 renderTab 方法,我们需要定义一些属性,如标签标题、图标、是否选中以及选中时的回调函数。现在,我们为每个标签设定相同的内容,实际应用中,需要将主要内容作为参数传递到 App 中。其中最重要的属性就是选中属性。因为只可以在选项卡中选中一个项,所以将当前选中的项保存在 state 中:
renderTab(options) {
  return (
    <TabBarIOS.Item
      title={options.title}
      selected={this.state.selected === options.id}
      onPress={() => this.selectTab(options.id)}
      icon={options.icon}
      >
      <View style={styles.container}>
        <Image source={options.icon} style={styles.icon} />
        <Text style={styles.title}>{options.title}</Text>
      </View>
    </TabBarIOS.Item>
  );
}
  1. 在上一步中,在选项卡项按下时,将会调用 selectTab 方法。这里的考虑是,当用户按下选项卡项时,调用此函数把选中项 ID 保存到 state 中,用来设置当前选中状态:
selectTab(id) {
  this.setState({
    selected: id,
  });
}
  1. 接着,给屏幕上的内容添加一些样式,也为每个标签的 icon 设置合适的颜色。同时,我们也将组件进行导出,便于在其他任何地方使用:
const styles = StyleSheet.create({
  container: {
    flex: 1,
    alignItems: 'center',
    justifyContent: 'center'
  },
  title: {
    fontSize: 20,
    marginTop: 20
  },
  icon: {
    width: 30,
    height: 30,
    tintColor: '#42b49a'
  }
});
export default MainApp;
  1. 最后,更新 index.ios.js,导入我们新的类:
import React, { Component } from 'react';
import { AppRegistry } from 'react-native';
import MainApp from './src/MainApp';
AppRegistry.registerComponent('TabsComponent', () => MainApp);
  1. 在模拟器中查看最终效果,如下:

使用 flexbox 创建个人资料页面

设置导航器