RN中的布局我觉得主要包含这几个部分:像素单位,布局方式,组件,CSS。熟悉这几点后,就是经验的积累,见得多了做的多了布局代码写起来自然就快许多。
react native 的页面布局使用的是flex布局,Flex是Flexible Box的缩写,意为"弹性布局",用来为盒状模型提供最大的灵活性。flex只是一种元素布局方式,所以任何一个元素都可以设定flex,而一个元素设定了flex之后,那么它里面的所有元素都是在这个容器内布局。
- Flex:1
在RN中的flex布局跟web中略有不同,RN中flex只可以指定一个数字, 根据具体数字值来填充展示当前元素,“1”即表示100%撑满当前容器,而该容器内的子元素只能够在该容器内区域布局。
2. 主次轴
容器内默认有两根轴,横轴和纵轴,当画一个页面时,首先要确定该页面或者该容器内是采用哪个轴作为主轴布局,其实就是行布局或者列布局。当确定主轴之后,另外一轴自动成为副轴。RN中使用flexDirection来定义当前容器是使用何种布局(column活row),默认为column。justifyContent 和 alignItems 分别制定主轴和次轴的排列方式。
flexDirection: column;row;
justifyContent:
flex-start(默认,起始位置,一般都是左对齐);
center(居中);
flex-end(结尾,一般是右对齐);
space-around;space-between;
alignItems:
flex-start(默认,起始位置,一般都是左对齐);
center(居中);
flex-end(结尾,一般是右对齐);
stretch(均匀分布);
当父容器指定了flex之后(比如1),那么如果子元素的flex也都设置为1,那么这些子元素将会平均分配父容器的尺寸来布局,就像如下代码:
<View style={{flex:1,flexDirection:'row',backgroundColor:'#ffffff'}}> <View style={{flex:1,backgroundColor:'red'}}></View> <View style={{flex:1,backgroundColor:'black'}}></View> <View style={{flex:1,backgroundColor:'blue'}}></View> </View>
![]() |
|
flexDirection:'column' | flexDirection:'row' |
再举个例子,子元素指定宽高,父容器采用space-between 和 space-around布局,代码如下:
<View style={{flex:1,borderWidth:2,flexDirection:'column',backgroundColor:'#ffffff',justifyContent:'space-between', alignItems:'center'}}> <View style={{height:100,width:100,borderRadius:50,backgroundColor:'red'}}></View> <View style={{height:100,width:100,borderRadius:50,backgroundColor:'black'}}></View> <View style={{height:100,width:100,borderRadius:50,backgroundColor:'blue'}}></View> </View>
![]()
| ![]()
|
justifyContent:'space-between' | justifyContent:'space-around' |
下面实现一个具体的例子,效果如下:
这是一个表单页面,从这个图可以得出:
1. 外层是主轴按照column排列。行元素撑满一行。
2. 行元素高度固定,主轴按row排列,次轴的排列应该居中。
3. 行元素有内衬,有分割线。
4. 行元素内应该分左右两部分,分别左右对齐。
根据这几点,我们可以大概写出这样的布局:
![](https://i-blog.csdnimg.cn/blog_migrate/8f900a89c6347c561fdf2122f13be562.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/961ddebeb323a10fe0623af514929fc1.gif)
class Layout extends Component { render() { return ( <View style={{flex:1,backgroundColor:'#dddddd',flexDirection:'column',justifyContent:'center'}}> <View style={LayoutStyles.row}> <Text style={{flex:1}}>真实姓名</Text> <View style={{flex:1,alignItems:'flex-end'}}> <Text style={{color:'#999999'}}>John</Text> </View> </View> <View style={LayoutStyles.row}> <Text>手机号码</Text> <View style={{flex:1,alignItems:'flex-end'}}> <Text style={{color:'#999999'}}>13812345678</Text> </View> </View> </View> ); } } const LayoutStyles = StyleSheet.create({ row: { backgroundColor:'#ffffff', height:47, flexDirection:'row', alignItems:'center', borderBottomWidth:0.5, borderBottomColor:'#dddddd', paddingHorizontal: 15 } });
这里可以看到, 在“手机号码”这一行内,用两个子元素Text和View分别设置flex:1来撑满行元素,然后设置view的末端对齐。
而“真实姓名”这一行只对view设置了flex:1,也达到了这个效果。
通过给view加上border看一下:
可以看出,如果在一个容器内,如果元素没有设置flex,那么默认会根据该元素的内容自动撑开宽度,而设置了flex:1的元素则会占满剩余的空间。
那么这里给 “真实姓名”这行的右边部分留下较大的空间,因为这里要放一个输入框,留下较大的区域可以方便它点中以获取焦点输入。
borderWidth问题
这样做使用borderWidth:0.5,这种写法在ios上是可以正常显示,但是在部分Android机型上显示异常。这个问题可以使用 StyleSheet.hairlineWidth 来避免这个问题。
这里分割线使用了行元素的下边框来做,其实也可以吧分割线作为一个单独的子元素来绘制,比如:
<View style={{height:1,backgroundColor:'#dddddd'}}></View>
分割线问题
跟效果图对比行元素的分割线没有撑满,而是随行内容一样存在内衬。这个问题,如果采用上面的方法把分割线作为子元素,则可以解决。
如果使用边框的话,可以在行元素内再包一层View,外层View设置padding,内层view设置borderBottomWidth即可。
最终代码:
![](https://i-blog.csdnimg.cn/blog_migrate/8f900a89c6347c561fdf2122f13be562.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/961ddebeb323a10fe0623af514929fc1.gif)
class Layout extends Component { render() { return ( <View style={{flex:1,backgroundColor:'#dddddd',flexDirection:'column',justifyContent:'center'}}> <View style={LayoutStyles.row}> <View style={LayoutStyles.rowContainer}> <Text>真实姓名</Text> <View style={{flex:1,alignItems:'flex-end',height:47}}> <TextInput style={LayoutStyles.inputTextName} underlineColorAndroid={'blue'} keyboardType={'default'} placeholder='请输入' placeholderTextColor='#999999' defaultValue={'laochan'} maxLength={10} /> </View> </View> </View> <View style={LayoutStyles.row}> <View style={LayoutStyles.rowContainer}> <Text style={{flex:1}}>手机号码</Text> <View style={{flex:1,alignItems:'flex-end'}}> <Text style={{color:'#999999'}}>13812345678</Text> </View> </View> </View> </View> ); } } const LayoutStyles = StyleSheet.create({ row: { backgroundColor:'#ffffff', height:47, paddingHorizontal: 15 }, rowContainer: { flex: 1, flexDirection:'row', alignItems:'center', borderBottomWidth:StyleSheet.hairlineWidth, borderBottomColor:'#dddddd', }, inputTextName: { flex:1, padding:0, fontSize:14, color: '#999999', textAlign: 'right', marginRight: 10 } });
参考资源:
http://reactnative.cn/docs/0.44/layout-with-flexbox.html#content
布局样式属性:http://reactnative.cn/docs/0.44/layout-props.html
flex布局:http://www.ruanyifeng.com/blog/2015/07/flex-examples.html