一、简介
2009年,W3C提出了一种新的方案----Flex布局,可以简便、完整、响应式地实现各种页面布局。
flex是Flexible Box的缩写,意为"弹性布局",用来为盒状模型提供最大的灵活性。采用flex布局的元素,称为flex容器(flex Container),简称"容器"。它的所有子元素自动成为容器成员,称为flex项目(flex item),简称"项目"。"容器"对应iOS中的父view概念,"项目"对应iOS中的子view概念。
React Native中的Flexbox的工作原理和web上的CSS基本一致,当然也存在少许差异。首先是默认值不同:flexDirection的默认值是column而不是row,而flex也只能指定一个数字值。
所有说,RN中的Flex布局来自于CSS,但是有点特殊性。RN中可以用到的属性,可以在官方文档中查阅。
二、RN中Flex布局用法
1、基本概念
容器默认存在两根轴:主轴(main axis)和交叉轴(cross axis)。主轴的开始位置(与边框的交叉点)叫做main start,结束位置叫做main end;交叉轴的开始位置叫做cross start,结束位置叫做cross end。项目默认沿主轴排列。单个项目占据的主轴空间叫做main size,占据的交叉轴空间叫做cross size。
Flex布局与Android的线性布局(LinearLayout)有点类似,都可以设置布局方向,对齐方式,以及项目的布局占位权重,区别是flex容器中项目分布的总长度超出屏幕宽度,超出的那部分项目不可见,项目不会变形,或者可以设置flexWrap属性,让容器可以分行布局,所有项目都能显示出来。
对比iOS:FlexBox没有XY轴的概念,主轴和交叉轴不是固定的;也没有坐标值(x,y)的概念。后文会介绍!
2、Flex基本属性
flex属性声明在:/node_modules/react-native/Libraries/StyleSheet/LayoutPropTypes.js
`// https://developer.mozilla.org/en-US/docs/Web/CSS/flex-direction
flexDirection: ReactPropTypes.oneOf([
'row',
'column'
]),
// https://developer.mozilla.org/en-US/docs/Web/CSS/flex-wrap
flexWrap: ReactPropTypes.oneOf([
'wrap',
'nowrap'
]),
// How to align children in the main direction
// https://developer.mozilla.org/en-US/docs/Web/CSS/justify-content
justifyContent: ReactPropTypes.oneOf([
'flex-start',
'flex-end',
'center',
'space-between',
'space-around'
]),
// How to align children in the cross direction
// https://developer.mozilla.org/en-US/docs/Web/CSS/align-items
alignItems: ReactPropTypes.oneOf([
'flex-start',
'flex-end',
'center',
'stretch'
]),
// How to align the element in the cross direction
// https://developer.mozilla.org/en-US/docs/Web/CSS/align-items
alignSelf: ReactPropTypes.oneOf([
'auto',
'flex-start',
'flex-end',
'center',
'stretch'
]),
//children scale in container view
// https://developer.mozilla.org/en-US/docs/Web/CSS/flex
flex: ReactPropTypes.number,`
由上述代码,我们可以看到flex的属性并不多,而且很好记忆,以下将会一一介绍
flex属性可以分为容器属性和项目属性
其中容器属性包括:flexDirection,justifyContent,alignItems,flexWrap
项目属性包括:flex,alignSelf
以下介绍会使用到一些代码和图片,先定义两个简单组件,方便理解
var Circle = React.createClass({
render : function(){
;var size = this.props.size || 20;
var color = this.props.color || '#527fe4';
return <View style={{backgroundColor:color,borderRadius:size/2,height:size,width:size,margin:1}}/>
},
});
//定义一个放置标题和项目的容器,传入的value属性将会是需要介绍的flex属性
var Value = React.createClass({
render : function(){
var value =
<View>
<Text style={styles.valueText}>{this.props.title}</Text>
<View style={[styles.valueContainer,this.props.value]}>
{this.props.children}
</View>
</View>;
return value;
},
});
//定义一个数组放置5个圆
var children = [<Circle/>,<Circle/>,<Circle/>,<Circle/>,<Circle/>];```
###2.1 容器属性
1、flexDirection:布局方向,决定主轴的方向,默认值是column,即纵向布局
值 | 描述 |
---|---|
row | 横向布局,主轴为水平方向 |
column | 纵向布局,主轴为竖直方向 |
row:横向布局
代码:
<Value title='row' value={{flexDirection:'row'}}>
{children}
</Value>
视图:
![97158B7B-CC32-4769-847F-A08CE7DC209B.png](http://upload-images.jianshu.io/upload_images/2305876-db41bc5aaf500302.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
column:纵向布局
代码:
<Value title='column' value={{flexDirection:'column'}}>
{children}
</Value>
视图:
![20160710123731597.jpg](http://upload-images.jianshu.io/upload_images/2305876-602391e00b4d8894.jpg?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
2、justifyContent:主轴方向对齐方式,子组件和容器的对齐方式,默认值是flex-start,即主轴的开端
值 | 描述 |
---|---|
flex-start | 主轴开端 |
center | 居中 |
flex-end | 主轴末端 |
space-between | 项目与项目之间插入相等空隙 |
space-around | 项目两旁插入相等空隙 |
flex-start:主轴开端
代码:
<Value title='flex-start' value={{flexDirection:'row', justifyContent:'flex-start'}}>
{children}
</Value>
视图:
![20160710123752426.jpg](http://upload-images.jianshu.io/upload_images/2305876-68f3e2bfcc2d0acf.jpg?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
center:主轴的中间位置
代码:
<Value title='center' value={{flexDirection:'row',justifyContent:'center'}}>
{children}
</Value>
视图:
![20160710123811612.jpg](http://upload-images.jianshu.io/upload_images/2305876-6ed71436d80ddc31.jpg?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
flex-end:主轴的末端位置
代码:
<Value title='flex-end' value={{flexDirection:'row',justifyContent:'flex-end'}}>
{children}
</Value>
视图:
![20160710123828083.jpg](http://upload-images.jianshu.io/upload_images/2305876-c329b7e35a156230.jpg?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
space-between:项目与项目之间插入相同距离的空隙
代码:
<Value title='space-between' value={{flexDirection:'row',justifyContent:'space-between'}}>
{children}
</Value>
视图:
![20160710123845099.jpg](http://upload-images.jianshu.io/upload_images/2305876-edef1daaa8fd306a.jpg?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
space-around:项目两旁插入相同距离的空隙
代码:
<Value title='space-around' value={{flexDirection:'row',justifyContent:'space-around'}}>
{children}
</Value>
视图:
![20160710123859802.jpg](http://upload-images.jianshu.io/upload_images/2305876-72248aac6862b6d3.jpg?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
3、alignItems:交叉轴方向对齐方式,子组件和容器的对齐方式,默认值flex-start,即交叉轴开端
值 | 描述 |
---|---|
flex-start | 交叉轴开端 |
center | 交叉轴居中 |
flex-end | 交叉轴末端 |
flex-start:交叉轴开端
![20160710123930800.jpg](http://upload-images.jianshu.io/upload_images/2305876-d5b418a97eb8a6c6.jpg?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
center:交叉轴的中间位置
![20160710123938397.jpg](http://upload-images.jianshu.io/upload_images/2305876-b65919e47a239d3a.jpg?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
flex-end:交叉轴的末端位置
![20160710123946034.jpg](http://upload-images.jianshu.io/upload_images/2305876-2975afe455bd778b.jpg?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
flexWrap:包含内容,默认值是nowrap,不包裹所有内容
值 | 描述 |
---|---|
nowrap | 项目沿主轴方向布局,超出容器长度的部分不可见 |
wrap | 项目沿主轴布局所需长度大于容器总长度时,分行布局,所有项目内容都可见 |
nowrap:不包裹内容
代码:
<Value title='nowrap' value={{flexWrap:'nowrap',flexDirection:'row'}}>
{children}{children}{children}{children}
</Value>
视图:
![20160710124011461.jpg](http://upload-images.jianshu.io/upload_images/2305876-ea4d01dc45b04a19.jpg?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
wrap:包裹内容
代码:
<Value title='wrap' value={{flexWrap:'wrap',flexDirection:'row'}}>
{children}{children}{children}{children}
</Value>
视图:
![20160710124019144.jpg](http://upload-images.jianshu.io/upload_images/2305876-fc66d654740f827f.jpg?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
###2.2 项目属性
1、flex:布局权重
值 | 描述 |
---|---|
>=0 | 项目占位权重 |
1:0:flex=0的项目占用空间仅为内容所需空间,flex=1的项目会占据其余所有空间
代码:
<Value title='1:0' value={{flexDirection:'row'}}>
<Text style={{color:'white',flex:1,textAlign:'center',backgroundColor:'red',fontSize:20,paddingHorizontal:10}}>flex=1</Text>
<Text style={{color:'white',textAlign:'center',backgroundColor:'yellow',fontSize:20,paddingHorizontal:10}}>flex=0</Text>
</Value>
![20160710124042149.jpg](http://upload-images.jianshu.io/upload_images/2305876-b79e28b56be5c95b.jpg?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
2:1
代码:
<Value title='2:1' value={{flexDirection:'row'}}>
<Text style={{color:'white',flex:2,textAlign:'center',backgroundColor:'blue',fontSize:20}}>flex=2</Text>
<Text style={{color:'white',flex:1,textAlign:'center',backgroundColor:'green',fontSize:20}}>flex=1</Text>
</Value>
![20160710124050258.jpg](http://upload-images.jianshu.io/upload_images/2305876-b97631c340b6e98c.jpg?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
1:1:1:1
代码:
<Value title='1:1:1:1' value={{flexDirection:'row'}}>
<Text style={{color:'white',flex:1,textAlign:'center',backgroundColor:'red',fontSize:20}}>flex=1</Text>
<Text style={{color:'white',flex:1,textAlign:'center',backgroundColor:'yellow',fontSize:20}}>flex=1</Text>
<Text style={{color:'white',flex:1,textAlign:'center',backgroundColor:'blue',fontSize:20}}>flex=1</Text>
<Text style={{color:'white',flex:1,textAlign:'center',backgroundColor:'green',fontSize:20}}>flex=1</Text>
</Value>
![20160710124105801.jpg](http://upload-images.jianshu.io/upload_images/2305876-dcbb3b1500328ef8.jpg?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
2、alignSelf:项目交叉轴方向自身对齐方式,子组件和容器的对齐方式,会覆盖alignItems的设置。
值 | 描述 |
---|---|
flex-start | 开端 |
center | 居中 |
flex-end | 末端 |
代码:
<Value title='alignSelf' value={{flexDirection:'row',height:30,alignItems:'center'}}>
<View style={{alignSelf:'flex-start'}}>
<Circle/>
</View>
<View style={{alignSelf:'flex-end'}}>
<Circle/>
</View>
<View style={{alignSelf:'flex-start'}}>
<Circle/>
</View>
<View style={{alignSelf:'flex-end'}}>
<Circle/>
</View>
<View style={{alignSelf:'flex-start'}}>
<Circle/>
</View>
</Value>
视图:
![20160710124121472.jpg](http://upload-images.jianshu.io/upload_images/2305876-97483e4bb247ab2d.jpg?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
##3、 Layout的其他属性
layout除了flex属性之外,当然还有其他属性,同样声明在:/node_modules/react-native/Libraries/StyleSheet/LayoutPropTypes.js
width: ReactPropTypes.number,
height: ReactPropTypes.number,
top: ReactPropTypes.number,
left: ReactPropTypes.number,
right: ReactPropTypes.number,
bottom: ReactPropTypes.number,
margin: ReactPropTypes.number,
marginVertical: ReactPropTypes.number,
marginHorizontal: ReactPropTypes.number,
marginTop: ReactPropTypes.number,
marginBottom: ReactPropTypes.number,
marginLeft: ReactPropTypes.number,
marginRight: ReactPropTypes.number,
padding: ReactPropTypes.number,
paddingVertical: ReactPropTypes.number,
paddingHorizontal: ReactPropTypes.number,
paddingTop: ReactPropTypes.number,
paddingBottom: ReactPropTypes.number,
paddingLeft: ReactPropTypes.number,
paddingRight: ReactPropTypes.number,
borderWidth: ReactPropTypes.number,
borderTopWidth: ReactPropTypes.number,
borderRightWidth: ReactPropTypes.number,
borderBottomWidth: ReactPropTypes.number,
borderLeftWidth: ReactPropTypes.number,
position: ReactPropTypes.oneOf([
'absolute',
'relative'
]),
属性 | 类型 | 描述 |
---|---|---|
width | number | 容器或者项目的宽度 |
height | number | 容器或者项目的高度 |
top,bottom,left,right | number | 在父容器的上下左右偏移量 |
margin | number | 留边,留边的空间不属于容器或者项目自身空间 |
marginHorizontal | number | 水平方向留边 |
marginVertical | number | 垂直方向留边 |
padding | number | 填充,填充的空间输入容器或者项目自身空间 |
paddingHorizontal | number | 水平方向填充 |
paddingVertical | number | 垂直方向填充 |
borderWidth | number | 边界宽度 |
position | enum | 位置方式:absolute与relative |
position:默认值为relative
值 | 描述 |
---|---|
absolute | 绝对布局 |
relative | 相对布局 |
react的默认位置方式是relative,项目是一个接一个排列下去的,absolute为绝对布局,一般会与left和top属性一起使用。有时候我们需要实现某些项目重叠起来,absolute属性就能发挥作用了,例如下图:
![20160710124137682.jpg](http://upload-images.jianshu.io/upload_images/2305876-1f7da8cfd80aa011.jpg?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
react的基本组件暂时不支持以图片作为背景,所以这里的的转入是一个文本组件,而红色的圆形是一个图片组件,在iOS里面组件也可以作为容器,图片可以正常显示,但是在Android里面,可能存在些问题,如果使用组件作为容器都会出现图片变得好奇怪,所以就可以absoulte来解决问题了。代码如下:
<View style={{width:80,height:80,alignItems:'center',justifyContent:'center'}}>
<Image style={{position:'absolute',left:0,top:0,resizeMode:'contain',width:80,height:80}} source={require('image!finance_usercenter_ic_into')}/>
<Text style={{width:80,textAlign:'center',color:'white',fontSize:16}}>转入</Text>
</View>
这里的View跟Android的View有点不一样,View是可以作为容器也可以作为项目,View作为容器还有其他很多属性,例如backgroundColor,borderWidth,borderColor,opacity等等,这里不一一介绍。
**注意:absolute时,控件的上下左右是相对于container;relative时,控件用的是marginLeft,marginTop,marginBottom,marginRight,分别相对于left,top,bottom,right的元素(container或者item)。**
4 布局的尺寸说明
react native的宽高是不需要带单位的,那些width,height,padding,margin的赋值都直接是数字的,当你设定width:10,在IOS的话就是设置了10pt宽度,而在Android上面是10dp,在做项目时,辛勤的美工会帮我们标出所有UI控件的宽,高,边距等等,他们用的单位也是dp,所以赋值style中宽高时,直接填入数字即可。
alignItems 和 alignSelf区别
alignItems
调整伸缩项目在侧轴上的定位方式
可选值: flex-start , flex-end , center , stretch
![20160710123625127.jpg](http://upload-images.jianshu.io/upload_images/2305876-2e1383a71736424a.jpg?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
alignSelf
alignSelf 属性会覆盖容器的 alignItems 属性,取值和用法 alignItems 一样。
可选值: auto , flex-start , flex-end , center , stretch
参考链接:
https://css-tricks.com/snippets/css/a-guide-to-flexbox/
http://blog.csdn.net/teng_ontheway/article/details/51870951
https://segmentfault.com/a/1190000002658374