前言
之前我们讲了很多react-native的基础控件,为了方便大家的理解,我们来对react-native的布局做一个总结,观看本节知识,你将看到。
- 宽度单位和像素密度
- flex的布局
- 图片布局
- 绝对定位和相对定位
- padding和margin的区别和应用场合
- 文本元素
宽度单位和像素密度
我们知道在Android中是用设备像素来作为单位的(后面又出现了百分比这么 一个概念),ios中后面也有了Auto Layout和1倍图,二倍图等概念(xib+storyboard)。然而react的宽度不支持百分比,那么React怎么提供尺寸的呢?PixelRatio,PixelRatio及像素密度,可以看看官方的介绍。
var image = getImage({ width: 200 * PixelRatio.get(),height: 100 * PixelRatio.get() }); <Image source={image} style={{width: 200,height: 100}} />
flex的布局
我们知道一个div如果不设置宽度,默认的会占用100%的宽度, 为了验证100%这个问题, 做三个实验:
- 根节点上方一个View, 不设置宽度
- 固定宽度的元素上设置一个View, 不设置宽度
- flex的元素上放一个View宽度, 不设置宽度
<Text style={[styles.text, styles.header]}> 根节点上放一个元素,不设置宽度 </Text> <View style={{height: 20,backgroundColor: '#333333'}} /> <Text style={[styles.text, styles.header]}> 固定宽度的元素上放一个View,不设置宽度 </Text> <View style={{width: 100}}> <View style={{height: 20,backgroundColor: '#333333'}} /> </View> <Text style={[styles.text, styles.header]}> flex的元素上放一个View,不设置宽度 </Text> <View style={{flexDirection: 'row'}}> <View style={{flex: 1}}> <View style={{height: 20,backgroundColor: '#333333'}} /> </View> <View style={{flex: 1}}/> </View>
来看一下运行的结果:
水平垂直居中
css 里边经常会将一个文本或者图片水平垂直居中,如果使用过css 的flexBox当然知道使用alignItems 和 justifyContent ,那如果用React Native如何实现呢?
<Text style={[styles.text, styles.header]}> 水平居中 </Text> <View style={{height: 100,backgroundColor: '#333333',alignItems: 'center'}}> <View style={{backgroundColor: '#fefefe',width: 30,height: 30,borderRadius: 15}}/> </View> <Text style={[styles.text, styles.header]}> 垂直居中 </Text> <View style={{height: 100,justifyContent: 'center'}}> <View style={{backgroundColor: '#fefefe', styles.header]}> 水平垂直居中 </Text> <View style={{height: 100,alignItems: 'center',borderRadius: 15}}/> </View>
网格布局
通常页面不是很复杂的时候,我们可以使用flex布局等分做到网格,复杂的那么就要用ListView实现,或者第三方控件。
等分的网格
<View style={styles.flexContainer}>
<View style={styles.cell}>
<Text style={styles.welcome}>
cell1
</Text>
</View>
<View style={styles.cell}>
<Text style={styles.welcome}>
cell2
</Text>
</View>
<View style={styles.cell}>
<Text style={styles.welcome}>
cell3
</Text>
</View>
</View>
styles = {
flexContainer: {
// 容器需要添加direction才能变成让子元素flex
flexDirection: 'row'
},cell: {
flex: 1,height: 50,backgroundColor: '#aaaaaa'
},welcome: {
fontSize: 20,textAlign: 'center',margin: 10
},}
另一种方式可以参照我之前的实现: React Native实现九宫格效果
图片布局
<Text style={styles.welcome}> 100px height </Text> <Image style={{height: 100}} source={{uri: 'http://gtms03.alicdn.com/tps/i3/TB1Kcs5GXXXXXbMXVXXutsrNFXX-608-370.png'}} />
100px 高度, 可以看到图片适应100高度和全屏宽度,背景居中适应未拉伸但是被截断也就是cover。
<Text style={styles.welcome}> 100px height with resizeMode contain </Text> <View style={[{flex: 1,backgroundColor: '#fe0000'}]}> <Image style={{flex: 1,height: 100,resizeMode: Image.resizeMode.contain}} source={{uri: 'http://gtms03.alicdn.com/tps/i3/TB1Kcs5GXXXXXbMXVXXutsrNFXX-608-370.png'}} /> </View>
<Text style={styles.welcome}> 100px height with resizeMode cover </Text> <View style={[{flex: 1,resizeMode: Image.resizeMode.cover}} source={{uri: 'http://gtms03.alicdn.com/tps/i3/TB1Kcs5GXXXXXbMXVXXutsrNFXX-608-370.png'}} /> </View>
stretch模式图片被拉伸适应屏幕
<Text style={styles.welcome}> set height to image container </Text> <View style={[{flex: 1,backgroundColor: '#fe0000',height: 100}]}> <Image style={{flex: 1}} source={{uri: 'http://gtms03.alicdn.com/tps/i3/TB1Kcs5GXXXXXbMXVXXutsrNFXX-608-370.png'}} /> </View>
绝对定位和相对定位
<View style={{flex: 1,backgroundColor: '#333333'}}> <View style={[styles.circle, {position: 'absolute',top: 50,left: 180}]}> </View> </View> styles = { circle: { backgroundColor: '#fe0000',borderRadius: 10,width: 20,height: 20 } }
和css的标准不同的是, 元素容器不用设置position:’absolute|relative’ 。
<View style={{flex: 1, {position: 'relative',left: 50,marginLeft: 50}]}> </View> </View>
padding和margin
我们知道在css中区分inline元素和block元素,既然react-native实现了一个超级小的css subset。那我们就来实验一下padding和margin在inline和非inline元素上的padding和margin的使用情况。
padding
<Text style={[styles.text, styles.header]}> 在正常的View上设置padding </Text> <View style={{padding: 30,backgroundColor: '#333333'}}> <Text style={[styles.text, {color: '#fefefe'}]}> Text Element</Text> </View> <Text style={[styles.text, styles.header]}> 在文本元素上设置padding </Text> <View style={{padding: 0, {backgroundColor: '#fe0000',padding: 30}]}> text 元素上设置paddinga </Text> </View>
margin
<Text style={[styles.text, styles.header]}> 在正常的View上设置margin </Text> <View style={{backgroundColor: '#333333'}}> <View style={{backgroundColor: '#fefefe',margin: 30}}/> </View> <Text style={[styles.text, styles.header]}> 在文本元素上设置margin </Text> <View style={{backgroundColor: '#333333'}}> <Text style={[styles.text,margin: 30}]}> text 元素上设置margin </Text> <Text style={[styles.text,margin: 30}]}> text 元素上设置margin </Text> </View>
文本元素
Attributes.style = {
color string
containerBackgroundColor string
fontFamily string
fontSize number
fontStyle enum('normal','italic')
fontWeight enum("normal",'bold','100','200','300','400','500','600','700','800','900')
lineHeight number
textAlign enum("auto",'left','right','center')
writingDirection enum("auto",'ltr','rtl')
}
Text的样式继承
实际上React-native里边是没有样式继承这种说法的, 但是对于Text元素里边的Text元素是可以继承的。到底是继承的最外层的Text的值呢,还是继承父亲Text的值呢?肯定是继承父亲Text的值。
<Text style={[styles.text, styles.header]}> 文本样式继承 </Text> <View style={{backgroundColor: '#333333',padding: 10}}> <Text style={{color: 'white'}}> <Text style={{color: 'red'}} onPress={this.onPressTitle}> 文本元素{'\n'} <Text>我是white还是red呢?{'\n'} </Text> </Text> <Text>我应该是white的</Text> </Text> </View>
总结
针对上面的实例,我们做一个总结。
- react 宽度基于pt为单位, 可以通过Dimensions 来获取宽高,PixelRatio 获取密度。
- 基于flex的布局:
view默认宽度为100%
水平居中用alignItems,垂直居中用justifyContent
基于flex能够实现现有的网格系统需求,且网格能够各种嵌套无bug - 图片布局
通过Image.resizeMode来适配图片布局,包括contain,cover,stretch 三种模式
默认不设置模式等于cover模式
contain模式自适应宽高,给出高度值即可
cover铺满容器,但是会做截取
stretch铺满容器,拉伸 绝对定位和相对定位
定位相对于父元素,父元素不用设置position也行
padding 设置在Text元素上的时候会存在bug。所有padding变成了marginBottom文本元素 文字必须放在Text元素里边 Text元素可以相互嵌套,且存在样式继承关系 numberOfLines 需要放在最外层的Text元素上,且虽然截取了文字但是还是会占用空间