id | title |
---|---|
flexbox |
使用 Flexbox 布局 |
import Tabs from '@theme/Tabs'; import TabItem from '@theme/TabItem'; import constants from '@site/core/TabsConstants';
我们在 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: 1
的容器 view 中,有红色,黄色和绿色三个子 view。红色 view 设置了flex: 1
,黄色 view 设置了flex: 2
,绿色 view 设置了flex: 3
。1+2+3 = 6,这意味着红色 view 占据整个区域的1/6
,黄色 view 占据整个区域的2/6
,绿色 view 占据整个区域的3/6
。
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 style={{ flex: 2, backgroundColor: "darkorange" }} />
<View style={{ flex: 3, backgroundColor: "green" }} />
</View>
);
};
const styles = StyleSheet.create({
container: {
flex: 1,
padding: 20,
},
});
export default Flex;
在组件的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>
);
};
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 FlexDirectionBasics;
布局方向指定了层次结构中的子元素和文本应该被排列的方向。布局方向还会影响到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;
在组件的 style 中指定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,
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 JustifyContentBasics;
在组件的 style 中指定alignItems
可以决定其子元素沿着次轴(与主轴垂直的轴,比如若主轴方向为row
,则次轴方向为column
)的排列方式。子元素是应该靠近次轴的起始端还是末尾段分布呢?亦或应该均匀分布?可用的选项有:
-
stretch
(默认值):将容器的子元素拉伸以匹配容器次轴的高度。 -
flex-start
:将容器的子元素对齐到容器次轴的起始位置。 -
flex-end
:将容器的子元素对齐到容器次轴的末尾位置。 -
center
:将容器的子元素居中对齐于容器次轴上。 -
baseline
:沿着公共基线对齐容器的子元素。可以为各个子元素设置参考基线,作为其父级基线。
:::info 提示
要使stretch
选项生效,子元素在次轴方向上不能有固定尺寸。例如下面这段代码: 只有当从子元素样式中移除了'width: 50'后, 'alignItems: 'stretch'' 才会生效.
:::
您可以在此处了解更多信息。
import React, { useState } from "react";
import {
View,
TouchableOpacity,
Text,
StyleSheet,
} from "react-native";
const AlignItemsLayout = () => {
const [alignItems, setAlignItems] = useState("stretch");
return (
<PreviewLayout
label="alignItems"
selectedValue={alignItems}
values={[
"stretch",
"flex-start",
"flex-end",
"center",
"baseline",
]}
setSelectedValue={setAlignItems}
>
<View
style={[styles.box, { backgroundColor: "powderblue" }]}
/>
<View
style={[styles.box, { backgroundColor: "skyblue" }]}
/>
<View
style={[
styles.box,
{
backgroundColor: "steelblue",
width: "auto",
minWidth: 50,
},
]}
/>
</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",
minHeight: 200,
},
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 AlignItemsLayout;
alignSelf
(布局属性#alignself)与 alignItems
具有相同的选项和效果,但不是影响容器内的子元素,而是可以将此属性应用于单个子元素以更改其在父级中的对齐方式。 alignSelf
会覆盖由父级设置的任何使用 alignItems
的选项。
import React, { useState } from "react";
import { View, TouchableOpacity, Text, StyleSheet } from "react-native";
const AlignSelfLayout = () => {
const [alignSelf, setAlignSelf] = useState("stretch");
return (
<PreviewLayout
label="alignSelf"
selectedValue={alignSelf}
values={["stretch", "flex-start", "flex-end", "center", "baseline"]}
setSelectedValue={setAlignSelf}>
<View
style={[styles.box, {
alignSelf,
width: "auto",
minWidth: 50,
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}>
{children}
</View>
</View>
);
const styles = StyleSheet.create({
container: {
flex: 1,
marginTop: 8,
backgroundColor: "aliceblue",
minHeight: 200,
},
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 AlignSelfLayout;
alignContent 定义了沿次轴分布行的方式。只有在使用 flexWrap
将项目换行到多个行时才会生效。
-
flex-start
(默认值):将换行后的行与容器的次轴起始位置对齐。 -
flex-end
:将换行后的行与容器的次轴末尾位置对齐。 -
stretch
(在 Web 上使用 Yoga 时的默认值):拉伸换行后的行以匹配容器的次轴高度。 -
center
:将换行后的行居中对齐于容器的次轴。 -
space-between
:均匀地在容器的次轴上间隔排列换行后的各个线,使剩余空间平均分布在这些线之间。 -
space-around
:均匀地在容器的次轴上间隔排列换行后各个线,使剩余空间平均分布在这些线周围。相较于使用space-between
,使用space-around
会导致空白区域被分配到第一条线和最后一条线之前及之后两端。
您可以点击此处了解更多信息。
import React, { useState } from "react";
import { View, TouchableOpacity, Text, StyleSheet } from "react-native";
const AlignContentLayout = () => {
const [alignContent, setAlignContent] = useState("flex-start");
return (
<PreviewLayout
label="alignContent"
selectedValue={alignContent}
values={[
"flex-start",
"flex-end",
"stretch",
"center",
"space-between",
"space-around",
]}
setSelectedValue={setAlignContent}>
<View
style={[styles.box, { backgroundColor: "orangered" }]}
/>
<View
style={[styles.box, { backgroundColor: "orange" }]}
/>
<View
style={[styles.box, { backgroundColor: "mediumseagreen" }]}
/>
<View
style={[styles.box, { backgroundColor: "deepskyblue" }]}
/>
<View
style={[styles.box, { backgroundColor: "mediumturquoise" }]}
/>
<View
style={[styles.box, { backgroundColor: "mediumslateblue" }]}
/>
<View
style={[styles.box, { backgroundColor: "purple" }]}
/>
</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,
flexWrap: "wrap",
marginTop: 8,
backgroundColor: "aliceblue",
maxHeight: 400,
},
box: {
width: 50,
height: 80,
},
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 AlignContentLayout;
flexWrap
属性用于设置容器的换行方式,它控制了当子元素超出容器在主轴上的尺寸时要如何处理。默认情况下,子元素被强制放置在一行中(这可能会使元素被挤压)。如果允许换行,则项目将根据需要沿主轴分为多行。
在换行时,可以使用alignContent
来设置这些行在容器中的排列方式。详细信息请参阅此处。
import React, { useState } from "react";
import { View, TouchableOpacity, Text, StyleSheet } from "react-native";
const FlexWrapLayout = () => {
const [flexWrap, setFlexWrap] = useState("wrap");
return (
<PreviewLayout
label="flexWrap"
selectedValue={flexWrap}
values={["wrap", "nowrap"]}
setSelectedValue={setFlexWrap}>
<View
style={[styles.box, { backgroundColor: "orangered" }]}
/>
<View
style={[styles.box, { backgroundColor: "orange" }]}
/>
<View
style={[styles.box, { backgroundColor: "mediumseagreen" }]}
/>
<View
style={[styles.box, { backgroundColor: "deepskyblue" }]}
/>
<View
style={[styles.box, { backgroundColor: "mediumturquoise" }]}
/>
<View
style={[styles.box, { backgroundColor: "mediumslateblue" }]}
/>
<View
style={[styles.box, { backgroundColor: "purple" }]}
/>
</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",
maxHeight: 400,
},
box: {
width: 50,
height: 80,
},
row: {
flexDirection: "row",
flexWrap: "wrap",
},
button: {
paddingHorizontal: 8,
paddingVertical: 6,
borderRadius: 4,
backgroundColor: "oldlace",
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 FlexWrapLayout;
-
flexBasis
是一种独立于轴线的方式,用于提供项目沿主轴的默认大小。如果父容器具有flexDirection: row
,则设置子项的flexBasis
类似于设置该子项的width
;如果父容器具有flexDirection: column
,则设置子项的flexBasis
类似于设置该子项的height
。项目的flexBasis
是在执行任何flexGrow
和flexShrink
计算之前该项目的默认大小。 -
flexGrow
描述了在主轴上如何分配容器中剩余空间给其子项。布局完其子项后,容器将根据其子项指定的 flex grow 值来分配任何剩余空间。flexGrow
接受大于等于 0 的任意浮点数值,默认值为 0。容器将按照各个子项的 flex grow 值加权分配剩余空间给它们。 -
flexShrink
描述了当所有子项总尺寸超过主轴上容器尺寸时,在溢出情况下如何收缩各个子项。如果将溢出尺寸视为负剩余空间,则可以认为 flex shrink 和 flex grow 的工作方式非常相似。这两个属性也能很好地配合使用,允许子项根据需要进行伸缩。flexShrink
接受大于等于 0 的任意浮点数值,默认值为 0(在 Web 上,默认值为 1)。容器将按照各个子项的 flex shrink 值加权收缩它们。
您可以在这里了解更多信息。
import React, { useState } from "react";
import {
View,
Text,
TextInput,
StyleSheet,
} from "react-native";
const App = () => {
const [powderblue, setPowderblue] = useState({
flexGrow: 0,
flexShrink: 1,
flexBasis: "auto",
});
const [skyblue, setSkyblue] = useState({
flexGrow: 1,
flexShrink: 0,
flexBasis: 100,
});
const [steelblue, setSteelblue] = useState({
flexGrow: 0,
flexShrink: 1,
flexBasis: 200,
});
return (
<View style={styles.container}>
<View
style={[
styles.container,
{
flexDirection: "row",
alignContent: "space-between",
},
]}
>
<BoxInfo
color="powderblue"
{...powderblue}
setStyle={setPowderblue}
/>
<BoxInfo
color="skyblue"
{...skyblue}
setStyle={setSkyblue}
/>
<BoxInfo
color="steelblue"
{...steelblue}
setStyle={setSteelblue}
/>
</View>
<View style={styles.previewContainer}>
<View
style={[
styles.box,
{
flexBasis: powderblue.flexBasis,
flexGrow: powderblue.flexGrow,
flexShrink: powderblue.flexShrink,
backgroundColor: "powderblue",
},
]}
/>
<View
style={[
styles.box,
{
flexBasis: skyblue.flexBasis,
flexGrow: skyblue.flexGrow,
flexShrink: skyblue.flexShrink,
backgroundColor: "skyblue",
},
]}
/>
<View
style={[
styles.box,
{
flexBasis: steelblue.flexBasis,
flexGrow: steelblue.flexGrow,
flexShrink: steelblue.flexShrink,
backgroundColor: "steelblue",
},
]}
/>
</View>
</View>
);
};
const BoxInfo = ({
color,
flexBasis,
flexShrink,
setStyle,
flexGrow,
}) => (
<View style={[styles.row, { flexDirection: "column" }]}>
<View
style={[
styles.boxLabel,
{
backgroundColor: color,
},
]}
>
<Text
style={{
color: "#fff",
fontWeight: "500",
textAlign: "center",
}}
>
Box
</Text>
</View>
<Text style={styles.label}>flexBasis</Text>
<TextInput
value={flexBasis}
style={styles.input}
onChangeText={(fB) =>
setStyle((value) => ({
...value,
flexBasis: isNaN(parseInt(fB))
? "auto"
: parseInt(fB),
}))
}
/>
<Text style={styles.label}>flexShrink</Text>
<TextInput
value={flexShrink}
style={styles.input}
onChangeText={(fS) =>
setStyle((value) => ({
...value,
flexShrink: isNaN(parseInt(fS))
? ""
: parseInt(fS),
}))
}
/>
<Text style={styles.label}>flexGrow</Text>
<TextInput
value={flexGrow}
style={styles.input}
onChangeText={(fG) =>
setStyle((value) => ({
...value,
flexGrow: isNaN(parseInt(fG))
? ""
: parseInt(fG),
}))
}
/>
</View>
);
const styles = StyleSheet.create({
container: {
flex: 1,
paddingHorizontal: 10,
},
box: {
flex: 1,
height: 50,
width: 50,
},
boxLabel: {
minWidth: 80,
padding: 8,
borderRadius: 4,
marginTop: 8,
},
label: {
marginTop: 6,
fontSize: 16,
fontWeight: "100",
},
previewContainer: {
flex: 1,
flexDirection: "row",
backgroundColor: "aliceblue",
},
row: {
flex: 1,
flexDirection: "row",
flexWrap: "wrap",
alignItems: "center",
marginBottom: 10,
},
input: {
borderBottomWidth: 1,
paddingVertical: 3,
width: 50,
textAlign: "center",
},
});
export default App;
-
rowGap
设置元素行之间的间隙(gutter)大小。 -
columnGap
设置元素列之间的间隙(gutter)大小。 -
gap
设置行和列之间的间隙(gutter)大小。它是rowGap
和columnGap
的简写形式。
您可以使用 flexWrap
和 alignContent
以及 gap
来为项目添加一致的间距。
import React, {useState} from 'react';
import {View, Text, StyleSheet, TextInput} from 'react-native';
const RowGapAndColumnGap = () => {
const [rowGap, setRowGap] = useState(10);
const [columnGap, setColumnGap] = useState(10);
return (
<PreviewLayout
columnGap={columnGap}
handleColumnGapChange={setColumnGap}
rowGap={rowGap}
handleRowGapChange={setRowGap}>
<View style={[styles.box, styles.box1]} />
<View style={[styles.box, styles.box2]} />
<View style={[styles.box, styles.box3]} />
<View style={[styles.box, styles.box4]} />
<View style={[styles.box, styles.box5]} />
</PreviewLayout>
);
};
const PreviewLayout = ({
children,
handleColumnGapChange,
handleRowGapChange,
rowGap,
columnGap,
}) => (
<View style={styles.previewContainer}>
<View style={styles.inputContainer}>
<View style={styles.itemsCenter}>
<Text>Row Gap</Text>
<TextInput
style={styles.input}
value={rowGap}
onChangeText={v => handleRowGapChange(Number(v))}
/>
</View>
<View style={styles.itemsCenter}>
<Text>Column Gap</Text>
<TextInput
style={styles.input}
value={columnGap}
onChangeText={v => handleColumnGapChange(Number(v))}
/>
</View>
</View>
<View style={[styles.container, {rowGap, columnGap}]}>{children}</View>
</View>
);
const styles = StyleSheet.create({
itemsCenter: {alignItems: 'center'},
inputContainer: {
gap: 4,
flexDirection: 'row',
justifyContent: 'space-around',
},
previewContainer: {padding: 10, flex: 1},
input: {
borderBottomWidth: 1,
paddingVertical: 3,
width: 50,
textAlign: 'center',
},
container: {
flex: 1,
marginTop: 8,
backgroundColor: 'aliceblue',
maxHeight: 400,
flexWrap: 'wrap',
alignContent: 'flex-start',
},
box: {
width: 50,
height: 80,
},
box1: {
backgroundColor: 'orangered',
},
box2: {
backgroundColor: 'orange',
},
box3: {
backgroundColor: 'mediumseagreen',
},
box4: {
backgroundColor: 'deepskyblue',
},
box5: {
backgroundColor: 'mediumturquoise',
},
});
export default RowGapAndColumnGap;
import React, {useState} from 'react';
import {View, Text, StyleSheet, TextInput} from 'react-native';
import type {PropsWithChildren} from 'react';
const RowGapAndColumnGap = () => {
const [rowGap, setRowGap] = useState(10);
const [columnGap, setColumnGap] = useState(10);
return (
<PreviewLayout
columnGap={columnGap}
handleColumnGapChange={setColumnGap}
rowGap={rowGap}
handleRowGapChange={setRowGap}>
<View style={[styles.box, styles.box1]} />
<View style={[styles.box, styles.box2]} />
<View style={[styles.box, styles.box3]} />
<View style={[styles.box, styles.box4]} />
<View style={[styles.box, styles.box5]} />
</PreviewLayout>
);
};
type PreviewLayoutProps = PropsWithChildren<{
columnGap: number;
handleColumnGapChange: (gap: number) => void;
rowGap: number;
handleRowGapChange: (gap: number) => void;
}>;
const PreviewLayout = ({
children,
handleColumnGapChange,
handleRowGapChange,
rowGap,
columnGap,
}: PreviewLayoutProps) => (
<View style={styles.previewContainer}>
<View style={styles.inputContainer}>
<View style={styles.itemsCenter}>
<Text>Row Gap</Text>
<TextInput
style={styles.input}
value={String(rowGap)}
onChangeText={v => handleRowGapChange(Number(v))}
/>
</View>
<View style={styles.itemsCenter}>
<Text>Column Gap</Text>
<TextInput
style={styles.input}
value={String(columnGap)}
onChangeText={v => handleColumnGapChange(Number(v))}
/>
</View>
</View>
<View style={[styles.container, {rowGap, columnGap}]}>{children}</View>
</View>
);
const styles = StyleSheet.create({
itemsCenter: {alignItems: 'center'},
inputContainer: {
gap: 4,
flexDirection: 'row',
justifyContent: 'space-around',
},
previewContainer: {padding: 10, flex: 1},
input: {
borderBottomWidth: 1,
paddingVertical: 3,
width: 50,
textAlign: 'center',
},
container: {
flex: 1,
marginTop: 8,
backgroundColor: 'aliceblue',
maxHeight: 400,
flexWrap: 'wrap',
alignContent: 'flex-start',
},
box: {
width: 50,
height: 80,
},
box1: {
backgroundColor: 'orangered',
},
box2: {
backgroundColor: 'orange',
},
box3: {
backgroundColor: 'mediumseagreen',
},
box4: {
backgroundColor: 'deepskyblue',
},
box5: {
backgroundColor: 'mediumturquoise',
},
});
export default RowGapAndColumnGap;
width
属性指定元素内容区域的宽度。同样,height
属性指定元素内容区域的高度。
width
和height
都可以取以下值:
-
auto
(默认值)React Native 根据元素的内容计算其宽度/高度,无论是其他子元素、文本还是图像。 -
pixels
以绝对像素定义宽度/高度。根据组件上设置的其他样式,这可能是节点最终尺寸也可能不是。 -
percentage
分别以父级宽度或高度的百分比定义宽度或高度。
import React, { useState } from "react";
import {
View,
SafeAreaView,
TouchableOpacity,
Text,
StyleSheet,
} from "react-native";
const WidthHeightBasics = () => {
const [widthType, setWidthType] = useState("auto");
const [heightType, setHeightType] = useState("auto");
return (
<PreviewLayout
widthType={widthType}
heightType={heightType}
widthValues={["auto", 300, "80%"]}
heightValues={["auto", 200, "60%"]}
setWidthType={setWidthType}
setHeightType={setHeightType}
>
<View
style={{
alignSelf: "flex-start",
backgroundColor: "aliceblue",
height: heightType,
width: widthType,
padding: 15,
}}
>
<View
style={[
styles.box,
{ backgroundColor: "powderblue" },
]}
/>
<View
style={[
styles.box,
{ backgroundColor: "skyblue" },
]}
/>
<View
style={[
styles.box,
{ backgroundColor: "steelblue" },
]}
/>
</View>
</PreviewLayout>
);
};
const PreviewLayout = ({
children,
widthType,
heightType,
widthValues,
heightValues,
setWidthType,
setHeightType,
}) => (
<View style={{ flex: 1, padding: 10 }}>
<View style={styles.row}>
<Text style={styles.label}>width </Text>
{widthValues.map((value) => (
<TouchableOpacity
key={value}
onPress={() => setWidthType(value)}
style={[
styles.button,
widthType === value && styles.selected,
]}
>
<Text
style={[
styles.buttonLabel,
widthType === value && styles.selectedLabel,
]}
>
{value}
</Text>
</TouchableOpacity>
))}
</View>
<View style={styles.row}>
<Text style={styles.label}>height </Text>
{heightValues.map((value) => (
<TouchableOpacity
key={value}
onPress={() => setHeightType(value)}
style={[
styles.button,
heightType === value && styles.selected,
]}
>
<Text
style={[
styles.buttonLabel,
heightType === value && styles.selectedLabel,
]}
>
{value}
</Text>
</TouchableOpacity>
))}
</View>
{children}
</View>
);
const styles = StyleSheet.create({
box: {
width: 50,
height: 50,
},
row: {
flexDirection: "row",
flexWrap: "wrap",
},
button: {
padding: 8,
borderRadius: 4,
backgroundColor: "oldlace",
alignSelf: "flex-start",
marginRight: 10,
marginBottom: 10,
},
selected: {
backgroundColor: "coral",
shadowOpacity: 0,
borderWidth: 0,
},
buttonLabel: {
fontSize: 12,
fontWeight: "500",
color: "coral",
},
selectedLabel: {
color: "white",
},
label: {
textAlign: "center",
marginBottom: 10,
fontSize: 24,
},
});
export default WidthHeightBasics;
position
类型定义了元素在其父元素中的定位方式。
-
relative
(默认值) 默认情况下,一个元素是相对定位的。这意味着一个元素根据布局的正常流程进行定位,然后根据top
、right
、bottom
和left
的值进行偏移。该偏移不会影响任何兄弟或父级元素的位置。 -
absolute
绝对定位时,一个元素不参与正常布局流程。它独立于其兄弟元素进行布局。位置是基于top
,right
,bottom
, 和 'left' 值来确定的。
import React, { useState } from "react";
import {
View,
SafeAreaView,
TouchableOpacity,
Text,
StyleSheet,
} from "react-native";
const PositionLayout = () => {
const [position, setPosition] = useState("relative");
return (
<PreviewLayout
label="position"
selectedValue={position}
values={["relative", "absolute"]}
setSelectedValue={setPosition}
>
<View
style={[
styles.box,
{
top: 25,
left: 25,
position,
backgroundColor: "powderblue",
},
]}
/>
<View
style={[
styles.box,
{
top: 50,
left: 50,
position,
backgroundColor: "skyblue",
},
]}
/>
<View
style={[
styles.box,
{
top: 75,
left: 75,
position,
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}>{children}</View>
</View>
);
const styles = StyleSheet.create({
container: {
flex: 1,
marginTop: 8,
backgroundColor: "aliceblue",
minHeight: 200,
},
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 PositionLayout;
Check out the interactive yoga playground that you can use to get a better understanding of flexbox.
以上我们已经介绍了一些基础知识,但要运用好布局,我们还需要很多其他的样式。对于布局有影响的完整样式列表记录在这篇文档中。
现在我们已经差不多可以开始真正的开发工作了。哦,忘了还有个常用的知识点:如何使用 TextInput 组件来处理用户输入。