【React Native】FlexBox布局

一、FlexBox布局
  • FlexBox是什么?

彈性盒模型(The Flexible Box Module),又叫Flexbox,意為“彈性布局”,旨在通過彈性的方式來對(duì)齊和分布容器中內(nèi)容的空間,使其能適應(yīng)不同屏幕,為盒裝模型提供最大的靈活性。
Flex布局主要思想是:讓容器有能力讓其子項(xiàng)目能夠改變其寬度、高度(甚至是順序),以最佳方式填充可用空間;
React native中的FlexBox是這個(gè)規(guī)范的一個(gè)子集。

二、Flexbox在開發(fā)中的應(yīng)用場景

  • Flexbox在布局中能夠解決什么問題?
    浮動(dòng)布局
    各種機(jī)型屏幕的適配
    水平和垂直居中
    自動(dòng)分配寬度
    ......
  • 在CSS中,常規(guī)的布局是基于塊和內(nèi)聯(lián)流方向,而Flex布局是基于flex-flow流,下圖很好解釋了Flex布局的思想

1.png

容器默認(rèn)存在兩根軸:水平的主軸(main axis)和垂直的交叉軸(cross axis)。主軸的開始位置(與邊框的交叉點(diǎn))叫做main start,結(jié)束位置叫做main end;交叉軸的開始位置叫做cross start,結(jié)束位置叫做cross end
項(xiàng)目默認(rèn)沿主軸排列。單個(gè)項(xiàng)目占據(jù)的主軸空間叫做main size,占據(jù)的交叉軸空間叫做cross size

三、Flexbox的常用屬性

  • 容器屬性

  • flexDirection: row | row-reverse | column | column-reverse
    該屬性決定主軸的方向(即項(xiàng)目的排列方向)。
    主要是父視圖來控制子視圖的顯示

    row:主軸為水平方向,起點(diǎn)在左端;
    row-reverse:主軸為水平方向,起點(diǎn)在右端;
    column(默認(rèn)值):主軸為垂直方向,起點(diǎn)在上沿。
    column-reverse:主軸為垂直方向,起點(diǎn)在下沿。

export default class meituanDemo extends Component {
  render() {
    return (
      <View style={styles.contains}>
        <View style={styles.title}> 
            <Text style={{width: 80, textAlign: 'center'}}>row</Text>
            <Text style={{width: 80, textAlign: 'center'}}>row-reverse</Text>  
            <Text style={{width: 80, textAlign: 'center'}}>column</Text>  
            <Text style={{width: 80, textAlign: 'center'}}>column-reverse</Text>   
        </View>
        <View style={styles.example}> 
          <View style={styles.one}> 
            <View style={styles.top}>
            </View>
            <View style={styles.middle}>
            </View>
            <View style={styles.bottom}>
            </View> 
          </View>
          <View style={styles.two}>  
            <View style={styles.top}>
            </View>
            <View style={styles.middle}>
            </View>
            <View style={styles.bottom}>
            </View> 
          </View>
          <View style={styles.three}> 
            <View style={styles.top}>
            </View>
            <View style={styles.middle}>
            </View>
            <View style={styles.bottom}>
            </View> 
          </View>
          <View style={styles.four}> 
            <View style={styles.top}>
            </View>
            <View style={styles.middle}>
            </View>
            <View style={styles.bottom}>
            </View> 
          </View>
        </View>
      </View> 
    );
  }
}

const styles = StyleSheet.create({
    contains: { 
      flexDirection: 'column',
      // justifyContent: 'space-around', 
      // alignItems: 'center',
      flex: 1
    },
    title: { 
      flexDirection: 'row',
      justifyContent: 'space-around', 
      alignItems: 'center', 
      height: 30,
      marginTop: 200
    },
    example: {
      flexDirection: 'row',
      justifyContent: 'space-around', 
      alignItems: 'center', 
      height: 200,
    },
    one: {
      backgroundColor: 'yellow',
      width: 80,
      height: 200,
      flexDirection: 'row'
    },
    two: {
      backgroundColor: 'purple',
      width: 80,
      height: 200,
      flexDirection: 'row-reverse'
    },
    three: {
      backgroundColor: 'blue',
      width: 80,
      height: 200,
      flexDirection: 'column'
    },
    four: {
      backgroundColor: 'red',
      width: 80,
      height: 200,
      flexDirection: 'column-reverse'
    },
    top: {
      backgroundColor: 'green',
      flex: 1
    },
    middle: {
      backgroundColor: 'black',
      flex: 1
    },
    bottom: {
      backgroundColor: 'orange',
      flex: 1
    } 
}); 
flexDirection 效果圖.png
  • justifyContent:flex-start | flex-end | center | space-between | space-around
    定義了伸縮項(xiàng)目在主軸線的對(duì)齊方式:

flex-start(默認(rèn)值):伸縮項(xiàng)目向一行的起始位置靠齊。
flex-end:伸縮項(xiàng)目向一行的結(jié)束位置靠齊。
center:伸縮項(xiàng)目向一行的中間位置靠齊。
space-between:兩端對(duì)齊,項(xiàng)目之間的間隔都相等。
space-around:伸縮項(xiàng)目會(huì)平均地分布在行里,兩端保留一半的空間。

export default class meituanDemo extends Component {
  render() {
    return (
      <View style={styles.contains}>
        <View style={styles.title}> 
            <Text style={{height: 30, textAlign: 'center'}}>flex-start</Text>
            <Text style={{height: 30, textAlign: 'center'}}>flex-end</Text>  
            <Text style={{height: 30, textAlign: 'center'}}>center</Text>  
            <Text style={{height: 30, textAlign: 'center'}}>space-between</Text>   
            <Text style={{height: 30, textAlign: 'center'}}>space-around</Text> 
        </View>
        <View style={styles.example}> 
          <View style={styles.one}> 
            <View style={styles.left}>
            </View>
            <View style={styles.middle}>
            </View>
            <View style={styles.right}>
            </View>  
          </View>
          <View style={styles.two}>  
            <View style={styles.left}>
            </View>
            <View style={styles.middle}>
            </View>
            <View style={styles.right}>
            </View>  
          </View>
          <View style={styles.three}> 
            <View style={styles.left}>
            </View>
            <View style={styles.middle}>
            </View>
            <View style={styles.right}>
            </View>  
          </View>
          <View style={styles.four}> 
            <View style={styles.left}>
            </View>
            <View style={styles.middle}>
            </View>
            <View style={styles.right}>
            </View>  
          </View>
          <View style={styles.five}>
            <View style={styles.left}>
            </View>
            <View style={styles.middle}>
            </View>
            <View style={styles.right}>
            </View>  
          </View> 
        </View>
      </View> 
    );
  }
}

const styles = StyleSheet.create({
    contains: { 
      flexDirection: 'row',
      justifyContent: 'space-around', 
      alignItems: 'center',
      flex: 1
    },
    title: { 
      flexDirection: 'column',
      justifyContent: 'space-around', 
      alignItems: 'center', 
      width: 100,
      height: 300 
    },
    example: {
      flexDirection: 'column',
      justifyContent: 'space-around',  
      flex: 1, 
      height: 300,
    },
    one: {
      backgroundColor: 'gray', 
      height: 50,  
      justifyContent: 'flex-start',
      flexDirection: 'row',
    },
    two: {
      backgroundColor: 'gray', 
      height: 50, 
      justifyContent: 'flex-end',
      flexDirection: 'row',
    },
    three: {
      backgroundColor: 'gray', 
      height: 50, 
      justifyContent: 'center',
      flexDirection: 'row',
    },
    four: {
      backgroundColor: 'gray', 
      height: 50, 
      justifyContent: 'space-between',
      flexDirection: 'row',
    },
    five: {
      backgroundColor: 'gray', 
      height: 50, 
      justifyContent: 'space-around',
      flexDirection: 'row',
    },
    left: {
      backgroundColor: 'green', 
      width: 50
    },
    middle: {
      backgroundColor: 'black', 
      width: 50
    },
    right: {
      backgroundColor: 'orange', 
      width: 50
    } 
});
justifyContent 效果圖.png
  • alignItems: flex-start | flex-end | center | baseline | stretch
    定義項(xiàng)目在交叉軸上如何對(duì)齊,可以把其想像成側(cè)軸(垂直于主軸)的“對(duì)齊方式”。

flex-start:交叉軸的起點(diǎn)對(duì)齊。
flex-end:交叉軸的終點(diǎn)對(duì)齊 。
center:交叉軸的中點(diǎn)對(duì)齊。
baseline:項(xiàng)目的第一行文字的基線對(duì)齊。
stretch(默認(rèn)值):如果項(xiàng)目未設(shè)置高度或設(shè)為auto,將占滿整個(gè)容器的高度。

const styles = StyleSheet.create({
  contains: { 
    flexDirection: 'row',
    justifyContent: 'space-around', 
    alignItems: 'center',
    flex: 1
  },
  title: { 
    flexDirection: 'column',
    justifyContent: 'space-around', 
    alignItems: 'center', 
    width: 100,
    height: 300 
  },
  example: {
    flexDirection: 'column',
    justifyContent: 'space-around',  
    flex: 1, 
    height: 300,
  },
  one: {
    backgroundColor: 'gray', 
    height: 50,  
    justifyContent: 'flex-start',
    flexDirection: 'row',
    alignItems: 'flex-start'
  },
  two: {
    backgroundColor: 'gray', 
    height: 50, 
    justifyContent: 'flex-end',
    flexDirection: 'row',
    alignItems: 'flex-end'
  },
  three: {
    backgroundColor: 'gray', 
    height: 50, 
    justifyContent: 'center',
    flexDirection: 'row',
    alignItems: 'center'
  },
  four: {
    backgroundColor: 'gray', 
    height: 50, 
    justifyContent: 'space-between',
    flexDirection: 'row',
    alignItems: 'baseline'
  },
  five: {
    backgroundColor: 'gray', 
    height: 50, 
    justifyContent: 'space-around',
    flexDirection: 'row',
    alignItems: 'stretch'
  },
  left: {
    backgroundColor: 'green', 
    width: 50,
    height: 30
  },
  middle: {
    backgroundColor: 'black', 
    width: 50,
    height: 20
  },
  right: {
    backgroundColor: 'orange', 
    width: 50,
    height: 50
  } 
});
alignItems 效果圖.png
  • flexWrap: nowrap | wrap | wrap-reverse
    默認(rèn)情況下,項(xiàng)目都排在一條線(又稱"軸線")上。flex-wrap屬性定義,如果一條軸線排不下,如何換行。

nowrap(默認(rèn)值):不換行。
wrap:換行,第一行在上方。

export default class meituanDemo extends Component {
  render() {
    return (
      <View style={styles.contains}>
        <View style={styles.title}> 
            <Text style={{height: 30, textAlign: 'center'}}>nowrap(默認(rèn)值)</Text>
            <Text style={{height: 30, textAlign: 'center'}}>wrap</Text>   
        </View>
        <View style={styles.example}> 
          <View style={styles.one}> 
            <View style={{backgroundColor: 'green',width: 50,height: 20,marginLeft:10,marginTop:2}}>
            </View>
            <View style={{backgroundColor: 'green',width: 50,height: 20,marginLeft:10,marginTop:2}}>
            </View>
            <View style={{backgroundColor: 'green',width: 50,height: 20,marginLeft:10,marginTop:2}}>
            </View>  
            <View style={{backgroundColor: 'green',width: 50,height: 20,marginLeft:10,marginTop:2}}>
            </View>
            <View style={{backgroundColor: 'green',width: 50,height: 20,marginLeft:10,marginTop:2}}>
            </View>
            <View style={{backgroundColor: 'green',width: 50,height: 20,marginLeft:10,marginTop:2}}>
            </View>  
          </View>
          <View style={styles.two}>  
            <View style={{backgroundColor: 'green',width: 50,height: 20,marginLeft:10,marginTop:2}}>
            </View>
            <View style={{backgroundColor: 'green',width: 50,height: 20,marginLeft:10,marginTop:2}}>
            </View>
            <View style={{backgroundColor: 'green',width: 50,height: 20,marginLeft:10,marginTop:2}}>
            </View>  
            <View style={{backgroundColor: 'green',width: 50,height: 20,marginLeft:10,marginTop:2}}>
            </View>
            <View style={{backgroundColor: 'green',width: 50,height: 20,marginLeft:10,marginTop:2}}>
            </View>
            <View style={{backgroundColor: 'green',width: 50,height: 20,marginLeft:10,marginTop:2}}>
            </View>  
          </View> 
        </View>
      </View> 
    );
  }
}
const styles = StyleSheet.create({
    contains: { 
      flexDirection: 'row',
      justifyContent: 'space-around', 
      alignItems: 'center',
      flex: 1
    },
    title: { 
      flexDirection: 'column',
      justifyContent: 'space-around', 
      alignItems: 'center', 
      width: 100,
      height: 300 
    },
    example: {
      flexDirection: 'column',
      justifyContent: 'space-around',  
      flex: 1, 
      height: 300,
    },
    one: {
      backgroundColor: 'gray', 
      height: 50,  
      justifyContent: 'flex-start',
      flexDirection: 'row',
      flexWrap: 'nowrap'
    },
    two: {
      backgroundColor: 'gray', 
      height: 50, 
      justifyContent: 'flex-end',
      flexDirection: 'row',
      flexWrap: 'wrap'
    },
    three: {
      backgroundColor: 'gray', 
      height: 50, 
      justifyContent: 'center',
      flexDirection: 'row',  
    },
    four: {
      backgroundColor: 'gray', 
      height: 50, 
      justifyContent: 'space-between',
      flexDirection: 'row',
      alignItems: 'baseline'
    },
    five: {
      backgroundColor: 'gray', 
      height: 50, 
      justifyContent: 'space-around',
      flexDirection: 'row',
      alignItems: 'stretch'
    },
    left: {
      backgroundColor: 'green', 
      width: 50,
      height: 30
    },
    middle: {
      backgroundColor: 'black', 
      width: 50,
      height: 20
    },
    right: {
      backgroundColor: 'orange', 
      width: 50,
      height: 50
    } 
});
flexWrap 效果圖.png
  • 元素屬性

    • flex
      flex屬性是flex-grow, flex-shrinkflex-basis的簡寫,默認(rèn)值為0 1 auto。后兩個(gè)屬性可選。 默認(rèn)值為“0 1 auto”。

    寬度 = 彈性寬度 * ( flexGrow / sum( flexGorw ) )

    • alignSelf: “auto | flex-start | flex-end | center | baseline | stretch
      align-self屬性允許單個(gè)項(xiàng)目有與其他項(xiàng)目不一樣的對(duì)齊方式,可覆蓋align-items屬性。默認(rèn)值為auto,表示繼承父元素的align-items屬性,如果沒有父元素,則等同于stretch

四、在React Native 中使用FlexlBox布局

  • 獲取當(dāng)前屏幕的寬度、高度和scale
var {width, height, scale} = Dimensions.get('window')
export default class meituanDemo extends Component {
  render() {
    return (
      <View style={styles.contains}> 
        <Text style={styles.welcome}>
          當(dāng)前屏幕的寬度:{width + '\n'}
          當(dāng)前屏幕的高度:{height + '\n'}
          當(dāng)前屏幕的scale:{scale + '\n'}
        </Text>
      </View> 
    );
  }
}

const styles = StyleSheet.create({
  contains: { 
    flexDirection: 'row',
    justifyContent: 'center', 
    alignItems: 'center',
    flex: 1,
  },
  welcome: { 
    textAlign: 'center',
    flex: 1
  } 
});
獲取屏幕信息.png
  • 水平居中,垂直居中和水平垂直居中
export default class meituanDemo extends Component {
  render() {
    return (
      <View style={styles.contains}>
        <View style={styles.title}> 
            <Text style={{height: 30, textAlign: 'center'}}>水平居中</Text>
            <Text style={{height: 30, textAlign: 'center'}}>垂直居中</Text>   
            <Text style={{height: 30, textAlign: 'center'}}>水平垂直居中</Text>   
        </View>
        <View style={styles.example}> 
          <View style={styles.one}>  
            <Image source={{uri:'http://farm4.staticflickr.com/3795/9269794168_3ac58fc15c_b.jpg'}} style={{width:30,height:30}} /> 
          </View>
          <View style={styles.two}>    
            <Image source={{uri:'http://farm4.staticflickr.com/3795/9269794168_3ac58fc15c_b.jpg'}} style={{width:30,height:30}} /> 
          </View> 
          <View style={styles.three}>   
            <Image source={{uri:'http://farm4.staticflickr.com/3795/9269794168_3ac58fc15c_b.jpg'}} style={{width:30,height:30}} />  
          </View> 
        </View>
      </View> 
    );
  }
}
const styles = StyleSheet.create({
    contains: { 
      flexDirection: 'row',
      justifyContent: 'space-around', 
      alignItems: 'center',
      flex: 1
    },
    title: { 
      flexDirection: 'column',
      justifyContent: 'space-around', 
      alignItems: 'center', 
      width: 100,
      height: 300 
    },
    example: {
      flexDirection: 'column',
      justifyContent: 'space-around',  
      flex: 1, 
      height: 300,
    },
    one: {
      backgroundColor: 'gray', 
      height: 50,   
      alignItems: 'center'
    },
    two: {
      backgroundColor: 'gray', 
      height: 50, 
      justifyContent: 'center', 
    },
    three: {
      backgroundColor: 'gray', 
      height: 50, 
      alignItems: 'center',
      justifyContent: 'center', 
    }
});

居中效果圖.png

備注:一旦設(shè)置alignItems屬性之后,組件的大小包裹隨著內(nèi)容的尺寸;此外水平居中和垂直居中還要結(jié)合FlexDirection進(jìn)行判斷。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 228,030評(píng)論 6 531
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 98,310評(píng)論 3 415
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 175,951評(píng)論 0 373
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經(jīng)常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 62,796評(píng)論 1 309
  • 正文 為了忘掉前任,我火速辦了婚禮,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 71,566評(píng)論 6 407
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 55,055評(píng)論 1 322
  • 那天,我揣著相機(jī)與錄音,去河邊找鬼。 笑死,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,142評(píng)論 3 440
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 42,303評(píng)論 0 288
  • 序言:老撾萬榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 48,799評(píng)論 1 333
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 40,683評(píng)論 3 354
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 42,899評(píng)論 1 369
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,409評(píng)論 5 358
  • 正文 年R本政府宣布,位于F島的核電站,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 44,135評(píng)論 3 347
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,520評(píng)論 0 26
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 35,757評(píng)論 1 282
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 51,528評(píng)論 3 390
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 47,844評(píng)論 2 372

推薦閱讀更多精彩內(nèi)容