在 React Native 中使用 flexbox 规则来指定某个组件的子元素的布局。Flexbox可以在不同屏幕尺寸上提供一致的布局结构。
使用flexDirection、alignItems和 justifyContent三个样式属性就已经能满足大多数布局需求。
React Native 中的 Flexbox 的工作原理和 web 上的 CSS基本一致,当然也存在少许差异。首先是默认值不同:flexDirection的默认值为column(而不是row),alignContent默认值为flex-start(而不是 stretch), flexShrink 默认值为0 (而不是1), 而flex只能指定一个数字值。
Flex
flex 属性决定元素在主轴上如何填满可用区域。整个区域会根据每个元素设置的 flex 属性值被分割成多个部分。
import React from "react";
import {
StyleSheet, Text, View } from "react-native";
const Flex = () => {
return (
<View style={
[styles.container, {
// Try setting `flexDirection` to `"row"`.
flexDirection: "column"
}]}>
<View style={
{
flex: 1, backgroundColor: "red" }} /> // view 占据整个区域的1/6
<View style={
{
flex: 2, backgroundColor: "darkorange" }} />
<View style={
{
flex: 3, backgroundColor: "green" }} />
</View>
);
};
const styles = StyleSheet.create({
container: {
flex: 1,
padding: 20,
},
});
export default Flex;
Flex Direction
在组件的style中指定flexDirection可以决定布局的主轴。子元素是应该沿着**水平轴(row)方向排列,还是沿着竖直轴(column)方向排列呢?默认值是竖直轴(column)**方向。
- column(默认值):将子元素从上到下对齐。如果启用换行,则下一行将从容器顶部的第一个项目右侧开始。
- row:将子元素从左到右对齐。如果启用换行,则下一行将在容器左侧的第一个项目下方开始。
- column-reverse:将子元素从底部向上对齐。如果启用换行,则下一行将从容器底部的第一个项目右侧开始。
- row-reverse:将子元素从右到左对齐。如果启用换行,则下一行将在容器右侧的第一个项目下方开始。
import React, {
useState } from "react";
import {
StyleSheet, Text, TouchableOpacity, View } from "react-native";
const FlexDirectionBasics = () => {
const [flexDirection, setflexDirection] = useState("column");
return (
<PreviewLayout
label="flexDirection"
values={
["column", "row", "row-reverse", "column-reverse"]}
selectedValue={
flexDirection}
setSelectedValue={
setflexDirection}
>
<View
style={
[styles.box, {
backgroundColor: "powderblue" }]}
/>
<View
style={
[styles.box, {
backgroundColor: "skyblue" }]}
/>
<View
style={
[styles.box, {
backgroundColor: "steelblue" }]}
/>
</PreviewLayout>
);
};
Layout Direction
布局方向指定了层次结构中的子元素和文本应该被排列的方向。布局方向还会影响到start和end所指代的边缘。默认情况下,React Native 采用从左到右(LTR)的布局方向进行排列。在这种模式下,start表示左侧,而end表示右侧。
- LTR(默认值): 文本和子元素从左到右进行排列。对于一个元素来说,在其起始位置应用的外边距和内边距将被应用在左侧。
- RTL: 文本和子元素从右到左进行排列。对于一个元素来说,在其起始位置应用的外边距和内边距将被应用在右侧。
import React, {
useState } from "react";
import {
View, TouchableOpacity, Text, StyleSheet } from "react-native";
const DirectionLayout = () => {
const [direction, setDirection] = useState("ltr");
return (
<PreviewLayout
label="direction"
selectedValue={
direction}
values={
["ltr", "rtl"]}
setSelectedValue={
setDirection}>
<View
style={
[styles.box, {
backgroundColor: "powderblue" }]}
/>
<View
style={
[styles.box, {
backgroundColor: "skyblue" }]}
/>
<View
style={
[styles.box, {
backgroundColor: "steelblue" }]}
/>
</PreviewLayout>
);
};
const PreviewLayout = ({
label,
children,
values,
selectedValue,
setSelectedValue,
}) => (
<View style={
{
padding: 10, flex: 1 }}>
<Text style={
styles.label}>{
label}</Text>
<View style={
styles.row}>
{
values.map((value) => (
<TouchableOpacity
key={
value}
onPress={
() => setSelectedValue(value)}
style={
[
styles.button,
selectedValue === value && styles.selected,
]}
>
<Text
style={
[
styles.buttonLabel,
selectedValue === value && styles.selectedLabel,
]}
>
{
value}
</Text>
</TouchableOpacity>
))}
</View>
<View style={
[styles.container, {
[label]: selectedValue }]}>
{
children}
</View>
</View>
);
const styles = StyleSheet.create({
container: {
flex: 1,
marginTop: 8,
backgroundColor: "aliceblue",
},
box: {
width: 50,
height: 50,
},
row: {
flexDirection: "row",
flexWrap: "wrap",
},
button: {
paddingHorizontal: 8,
paddingVertical: 6,
borderRadius: 4,
backgroundColor: "oldlace",
alignSelf: "flex-start",
marginHorizontal: "1%",
marginBottom: 6,
minWidth: "48%",
textAlign: "center",
},
selected: {
backgroundColor: "coral",
borderWidth: 0,
},
buttonLabel: {
fontSize: 12,
fontWeight: "500",
color: "coral",
},
selectedLabel: {
color: "white",
},
label: {
textAlign: "center",
marginBottom: 10,
fontSize: 24,
},
});
export default DirectionLayout;
Justify Content
justifyContent可以决定其子元素沿着主轴的排列方式。子元素是应该靠近主轴的起始端还是末尾段分布呢?亦或应该均匀分布?可用的选项有:
- flex-start(默认值)将容器中的子元素沿主轴起始位置对齐。
- flex-end 将容器中的子元素沿主轴末尾位置对齐。
- center 将容器中的子元素在主轴上居中对齐。
- space-between 在容器的主轴上均匀分布子元素,将剩余空间平均分配给子元素之间
- space-around 在容器的主轴上均匀分布子元素,将剩余空间围绕在每个子元素周围。与space-between相比,使用space-around会导致空间被分配到第一个子元素和最后一个子元素之前和之后。
- space-evenly 在对齐容器内沿着主轴均匀分布子项。每一对相邻项、主开始边缘和第一项以及主结束边缘和最后一项之间的间距都完全相同。
import React, {
useState } from "react";
import {
View, TouchableOpacity, Text, StyleSheet } from "react-native";
const JustifyContentBasics = () => {
const [justifyContent, setJustifyContent] = useState("flex-start");
return (
<PreviewLayout
label="justifyContent"
selectedValue={
justifyContent}
values={
[
"flex-start",
"flex-end",
"center",
"space-between",
"space-around",
"space-evenly",
]}
setSelectedValue={
setJustifyContent}
>
<View
style={
[styles.box, {
backgroundColor: "powderblue" }]}
/>
<View
style={
[styles.box, {
backgroundColor: "skyblue" }]}
/>
<View
style={
[styles.box, {
backgroundColor: "steelblue" }]}
/>
</PreviewLayout>
);
};
const PreviewLayout = ({
label,
children,
values,
selectedValue,
setSelectedValue,
}) => (
<View style={
{
padding: 10, flex: 1 }}>
<Text style={
styles.label}>{
label}</Text>
<View style={
styles.row}>
{
values.map((value) => (
<TouchableOpacity
key={
value}
onPress={
() => setSelectedValue(value)}
style={
[styles.button, selectedValue === value && styles.selected]}
>
<Text
style={
[
styles.buttonLabel,
selectedValue === value && styles.selectedLabel,
]}
>
{
value}
</Text>
</TouchableOpacity>
))}
</View>
<View style={
[styles.container, {
[label]: selectedValue }]}>
{
children}
</View>
</View>
);
const styles = StyleSheet.create({
container: {
flex: 1,
marginTop: 8,
backgroundColor: "aliceblue",
},
box: {
width: 50,
height: 50,
},
row: {
flexDirection: "row",
flexWrap: "wrap",
},
button: {
paddingHorizontal: 8,
paddingVertical: 6,
borderRadius: 4,