在本教程中,您将学习如何布局React Native应用程序以及如何实现应用程序中常用的布局。 这包括堆栈布局,网格布局和绝对布局。 我假设您已经了解了React Native应用程序样式的基础知识以及一般如何使用CSS,因此我不会过多地关注StyleSheet.create
以及如何向不同的元素添加样式。
您可以在GitHub上找到本教程的完整源代码 。
项目设置
为了使事情变得容易,我们将使用React Native for Web 。 借助用于Web Starter的React Native ,我们可以轻松启动可以在浏览器中运行的新React Native项目。 此代码与React Native项目 100%兼容。 我们将为要实现的每个布局创建一个单独的组件,以便您可以根据需要轻松地将它们导入到正常的React Native项目中。 我们只是使用React Native for Web,因为它更容易启动和运行。
您可以执行以下命令来设置项目:
git clone https://github.com/grabcode/react-native-web-starter.git RNLayouts
cd RNLayouts
rm -rf .git
npm install
安装完成后,在app / components目录中导航。 这是我们将主要处理的文件。
打开App.js文件,并用以下内容替换默认代码:
import React, { Component } from 'react';
//import the components that we'll be creating here
export class App extends Component {
render() {
return (
//use the components here
);
}
}
稍后,您可以导入我们将要创建的组件,然后从该文件中渲染它们。 只需记住,我们保存在layouts
目录中的任何组件都不应使用其他任何元素进行渲染。 例如,如果我们有layouts / StackLayout.js ,请在App.js中执行以下操作 :
import React, { Component } from 'react';
//import the components that we'll be creating here
import StackLayout from './layouts/StackLayout';
export class App extends Component {
render() {
return (
);
}
}
您可以通过执行以下命令为项目提供服务:
npm run dev
这样,您可以通过访问http://localhost:3000
在浏览器中对其进行访问。 如果您更改当前从App.js文件导入的任何文件,将触发整页重新加载。
如何创建不同的布局
React Native中的布局使用Flexbox的子集。 (我说“子集”是因为未包括Flexbox规范中的所有功能。)因此,如果您已经知道Flexbox,则可以轻松地在React Native中应用这些技能。 还值得注意的是,React Native中没有浮点数或基于百分比的单位。 这意味着我们只能使用Flexbox和CSS定位进行布局。
堆叠布局
我们将要实现的第一种布局是堆栈布局。 对于垂直方向,它将元素堆叠在一起,而对于水平方向,则将元素并排放置。 首先让我们看一下垂直方向:
这是完成上述布局的代码:
import React, { Component } from 'react';
import {
StyleSheet,
View,
Dimensions
} from 'react-native';
var { height } = Dimensions.get('window');
var box_count = 3;
var box_height = height / box_count;
export default class VerticalStackLayout extends Component {
render() {
return (
);
}
}
const styles = StyleSheet.create({
container: {
flex: 1,
flexDirection: 'column'
},
box: {
height: box_height
},
box1: {
backgroundColor: '#2196F3'
},
box2: {
backgroundColor: '#8BC34A'
},
box3: {
backgroundColor: '#e3aa1a'
}
});
分解上面的代码,我们首先获得应用程序要消耗的可用空间的高度。 然后我们计算每个盒子的高度。 由于我们有三个方框,因此我们将其除以三。
var { height } = Dimensions.get('window');
var box_count = 3;
var box_height = height / box_count;
对于标记,盒子应包装在容器内。 通用样式在box
对象中声明,并且唯一的背景颜色应用于唯一命名的对象( box1
, box2
, box3
):
要使用Flexbox,必须在容器上使用flex
属性。 该值是它将消耗的空间量。 如果为1
,则意味着它将消耗所有可用空间,前提是该元素没有兄弟姐妹。 稍后,我们将看一个使用flex
与同级对象的示例。
flexDirection
允许您指定布局的主轴。 默认情况下,它设置为column
。 将flexDirection
设置为column
意味着容器的子代将垂直放置(堆叠在一起),而将其设置为row
意味着将子容器水平放置(并排放置)。 要获得相等的高度,请将box
的高度设置为我们先前计算的值。
const styles = StyleSheet.create({
container: {
flex: 1,
flexDirection: 'column'
},
box: {
height: box_height //set this one
},
box1: {
backgroundColor: '#2196F3'
},
box2: {
backgroundColor: '#8BC34A'
},
box3: {
backgroundColor: '#e3aa1a'
}
});
这是一张图像,可帮助您根据指定的flexDirection
可视化内容的流动方式。
我刚刚向您展示的方法是手动执行操作。 如果您的应用同时支持纵向和横向设备方向,则使用“ Dimensions
计算元素的宽度或高度将失败。 这是因为一旦用户翻转设备,您之前计算出的宽度或高度就会错误。 React Native不会自动为您重新计算,因此该应用最终看起来很奇怪。
如果您提供正确的值,Flexbox实际上可以为您进行计算。 要在不使用Dimensions
情况下实现与上述相同的布局,您要做的就是为所有框指定flex: 1
而不是指定height
:
box: {
flex: 1
},
现在,这是将flex
与同级结合使用的示例。 现在,我们有三个具有相同flex
值的兄弟姐妹。 这意味着,由于flex
值相同,所以它们三个都将平均共享可用空间。 (您实际上可以使用任何flex
值,只要所有子元素都具有相同的值即可。)
使用此知识,您现在可以使用页眉,内容和页脚实现布局:
//header
box1: {
flex: 1,
backgroundColor: '#2196F3'
},
//content
box2: {
flex: 10,
backgroundColor: '#8BC34A'
},
//footer
box3: {
flex: .5,
backgroundColor: '#e3aa1a'
}
它将是这样的:
请注意,这将是静态的。 因此,如果您的主要内容变得高于最大可用高度,则其余内容将被隐藏。 如果您希望内容超过该限制,则可以使用内置的ScrollView
组件来自动生成垂直滚动条,就像在网页中一样。
水平堆栈布局
要实现水平堆栈布局,您要做的就是将flexDirection
更改为row
。
container: {
flex: 1,
flexDirection: 'row'
},
如果将box flex
值更改回1
,则会得到以下输出:
我们唯一更改的是flexDirection
,现在将其设置为row
。 由于所有框都设置为flex: 1
,因此它们将具有相同的宽度和高度。 垂直堆栈布局中的所有想法都同样适用于这一想法。
证明内容合理
如果要控制容器中子代的分布,请使用容器上的justifyContent
属性。
以下是可与此属性一起使用的五个可能的值。 在以下示例中,每个孩子的身高都降低了,以演示每个孩子的外观。 如果每个子代的flex
值为1
,您将看不到任何差异,因为它们最终将占用所有可用空间。
-
flex-start
:子元素朝向起点对齐。 注意最后一个孩子下方的白色背景。 这就是您知道这是在使用flex-start
原因,因为所有子项都对准起点。 到最后留下一个空白空间。
-
flex-end
:子元素朝终点线对齐。 请注意,这次空白是在起点。
-
center
:子元素朝中心放置。 这次,空白空间在起点和终点之间平均分配。
-
space-around
:子元素的分布方式使得每个元素space-around
均等。 这意味着外部的元素在其外侧上的空间较小,并且两个子元素之间的空间增加了一倍。
-
space-between
:子元素的分布方式使得每个子元素之间的空间相等。
您可能已经注意到,每个样式属性都取决于子元素的高度或宽度。 它是依赖于宽度,如果flexDirection
是row
,并在高度如果flexDirection
是column
。
例如,如果每个子元素都使用flex
来控制高度,则在垂直堆栈布局上的space-between
实际上不会产生任何影响。 这是因为每个子元素之间的间隙将不再有空间要消耗。
对齐项目
乍一看, justifyContent
和alignItems
看起来好像在做相同的事情。 它们还共享三个可能的值: flex-start
, flex-end
和center
,并增加了stretch
值。
justifyContent
和alignItems
之间的主要区别是分布子项的轴。 如前所述, justifyContent
在分发子元素时始终使用主轴。 但是alignItems
使用与主要轴相反的轴。
我们已经知道轴由已设置的flexDirection
确定。 因此,如果flexDirection
为row
,则主轴从左向右流动。 这意味着横轴将从上到下流动。 另一方面,如果flexDirection
为column
则交叉轴将从左向右流动。
下面是一些例子justifyContent
和alignItems
实施并排的flexDirection
的row
。 第一个使用justifyContent
,第二个使用alignItems
。
-
flex-start
:元素的位置相同,这就是为什么alignItems
实现看起来完全像justifyContent
。
-
flex-end
:现在我们开始看到差异。 在第一个实例中,它位于第一行行的末尾,而第二个实例似乎在最后一行的起始行。
-
center
:center
与我们到目前为止使用的其余值具有相同的想法。 在第一种情况下,项目以x轴为中心,而在第二种情况下,项目以y轴为中心。
-
stretch
:使用它来拉伸子元素以填充容器。 这是alignItems
的默认值,因此指定此值是可选的。 您已经了解了当我们实现垂直和水平堆栈布局时这是如何工作的。
这是上面示例中使用的代码。 如果要查看它们的外观,只需使用flexDirection
, justifyContent
和alignItems
的值即可:
import React, { Component } from 'react';
import {
StyleSheet,
View
} from 'react-native';
export default class AlignItems extends Component {
render() {
return (
);
}
}
const styles = StyleSheet.create({
wrapper: {
flex: 1
},
container: {
flex: .5,
flexDirection: 'row',
justifyContent: 'flex-start', //replace with flex-end or center
borderBottomWidth: 1,
borderBottomColor: '#000'
},
container2: {
flex: .5,
flexDirection: 'row',
alignItems: 'flex-start' //replace with flex-end or center
},
box: {
width: 100,
height: 100
},
box1: {
backgroundColor: '#2196F3'
},
box2: {
backgroundColor: '#8BC34A'
},
box3: {
backgroundColor: '#e3aa1a'
}
});
如果要指定容器中各个元素的对齐方式,则可以使用alignSelf
属性。 align-items
所有可能值也适用于此属性。 因此,例如,您可以将单个元素对齐到其容器的右侧,而将其余所有元素都对齐到左侧。
网格布局
React Native并没有真正提供网格布局系统,但是Flexbox足够灵活以创建一个网格布局系统。 通过使用到目前为止所学的知识,我们可以使用Flexbox重新创建Grid布局。 这是一个例子:
这是创建布局的代码:
import React, { Component } from 'react';
import {
StyleSheet,
View
} from 'react-native';
export default class GridLayout extends Component {
render() {
return (
);
}
}
const styles = StyleSheet.create({
row: {
flex: 1,
flexDirection: 'row',
justifyContent: 'space-between',
marginBottom: 10
},
box: {
flex: 1,
height: 100,
backgroundColor: '#333',
},
box2: {
backgroundColor: 'green'
},
box3: {
backgroundColor: 'orange'
},
two: {
flex: 2
}
});
从上面的代码中,您可以看到我们正在模仿它们在CSS网格框架中通常执行的操作。 每行都包装在单独的视图中,并且网格项位于其中。 默认的flex
值1
应用于每个项目,因此它们将平均共享每一行上的可用空间。 但是对于需要占用较大空间的项目,将应用较高的flex
值。 这将自动调整其他项目的宽度,以便容纳所有项目。
如果要在行中的每个项目之间添加空格,则可以为每个项目添加填充,然后在每个项目内部创建一个框。
结果为以下输出:
绝对布局
React Native仅支持absolute
和relative
定位。 但是,这不应该限制您,因为您始终可以将它们与Flexbox结合使用,以将不同的元素放置在所需的任何位置。
让我们看看如何完成以下任务:
如果我们对浏览器中可用的定位值具有完整的命令,则可以轻松实现此目的。 但是由于我们在React Native中,所以我们需要首先考虑Flexbox的方式,然后再对小盒子使用CSS定位。
使用Flexbox,可以通过两种方式实现。 您可以将row
或column
用于主容器的flexDirection
。 如何安排不同元素取决于您选择哪种方法。 在这里,我们将对flexDirection
使用row
,以便将屏幕分为三列。 第一列将包含橙色框,第二列将包含黑色,灰色和绿色框,第三列将包含蓝色和紫色小框。
import React, { Component } from 'react';
import {
StyleSheet,
View
} from 'react-native';
export default class Positioning extends Component {
render() {
return (
);
}
}
如果您已经知道每个元素的布局方式,那么只需应用到目前为止所学的知识即可。 毕竟,我们实际上不需要在大盒子上应用CSS定位,只需要在小盒子上应用CSS定位。
第一列只有橙色框,因此在其容器中应用justifyContent: 'center'
应该可以解决问题。 如果您已经忘记了, flexDirection
默认为column
。 这意味着,如果将justifyContent
设置为center
,则子代将在Y轴的中心对齐。
第二列与第一列基本具有相同的想法,只是这次我们不想将所有框对齐到中心。 我们想要的是它们彼此之间具有相等的空间,并实现justifyContent: 'space-between'
可以完成这项工作。 但是同时,我们还希望将所有子项都放在X轴上alignItems: 'center'
因此我们使用alignItems: 'center'
。
这里唯一棘手的部分是,您不应将任何width
属性应用于灰色框,因为我们希望它一直伸展以消耗其父级的整个宽度。 由于我们没有应用任何width
,因此我们应该将alignSelf: 'stretch'
应用于灰色框,以便它将占用其父级的全部宽度。
接下来,要使红色小框的位置稍微偏离其相对位置,我们使用position: relative
,然后应用top
和left
值,因为其相对位置在其父级的左上角附近。
至于小橙色框,我们使用position: 'absolute'
因为我们需要将其对准其父级的右上角。 之所以可行,是因为React Native中绝对定位的元素已绑定到其父元素。
第三列基本上采用了相同的想法,因此我不再赘述。
const styles = StyleSheet.create({
container: {
flex: 1,
flexDirection: 'row'
},
left: {
flex: 1,
justifyContent: 'center'
},
middle: {
flex: 5,
justifyContent: 'space-between',
alignItems: 'center'
},
right: {
flex: 1,
justifyContent: 'center',
alignItems: 'flex-end'
},
box: {
width: 100,
height: 100,
backgroundColor: '#333'
},
big_green_box: {
backgroundColor: 'green'
},
big_orange_box: {
backgroundColor: 'orange'
},
big_lightblue_box: {
backgroundColor: '#03A9F4'
},
big_gray_box: {
height: 100,
alignSelf: 'stretch',
backgroundColor: '#ccc'
},
inner_box: {
width: 20,
height: 20,
},
red_box: {
position: 'relative',
backgroundColor: 'red',
top: 10,
left: 10
},
orange_box: {
position: 'absolute',
backgroundColor: 'orange',
top: 10,
right: 10
},
purple_box: {
position: 'absolute',
backgroundColor: 'purple',
bottom: 10,
right: 10
},
black_box: {
position: 'relative',
backgroundColor: 'black'
}
});
接下来,让我们尝试实现固定的页眉和页脚布局。 这通常在具有标签导航的应用中找到; 选项卡固定在屏幕底部,而主要内容可以滚动。
为此,我们需要使用ScrollView
组件,以便如果主要内容超出了容器的高度,React Native将自动生成一个垂直滚动条。 这使我们可以在主要内容容器中添加marginTop
和marginBottom
,以便固定的页眉和页脚不会阻碍主要内容。 另外,请注意,页眉和页脚的left
值和right
值都设置为0
这样它们将占用整个设备的宽度。
import React, { Component } from 'react';
import {
StyleSheet,
View,
ScrollView
} from 'react-native';
export default class FixedHeaderFooter extends Component {
render() {
return (
);
}
}
const styles = StyleSheet.create({
container: {
flex: 1,
flexDirection: 'column',
justifyContent: 'center'
},
header: {
height: 40,
position: 'absolute',
left: 0,
right: 0,
top: 0,
backgroundColor: '#03A9F4',
zIndex: 10
},
content: {
alignItems: 'center',
marginTop: 50,
marginBottom: 40
},
footer: {
height: 40,
position: 'absolute',
left: 0,
right: 0,
bottom: 0,
backgroundColor: '#8BC34A'
},
box: {
width: 100,
height: 100,
backgroundColor: '#333',
marginBottom: 10
}
});
外观如下:
第三方图书馆
React Native背后有一个庞大的社区,因此,毫无疑问已经创建了一些库来简化布局的实现。 在本节中,我将向您介绍一个名为React Native Easy Grid的库。 您可以使用它来描述如何通过使用Grid
, Row
和Col
组件来布局应用程序。
您可以使用以下命令进行安装:
npm install react-native-easy-grid --save
导入库并提取文件中的不同组件。
import React, { Component } from 'react';
import {
StyleSheet,
View
} from 'react-native';
import { Col, Row, Grid } from "react-native-easy-grid";
Grid
组件用于包装所有内容。 Col
用于创建列, Row
用于创建行。 您可以为Row
和Col
都指定一个size
属性,尽管我们仅在下面的Row
中使用了它。 如果未指定大小,它将在Col
实例之间平均分配可用空间。
在这种情况下,只有两个,因此整个屏幕分为两列。 然后,第一列分为两行。 在这里,我们指定了一个size
,但是如果您只需要相同大小的行,则可以实际跳过它,如下所示。
export default class FlexboxGridLibrary extends Component {
render() {
return (
);
}
}
完成后,您所要做的就是为行和列添加样式:
const styles = StyleSheet.create({
orange_box: {
backgroundColor: 'orange'
},
green_box: {
backgroundColor: 'green'
},
gray_box: {
backgroundColor: 'gray'
}
});
您已经注意到,React Native Easy Grid具有非常直观的API。
结论
在本教程中,您学习了如何布局React Native应用程序。 具体来说,您学习了如何使用React Native的Flexbox定位事物。 您还学习了如何使用React Native Easy Grid,这使Flexbox的实现更加容易。
在即将发布的教程中,我们将通过重新创建应用程序中常见的UI元素将您学到的所有知识付诸实践,例如日历,列表和标签导航。
翻译自: https://code.tutsplus.com/tutorials/get-started-with-layouts-in-react-native--cms-27418