2019-03-28
本文的原作者是Holly Girouard,文章源链接为 Building a Landing Page in React Native Using Flexbox,我将其翻译成中文。
如果你不熟悉 React Native 的 Flexbox 布局机制的话,编写 React Native 布局会十分痛苦。虽然你也可以用 JavaScript 写布局,但是理解和使用 Flexbox 布局是 React Native UI 开发的必备技能。在本文中,我们将使用 React Native 开发一个落地页。
你很可能已经熟悉了 CSS 中的 Flexbox 布局,React Native 的 Flexbox 实现跟它几乎是一样的。
Flexbox 是一种高效强大的布局工具,专门用于构建用户界面,特别是移动界面。
通过在组件的 style 中使用 flex
属性,我们可以根据可用的空间动态地放大和缩小。
React 中的 flex 属性与 CSS 的有一点不同,它的工作原理更像是 CSS 中的 fr 单元,其中提供一个数值表示占据屏幕的空间比例。
因此,在 React Native 中,flex 的取值是一个整数值。
除了 flex 属性之外,另一点与 CSS 的不同是:在 React Native 的 Flexbox 中,flex-direction
默认值是 column
。
在我们的实例项目汇总,我们要创建一个 AlligatorChef 🐊 落地页。
项目完成后的最终结果如下:
🐥如果你是 React Native 新手,可以先看我们的 Getting Started with React Native and Expo 再看本文。
在命令行中输入下列命令创建一个新的 React Native 项目。进入新目录中,初始化项目,并输入 i 对应 iOS 平台:
$ create-react-native-app AlligatorChef
$ cd AlligatorChef
$ npm start
$ i
在 Create React Native App 的初始化代码中,已经包含了一个 Flexbox 的示例,它在 StyleSheet.create 调用中使用 flex 属性。
看一下 App.js 文件。似乎给了我们一个暗示,Flexbox 是在 React Native 中设置样式的关键:
const styles = StyleSheet.create({ container: { flex: 1, backgroundColor: '#fff', alignItems: 'center', justifyContent: 'center', }, });
这告诉我们 container 应当拉伸到充满整个屏幕。
现在我们有了默认的项目,下一步对它做一些修改。
首先创建两个 Text 元素用于标题。
替换以下代码:
<Text>Open up App.js to start working on your app!</Text> <Text>Changes you make will automatically reload.</Text> <Text>Shake your phone to open the developer menu.</Text>
替换为:
<Text style={styles.h1}>AlligatorChef</Text> <Text style={styles.h2}>Providing cajun bacon recipes since 1987.</Text>
下面再在 StyleSheet 中添加一些样式。清空 StyleSheet 中的内容,替换为以下样式:
const styles = StyleSheet.create({ container: { flex: 1, justifyContent: 'space-between', backgroundColor: '#000', alignItems: 'center', width: '100%', }, h1: { color: '#008F68', fontSize: 40, }, h2: { color: '#FAE042', fontSize: 18, marginTop: 8, }, });
现在看看修改之后的效果。
我们将 justifyContent 从 center
改为 space-between
。如果我们改回 center
,所有元素都会再次居中。
当使用 justifyContent: 'space-between'
时,表示每个元素在屏幕的顶部与底部之间按照相同的间隔排布。
这是为什么我们的 h1 跑到最顶上,h2 跑到最底下。
我们继续来添加按钮和图片。
将你现在的代码替换为下面代码,保留 styles 声明:
import React from 'react'; import { StyleSheet, Text, View, Button, Image } from 'react-native'; import Logo from './assets/chef.png'; export default class App extends React.Component { render() { return ( <View style={styles.container}> <Text style={styles.h1}>AlligatorChef</Text> <Text style={styles.h2}>Providing cajun bacon recipes since 1987.</Text> <Image source={Logo} style={styles.image} /> <Button title="LET'S START" style={styles.button} onPress={() => this.onPress()} color="#fff" /> </View> ); } } // ...
下面在根目录下创建一个 assets 目录。
通常我们把图片放到 assets 目录下,这样项目中的所有组件都能很方便地获取到。
添加一个你想用作 AlligatorChef 🐊 Logo 的图片到这个目录下。
React Native 对图片的处理有些奇怪,可能会给你带来问题。在我们的长讲下,确保你导入的是 png 图片。
添加图片后,效果过下:
这个效果不太好。
现在界面中的元素都有了,但是展示效果不太好。我们来修复它。
作为 React Native 的一个最佳实践,我们总是给图片一个尺寸。
如果你曾经遇到过图片没有展示出来的问题,先看看你有没有给图片指定尺寸。
在上面的代码中可以看出,我们已经给图片指定了一个 style prop。在 StyleSheet 添加如下代码:
image: { width: 300, height: 260, justifyContent: 'center', },
再次运行,会看到 Logo 的展示效果好多了!
React Native 中的按钮也很特别。
它的按钮文字不是在 <Button>
和 </Button>
之间添加,而是使用一个 title prop 添加。
下面我们继续给按钮添加一个 Style。
首先,添加一个 class 为 buttonContainer 的 View:
<View style={styles.buttonContainer}> <Button title="LET'S START" style={styles.button} onPress={() => this.onPress()} color="#fff" /> </View>
stylesheet 的定义如下:
buttonContainer: { backgroundColor: '#008F68', borderRadius: 5, padding: 8, margin: 8, },
显示效果如下,现在看起来像按钮了:
现在我们通过使用神器的 Flexbox 让页面剩下的部分都变得可控。准备好了吗?🏀
首先我们在最初的 container 下添加三个 container。
将你的原始代码替换为下面代码,你将注意到几个新的类(topContainer
, middleContainer
, 和 bottomContainer
):
import React from "react"; import { StyleSheet, Text, View, Button, Image, ProgressViewIOS } from "react-native"; import Logo from "./assets/chef.png"; export default class App extends React.Component { render() { return ( <View style={styles.container}> <View style={styles.topContainer}> <Text style={styles.h1}>AlligatorChef</Text> <Text style={styles.h2}> Providing cajun bacon recipes since 1987. </Text> </View> <View style={styles.middleContainer}> <Image source={Logo} style={styles.image} /> </View> <ProgressViewIOS number={1} /> <View style={styles.bottomContainer}> <View style={styles.buttonContainer}> <Button title="LET'S START" style={styles.button} onPress={() => this.onPress()} color="#fff" /> </View> </View> </View> ); } }
下面给我们的 StyleSheet 添加这些类:
topContainer: { flex: 2, justifyContent: 'center', alignItems: 'center', }, middleContainer: { flex: 3, justifyContent: 'flex-start', alignItems: 'center', }, bottomContainer: { justifyContent: 'flex-end', width: '90%', margin: 20, padding: 10, },
下面是见证奇迹的时刻:
我们给 topContainer 赋值了 flex: 2
,赋予 flex-grow 值为 2,因此它占据原始 container 的 2/5 的空间。
我们还告诉他将所有子元素 align 和 justify 到中心。
在下图中给出一个可视的理解:
我们给 middleContainer 赋值 flex: 3
,表示它占据原始 container 3/5 的空间。
我们没有用 justifyContent: 'center'
,而是使用了 justifyContent: 'flex-start'
。
这样 AlligatorChef 会位于 middleContainer 的顶部位置:
最后,因为我们不关心按钮占据的控件,因此就不需要给他设定 flex 值。我们只需要按钮位于页面的最底部,因此设置值 bottomContainer
justifyContent: 'flex-end'
。
本文只是一个大体介绍,Flexbox 布局模块不仅在 React Native 中很有用,在整个 Web 开发中都很有用。