Skip to content

Commit

Permalink
Update chapter1
Browse files Browse the repository at this point in the history
Former-commit-id: 624fa3b
Former-commit-id: 018e6f4
  • Loading branch information
hstarorg committed Mar 23, 2018
1 parent 7a171a5 commit 7c517e0
Showing 1 changed file with 315 additions and 0 deletions.
315 changes: 315 additions & 0 deletions React Native Cookbook/章节一.md
Original file line number Diff line number Diff line change
Expand Up @@ -450,8 +450,323 @@ AppRegistry.registerComponent('ButtonsAndEvents', () => MainApp);
## 显示列表元素
**列表无处不在!**如用户的历史订单列表、商店中的可用商品、待播放的歌曲列表等;基本上,任何 App 都需要用到列表。
在这个小节中,我们将使用列表组件显示几个 Item。先将一些数据定义成 JSON 文件,然后使用 `require` 来加载这个文件,最终将其渲染为一个漂亮又简洁的列表布局。
### 前提
首先,创建一个名为 `ListItems` 的空 App。为了在列表的每个 Item 中显示 icon 图标,请下载图片资源或使用您自己的 `.png` 图片资源。
### 实现
1. 在项目中创建 `src` 目录,然后在 `src` 目录中创建 `MainApp.js` 以及 `sales.json`
2. 我们将要显示的列表数据定义在 `sales.json` 中,示例数据如下:
```json
[{ "items": 5, "address": "140 Broadway, New York, NY 11101", "total": 38, "date": "May 15, 2016" }]
```
3. 为了避免占用大量篇幅,我只定义了一条数据,您可以往数据数组中加入更多内容。使用 `Ctrl+C Ctrl+V` 来创建更多元素,另外,可以修改其中的一些数值。
4. 找到 `index.ios.js``index.android.js` 文件,移除掉已有的代码,添加如下代码来导入依赖和注册 App:
```js
import React, { Component } from 'react';
import { AppRegistry } from 'react-native';
import MainApp from './src/MainApp';
AppRegistry.registerComponent('ListItems', () => MainApp);
```
5. 在上一步中,虽然导入了 `MainApp`,但实际上并没有定义。打开 `src/MainApp.js`,然后导入如下依赖:
```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');
```
6. 现在需要创建一个类来渲染列表。将销售数据放到 `state` 中,可以让我们很轻松的插入或删除数据:
```js
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;
```
7. 我们需要在 `render` 方法中,使用 `ListView` 组件,并使用 `renderRow` 方法来渲染每个单独的 Item。`dataSource` 属性定义了需要在列表中呈现的数组元素:
```js
render() {
return (
<View style={styles.mainContainer}>
<Text style={styles.title}>Sales</Text>
<ListView
dataSource={this.state.dataSource}
renderRow={this.renderRow}/>
</View>
);
}
```
8. 现在,我们来补充 `renderRow` 方法的内容。这个方法接收包含所需信息单个对象。我们将要显示三个数据列。第一列中,显示 Icon 图标,第二列中每次销售的商品数量和该订单的发货地址,第三列中将售出日期和总价:
```js
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>
);
}
```
9. 当我们定义好 JSX 之后,是时候添加样式了。首先,需要为主容器、标题以及行容器定义颜色、外边距、内边距等等。为了为每个列创建三列布局,需要使用到 `flexDirection` 中的 `row` 属性。我们将在本章其他小节中学到更多关于该属性的知识:
```js
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
}
});
```
10. 当我们刷新模拟器时,我们可以看到如下一些截图:
11. 现在,在 `StyleSheet` 的定义中,我们来给 icon 图标添加样式。添加一个黄色圆圈作为背景,并将图标的颜色设定为白色:
```js
iconContainer: {
alignItems: 'center',
backgroundColor: '#feb401',
borderColor: '#feaf12',
borderRadius: 25,
borderWidth: 1,
justifyContent: 'center',height: 50,
width: 50,
},
icon: {
tintColor: '#fff',
height: 22,
width: 22,
},
```
12. 应用这些变更后,我们可以每行的左侧有一个好看的 icon 图标,如下图所示:
13. 最后,为文本设置样式。需要设置颜色、字体、字号、内边距以及其他一些样式:
```js
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',
},
```
14. 最终结果应该类似下图所示:
### 原理分析
在步骤 6 中,创建了数据源并添加到了 `state` 中。`ListView.DataSource``ListView` 组件提供了高性能的数据处理。`rowhHasChanged` 是一个必须的属性,它是一个用来比较数据元素是否变化的函数。
我们需要调用 `cloneWithRows` 来将数据填充到数据源,并传递给组件。
如果要添加更多数据,我们应该再次调用 `cloneWithRows` 包含旧数据和新数据。数据源将计算差异并在必要时重新渲染。
在步骤 7 中,使用 `render` 方法来渲染列表。步骤 6 中的数据源以及 `renderRow` 方法是两个必备的属性。
`renderRow` 是为每个行返回 JSX 的函数。
### 更多
我们使用 `flexbox` 创建了一个简单的布局;然而,在本章中还有另外的小节将深入的探讨使用 `flexbox` 的更多细节。
一旦有了列表,我们就应该有机会去看到每个订单的细节。此时,我们应该使用 `TouchableHighlight` 组件作为每行的主容器,所以,请继续尝试。如果还不确定如何使用 `TouchableHighlight` 组件,请参考本章节中“创建一个切换按钮”。
## 在视窗中添加选项卡
`Tabs(选项卡)` 是一个非常常见的组件,特别是在 `iOS` App 中。在本小节中,我们来学习如何在 `iOS` 中使用选项卡组件。截止目前,还并不支持 `Android`,如果真的需要在 `Android` 中使用选项卡,请选用第三方组件库来添加类似功能。
### 实现
1. 首先,导入该组件的所有依赖项以及需要使用到的图标:
```js
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');
```
2. 为了选中一个选项卡,应该在 `state` 中存储当前选中状态,因此我们需要使用类来定义组件,如下:
```js
class MainApp extends Component {
state = {
selected: 'home'
};
selectTab(id) {
// Defined on step 5
}
renderTab(options) {
// Defined on step 4
}
render() {
// Defined on step 3
}
}
```
3. 在 `render` 方法中,我们需要定义选项卡组件以及我们要展示的每个选项卡。此时,我们可以使用包含参数的 `renderTab` 方法来构建 JSX,这使得我们可以通过调用函数来复用代码:
```js
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>
);
}
```
4. 对于 `renderTab` 方法,我们需要定义一些属性,如标签标题、图标、是否选中以及选中时的回调函数。现在,我们为每个标签设定相同的内容,实际应用中,需要将主要内容作为参数传递到 App 中。其中最重要的属性就是选中属性。因为只可以在选项卡中选中一个项,所以将当前选中的项保存在 `state` 中:
```js
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>
);
}
```
5. 在上一步中,在选项卡项按下时,将会调用 `selectTab` 方法。这里的考虑是,当用户按下选项卡项时,调用此函数把选中项 ID 保存到 `state` 中,用来设置当前选中状态:
```js
selectTab(id) {
this.setState({
selected: id,
});
}
```
6. 接着,给屏幕上的内容添加一些样式,也为每个标签的 icon 设置合适的颜色。同时,我们也将组件进行导出,便于在其他任何地方使用:
```js
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;
```
7. 最后,更新 `index.ios.js`,导入我们新的类:
```js
import React, { Component } from 'react';
import { AppRegistry } from 'react-native';
import MainApp from './src/MainApp';
AppRegistry.registerComponent('TabsComponent', () => MainApp);
```
8. 在模拟器中查看最终效果,如下:
## 使用 `flexbox` 创建个人资料页面
## 设置导航器

0 comments on commit 7c517e0

Please sign in to comment.