react-native 之布局总结

2018-02-06 10:28:49 浏览数 (1)

前言

之前我们讲了很多react-native的基础控件,为了方便大家的理解,我们来对react-native的布局做一个总结,观看本节知识,你将看到。

  • 宽度单位和像素密度
  • flex的布局
  • 图片布局
  • 绝对定位和相对定位
  • padding和margin的区别和应用场合
  • 文本元素

宽度单位和像素密度

我们知道在Android中是用设备像素来作为单位的(后面又出现了百分比这么 一个概念),ios中后面也有了Auto Layout和1倍图,二倍图等概念(xib storyboard)。然而react的宽度不支持百分比,那么React怎么提供尺寸的呢?PixelRatio,PixelRatio及像素密度,可以看看官方的介绍。

代码语言:javascript复制
 var image = getImage({
   width: 200 * PixelRatio.get(),
   height: 100 * PixelRatio.get()
 });
 <Image source={image} style={{width: 200, height: 100}} />

flex的布局

我们知道一个div如果不设置宽度,默认的会占用100%的宽度, 为了验证100%这个问题, 做三个实验:

  1. 根节点上方一个View, 不设置宽度
  2. 固定宽度的元素上设置一个View, 不设置宽度
  3. flex的元素上放一个View宽度, 不设置宽度
代码语言:javascript复制
 <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如何实现呢?

代码语言:javascript复制
<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, backgroundColor: '#333333', justifyContent: 'center'}}>
      <View style={{backgroundColor: '#fefefe', width: 30, height: 30, borderRadius: 15}}/>
    </View>

    <Text style={[styles.text, styles.header]}>
        水平垂直居中
    </Text>
    <View style={{height: 100, backgroundColor: '#333333', alignItems: 'center', justifyContent: 'center'}}>
      <View style={{backgroundColor: '#fefefe', width: 30, height: 30, borderRadius: 15}}/>
    </View>

网格布局

通常页面不是很复杂的时候,我们可以使用flex布局等分做到网格,复杂的那么就要用ListView实现,或者第三方控件。

等分的网格

代码语言:javascript复制
<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实现九宫格效果

图片布局

代码语言:javascript复制
<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。

代码语言:javascript复制
  <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>

contain 模式容器完全容纳图片,图片自适应宽高。

代码语言:javascript复制
  <Text style={styles.welcome}> 100px height with resizeMode cover </Text>
  <View style={[{flex: 1, backgroundColor: '#fe0000'}]}>
      <Image style={{flex: 1, height: 100, resizeMode: Image.resizeMode.cover}} source={{uri: 'http://gtms03.alicdn.com/tps/i3/TB1Kcs5GXXXXXbMXVXXutsrNFXX-608-370.png'}} />
  </View>

stretch模式图片被拉伸适应屏幕

代码语言:javascript复制
 <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>

绝对定位和相对定位

代码语言:javascript复制
<View style={{flex: 1, height: 100, 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’ 。

代码语言:javascript复制
<View style={{flex: 1, height: 100, backgroundColor: '#333333'}}>
    <View style={[styles.circle, {position: 'relative', top: 50, left: 50, marginLeft: 50}]}>
    </View>
  </View>

padding和margin

我们知道在css中区分inline元素和block元素,既然react-native实现了一个超级小的css subset。那我们就来实验一下padding和margin在inline和非inline元素上的padding和margin的使用情况。

padding

代码语言:javascript复制
 <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: '#333333'}}>
    <Text style={[styles.text, {backgroundColor: '#fe0000', padding: 30}]}>
      text 元素上设置paddinga
    </Text>
  </View>

margin

代码语言:javascript复制
 <Text style={[styles.text, styles.header]}>
    在正常的View上设置margin 
  </Text>

  <View style={{backgroundColor: '#333333'}}>
    <View style={{backgroundColor: '#fefefe', width: 30, height: 30, margin: 30}}/>
  </View>

  <Text style={[styles.text, styles.header]}>
    在文本元素上设置margin
  </Text>
  <View style={{backgroundColor: '#333333'}}>
    <Text style={[styles.text, {backgroundColor: '#fe0000', margin: 30}]}>
      text 元素上设置margin
    </Text>
    <Text style={[styles.text, {backgroundColor: '#fe0000', margin: 30}]}>
      text 元素上设置margin
    </Text>
  </View>

文本元素

先看看文字有哪些支持的style属性:

代码语言:javascript复制
 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的值。

代码语言:javascript复制
 <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元素上,且虽然截取了文字但是还是会占用空间

0 人点赞