React Native 样式与布局
样式
在 React Native 中,仍然是使用 JavaScript 来写样式,所有的核心组件都接受名为 style 的属性,这些样式名基本上都遵循 web 上的 CSS 属性名
RN 中的样式与 CSS 的不同
1、没有继承性
RN 中的继承只发生在 Text 组件上
2、样式名采用小驼峰命名
fontSize VS font-size
3、所有尺寸都没有单位
width: 100
4、有一些特殊的样式名
marginHorizontal(水平外边距), marginVertical (垂直外边距)
RN 样式的声明方式
1、通过 style 属性直接声明
属性值为对象:<组件 style={{样式}} />
属性值为数组:<组件 style={[{样式1}, ..., {样式N}]} />
2、在 style 属性中调用 StyleSheet 声明的样式
引入:import {StyleSheet, View} from 'react-native'
声明:const styles = StyleSheet.create({foo: {样式1}, bar: {样式2}})
使用:<View style={[styles.foo, styles.bar]}>内容</View>
import {StyleSheet, Text, View} from 'react-native'; import React, {Component} from 'react'; export default class index extends Component { render() { return ( <View> <Text style={{fontSize: 60}}>index</Text> <Text style={[{color: 'red'}, {fontSize: 30}]}>React Native</Text> <Text style={[{color: 'red'}, {color: 'green'}]}>React Native</Text> <Text style={styles.mainTitle}>Flutter</Text> <Text style={[styles.subTitle]}>React</Text> </View> ); } } const styles = StyleSheet.create({ mainTitle: { fontSize: 40, // number 类型 fontWeight: 'bold', // string 类型 marginVertical: 30, // number 类型 }, subTitle: { fontSize: 20, fontWeight: '400', // string 类型 }, });
使用 Flexbox 布局
在 RN 中使用 flexbox 规则来指定某个组件的子元素的布局,flexbox 可以在不同屏幕尺寸上提供一致的布局结构
flexbox 术语
容器(container)
采用 flex 布局的元素,称为 flex 容器,简称 容器
项目(item)
容器所有的子元素,称为 flex 项目,简称 项目
主轴(main axis)
交叉轴(cross axis)
![](https://img2022.cnblogs.com/blog/997093/202209/997093-20220901135634446-1826327306.png)
flexbox 属性
flex
flex 属性决定元素在主轴上如何 填满 可用区域。整个区域会根据每个元素设置的 flex 属性值被分割成多个部分
在下面的例子中,在设置了宽高为100%的容器中,有红色、黄色和绿色三个子 View,红色设置了 flex:1,黄色设置了 flex:2,绿色设置了 flex:3,这意味着 红色 view 占据整个容器的 1/6,黄色 view 占据整个容器的 2/6,绿色 view 占据整个容器的 3/6
import React from 'react'; import {View, StyleSheet, Dimensions} from 'react-native'; const Flex = () => { return ( <View style={[styles.container]}> <View style={{flex: 1, backgroundColor: 'red'}} /> <View style={{flex: 2, backgroundColor: 'darkorange'}} /> <View style={{flex: 3, backgroundColor: 'green'}} /> </View> ); }; const styles = StyleSheet.create({ container: { width: Dimensions.get('window').width, height: Dimensions.get('window').height, padding: 20, backgroundColor: '#f0f0f0', }, }); export default Flex;
flexDirection
声明主轴的方向,子元素是应该沿着 水平轴(row)方向排列,还是沿着 竖直轴(column)方向排列
在 Web 里默认是 水平轴(row),在 RN 里默认是 垂直轴(column)
import React from 'react'; import {View, Text, StyleSheet} from 'react-native'; const FlexDirection = () => { return ( <View> <View style={styles.card}> <Text style={styles.title}>flexDirection: column(默认)</Text> <View style={[styles.container, {flexDirection: 'column'}]}> <View style={[styles.box, {backgroundColor: 'powderblue'}]} /> <View style={[styles.box, {backgroundColor: 'skyblue'}]} /> <View style={[styles.box, {backgroundColor: 'steelblue'}]} /> </View> </View> <View style={styles.card}> <Text style={styles.title}>flexDirection: row</Text> <View style={[styles.container, {flexDirection: 'row'}]}> <View style={[styles.box, {backgroundColor: 'powderblue'}]} /> <View style={[styles.box, {backgroundColor: 'skyblue'}]} /> <View style={[styles.box, {backgroundColor: 'steelblue'}]} /> </View> </View> <View style={styles.card}> <Text style={styles.title}>flexDirection: row-reverse</Text> <View style={[styles.container, {flexDirection: 'row-reverse'}]}> <View style={[styles.box, {backgroundColor: 'powderblue'}]} /> <View style={[styles.box, {backgroundColor: 'skyblue'}]} /> <View style={[styles.box, {backgroundColor: 'steelblue'}]} /> </View> </View> <View style={styles.card}> <Text style={styles.title}>flexDirection: column-reverse</Text> <View style={[styles.container, {flexDirection: 'column-reverse'}]}> <View style={[styles.box, {backgroundColor: 'powderblue'}]} /> <View style={[styles.box, {backgroundColor: 'skyblue'}]} /> <View style={[styles.box, {backgroundColor: 'steelblue'}]} /> </View> </View> </View> ); }; const styles = StyleSheet.create({ title: { textAlign: 'center', fontSize: 24, fontWeight: '600', }, card: { marginTop: 10, backgroundColor: 'oldlace', }, container: { marginTop: 10, }, box: { width: 50, height: 50, }, }); export default FlexDirection;
justifyContent
在组件的 style 中指定 justifyContent 可以决定其子元素沿着 主轴 的排列方式
取值:
flex-start: 默认值,左对齐
flex-end: 右对齐
center: 居中
space-between: 两端对齐,项目之间的间隔都相等
space-around: 每个项目两侧的间隔相等。所以,项目之间的间隔比项目与两端的间隔大一倍
space-evenly:每个项目之间的间隔相等,均匀排列每个项目
import React from 'react'; import {View, Text, StyleSheet} from 'react-native'; const JustifyContent = () => { return ( <View> <View style={styles.card}> <Text style={styles.title}>justifyContent: flex-start</Text> <View style={[styles.container, {justifyContent: 'flex-start'}]}> <View style={[styles.box, {backgroundColor: 'powderblue'}]} /> <View style={[styles.box, {backgroundColor: 'skyblue'}]} /> <View style={[styles.box, {backgroundColor: 'steelblue'}]} /> </View> </View> <View style={styles.card}> <Text style={styles.title}>justifyContent: flex-end</Text> <View style={[styles.container, {justifyContent: 'flex-end'}]}> <View style={[styles.box, {backgroundColor: 'powderblue'}]} /> <View style={[styles.box, {backgroundColor: 'skyblue'}]} /> <View style={[styles.box, {backgroundColor: 'steelblue'}]} /> </View> </View> <View style={styles.card}> <Text style={styles.title}>justifyContent: center</Text> <View style={[styles.container, {justifyContent: 'center'}]}> <View style={[styles.box, {backgroundColor: 'powderblue'}]} /> <View style={[styles.box, {backgroundColor: 'skyblue'}]} /> <View style={[styles.box, {backgroundColor: 'steelblue'}]} /> </View> </View> <View style={styles.card}> <Text style={styles.title}>justifyContent: space-between</Text> <View style={[styles.container, {justifyContent: 'space-between'}]}> <View style={[styles.box, {backgroundColor: 'powderblue'}]} /> <View style={[styles.box, {backgroundColor: 'skyblue'}]} /> <View style={[styles.box, {backgroundColor: 'steelblue'}]} /> </View> </View> <View style={styles.card}> <Text style={styles.title}>justifyContent: space-around</Text> <View style={[styles.container, {justifyContent: 'space-around'}]}> <View style={[styles.box, {backgroundColor: 'powderblue'}]} /> <View style={[styles.box, {backgroundColor: 'skyblue'}]} /> <View style={[styles.box, {backgroundColor: 'steelblue'}]} /> </View> </View> <View style={styles.card}> <Text style={styles.title}>justifyContent: space-evenly</Text> <View style={[styles.container, {justifyContent: 'space-evenly'}]}> <View style={[styles.box, {backgroundColor: 'powderblue'}]} /> <View style={[styles.box, {backgroundColor: 'skyblue'}]} /> <View style={[styles.box, {backgroundColor: 'steelblue'}]} /> </View> </View> </View> ); }; const styles = StyleSheet.create({ title: { textAlign: 'center', fontSize: 24, fontWeight: '600', }, card: { marginTop: 10, backgroundColor: 'oldlace', }, container: { marginTop: 10, flexDirection: 'row', }, box: { width: 50, height: 50, }, }); export default JustifyContent;
alignItems
在组件的 style 中指定 alignItems 可以决定其子元素沿着 交叉轴 的排列方式
取值:
stretch: 默认值,根据容器交叉轴的高度撑满容器子元素
注意:要使 stretch 选项生效的话,子元素在 交叉轴 方向上不能有固定的尺寸
flex-end: 右对齐
center: 居中
space-between: 两端对齐,项目之间的间隔都相等
space-around: 每个项目两侧的间隔相等。所以,项目之间的间隔比项目与两端的间隔大一倍
space-evenly:每个项目之间的间隔相等,均匀排列每个项目
alignSelf
alignSelf 和 alignItems 具有相同的取值属性和作用,区别是:
alignItems 作用于容器下所有的子元素
alignSelf 作用于单个子元素,并且会覆盖 alignItems 指定的属性
import React from 'react'; import {View, Text, ScrollView, StyleSheet} from 'react-native'; const AlignItems = () => { return ( <ScrollView> <View style={styles.card}> <Text style={styles.title}>alignItems: stretch(默认)</Text> <View style={[styles.container, {alignItems: 'stretch'}]}> <View style={[styles.box, {backgroundColor: 'powderblue'}]} /> <View style={[styles.box, {backgroundColor: 'skyblue'}]} /> <View style={[styles.box, {backgroundColor: 'steelblue'}]} /> </View> </View> <View style={styles.card}> <Text style={styles.title}>alignItems: flex-start</Text> <View style={[styles.container, {alignItems: 'flex-start'}]}> <View style={[styles.box, {backgroundColor: 'powderblue'}]} /> <View style={[styles.box, {backgroundColor: 'skyblue'}]} /> <View style={[styles.box, {backgroundColor: 'steelblue'}]} /> </View> </View> <View style={styles.card}> <Text style={styles.title}>alignItems: flex-end</Text> <View style={[styles.container, {alignItems: 'flex-end'}]}> <View style={[styles.box, {backgroundColor: 'powderblue'}]} /> <View style={[styles.box, {backgroundColor: 'skyblue'}]} /> <View style={[styles.box, {backgroundColor: 'steelblue'}]} /> </View> </View> <View style={styles.card}> <Text style={styles.title}>alignItems: center</Text> <View style={[styles.container, {alignItems: 'center'}]}> <View style={[styles.box, {backgroundColor: 'powderblue'}]} /> <View style={[styles.box, {backgroundColor: 'skyblue'}]} /> <View style={[styles.box, {backgroundColor: 'steelblue'}]} /> </View> </View> <View style={styles.card}> <Text style={styles.title}>alignItems: baseline</Text> <View style={[styles.container, {alignItems: 'baseline'}]}> <View style={[styles.box, {backgroundColor: 'powderblue'}]} /> <View style={[styles.box, {backgroundColor: 'skyblue'}]} /> <View style={[styles.box, {backgroundColor: 'steelblue'}]} /> </View> </View> <View style={styles.card}> <Text style={styles.title}>alignItems: baseline vs</Text> <Text style={styles.title}>alignSelf: center</Text> <View style={[styles.container, {alignItems: 'baseline'}]}> <View style={[styles.box, {backgroundColor: 'powderblue'}]} /> <View style={[ styles.box, {backgroundColor: 'skyblue', alignSelf: 'center'}, ]} /> <View style={[styles.box, {backgroundColor: 'steelblue'}]} /> </View> </View> </ScrollView> ); }; const styles = StyleSheet.create({ title: { textAlign: 'center', fontSize: 24, fontWeight: '600', }, card: { marginTop: 10, backgroundColor: 'oldlace', }, container: { marginTop: 10, }, box: { minWidth: 50, height: 50, }, }); export default AlignItems;
flexWrap
flexWrap 属性作用于容器上,控制子元素溢出时如何在主轴上排列。默认是强制不换行
import React from 'react'; import {View, Text, StyleSheet} from 'react-native'; const FlexWrap = () => { return ( <View> <View style={styles.card}> <Text style={styles.title}>flexWrap: nowrap(默认)</Text> <View style={[styles.container, {flexWrap: 'nowrap'}]}> <View style={[styles.box, {backgroundColor: 'powderblue'}]} /> <View style={[styles.box, {backgroundColor: 'skyblue'}]} /> <View style={[styles.box, {backgroundColor: 'steelblue'}]} /> <View style={[styles.box, {backgroundColor: 'aquamarine'}]} /> <View style={[styles.box, {backgroundColor: 'cadetblue'}]} /> </View> </View> <View style={styles.card}> <Text style={styles.title}>flexWrap: wrap</Text> <View style={[styles.container, {flexWrap: 'wrap'}]}> <View style={[styles.box, {backgroundColor: 'powderblue'}]} /> <View style={[styles.box, {backgroundColor: 'skyblue'}]} /> <View style={[styles.box, {backgroundColor: 'steelblue'}]} /> <View style={[styles.box, {backgroundColor: 'aquamarine'}]} /> <View style={[styles.box, {backgroundColor: 'cadetblue'}]} /> </View> </View> <View style={styles.card}> <Text style={styles.title}>flexWrap: wrap-reverse</Text> <View style={[styles.container, {flexWrap: 'wrap-reverse'}]}> <View style={[styles.box, {backgroundColor: 'powderblue'}]} /> <View style={[styles.box, {backgroundColor: 'skyblue'}]} /> <View style={[styles.box, {backgroundColor: 'steelblue'}]} /> <View style={[styles.box, {backgroundColor: 'aquamarine'}]} /> <View style={[styles.box, {backgroundColor: 'cadetblue'}]} /> </View> </View> </View> ); }; const styles = StyleSheet.create({ title: { textAlign: 'center', fontSize: 24, fontWeight: '600', }, card: { marginTop: 10, backgroundColor: 'oldlace', }, container: { marginTop: 10, flexDirection: 'row', }, box: { width: 100, height: 100, }, }); export default FlexWrap;
相对定位与绝对定位
一个元素的position类型决定了其在父元素中的位置
position 取值:
relative:(默认值),元素的位置取决于文档流
absolute:元素会脱离正常的文档流
import {StyleSheet, Text, View} from 'react-native'; import React from 'react'; export default function Position() { return ( <View> <View style={styles.card}> <Text style={styles.title}>position:relative(默认)</Text> <View style={[styles.container]}> <View style={[styles.box, styles.box1]} /> <View style={[styles.box, styles.box2]} /> <View style={[styles.box, styles.box3]} /> </View> </View> <View style={styles.card}> <Text style={styles.title}>position: absolute</Text> <View style={[styles.container]}> <View style={[styles.box, styles.box1, styles.pbox]} /> <View style={[styles.box, styles.box2, styles.pbox]} /> <View style={[styles.box, styles.box3, styles.pbox]} /> </View> </View> </View> ); } const styles = StyleSheet.create({ card: { marginTop: 10, }, title: { textAlign: 'center', fontSize: 24, fontWeight: '600', backgroundColor: 'aquamarine', }, container: { flexDirection: 'row', minHeight: 200, backgroundColor: 'oldlace', }, box: { width: 100, height: 100, }, box1: { backgroundColor: 'powderblue', top: 25, left: 25, }, box2: { backgroundColor: 'skyblue', top: 50, left: 50, }, box3: { backgroundColor: 'steelblue', top: 75, left: 75, }, pbox: { position: 'absolute', }, });
宽度与高度
组件的宽度和高度决定了其在屏幕上显示的尺寸
指定宽高
RN 中的尺寸都是 无单位的,表示的是与设备像素密度无关的逻辑像素点
指定宽高一般用于在不同尺寸的屏幕上都显示成一样的大小
import {View} from 'react-native'; import React from 'react'; export default function Basics() { return ( <View> <View style={{width: 50, height: 50, backgroundColor: 'powderblue'}} /> <View style={{width: 100, height: 100, backgroundColor: 'skyblue'}} /> <View style={{width: 150, height: 150, backgroundColor: 'steelblue'}} /> </View> ); }
弹性(Flex)宽高
在组件中使用 flex 可以使其在可利用的空间中动态地扩张或收缩,一般会使用 flex:1 来指定某个组件扩张以撑满所有剩余的空间
如果有多个并列的子组件使用了 flex:1,则这些子组件会平分父容器的剩余的空间
如果这些并列的子组件的 flex 值不一样,则谁的值更大,谁占据剩余空间的比例就更大
注意:使用 flex 指定宽高的前提是其父容器的尺寸不为零
import {View} from 'react-native'; import React from 'react'; export default function FlexDimensions() { return ( <View style={{height: '100%'}}> <View style={{flex: 1, backgroundColor: 'powderblue'}} /> <View style={{flex: 2, backgroundColor: 'skyblue'}} /> <View style={{flex: 3, backgroundColor: 'steelblue'}} /> </View> ); }
百分比宽高
用法和注意事项同 flex 宽高
import {View} from 'react-native'; import React from 'react'; export default function FlexDimensions() { return ( <View style={{height: '100%'}}> <View style={{height: '15%', backgroundColor: 'powderblue'}} /> <View style={{height: '35%', backgroundColor: 'skyblue'}} /> <View style={{height: '55%', backgroundColor: 'steelblue'}} /> </View> ); }
设备宽高
用法:
获取设备宽度:Dimensions.get('window').width
获取设备高度:Dimensions.get('window).height
import {View, Dimensions, StyleSheet} from 'react-native'; import React from 'react'; export default function DimensionsDemo() { return ( <View style={{flexDirection: 'row'}}> {/* 注意看父容器是没有指定宽高的 */} <View style={[styles.box, {backgroundColor: 'powderblue'}]} /> <View style={[styles.box, {backgroundColor: 'skyblue'}]} /> <View style={[styles.box, {backgroundColor: 'steelblue'}]} /> </View> ); } const styles = StyleSheet.create({ box: { width: Dimensions.get('window').width / 3, // 三等分设备宽度 height: 90, }, });