react-native 之布局總結

nlts2569 7年前發布 | 16K 次閱讀 ReactNative 移動開發 React Native

前言

之前我們講了很多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%這個問題, 做三個實驗:

  1. 根節點上方一個View, 不設置寬度
  2. 固定寬度的元素上設置一個View, 不設置寬度
  3. 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></code></pre>

來看一下運行的結果:

水平垂直居中

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, 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></code></pre> 

網格布局

通常頁面不是很復雜的時候,我們可以使用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
        },
    }

 

圖片布局

<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>

contain 模式容器完全容納圖片,圖片自適應寬高。

  <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模式圖片被拉伸適應屏幕

 <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, 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’ 。

<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

 <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

 <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屬性:

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元素上,且雖然截取了文字但是還是會占用空間

 

來自:http://blog.csdn.net/xiangzhihong8/article/details/54588342

 

 本文由用戶 nlts2569 自行上傳分享,僅供網友學習交流。所有權歸原作者,若您的權利被侵害,請聯系管理員。
 轉載本站原創文章,請注明出處,并保留原始鏈接、圖片水印。
 本站是一個以用戶分享為主的開源技術平臺,歡迎各類分享!