React-Native 之 FlexBox介紹與使用

前言


  • 學習本系列內容需要具備一定 HTML 開發(fā)基礎畅铭,沒有基礎的朋友可以先轉至 HTML快速入門(一) 學習

  • 本人接觸 React Native 時間并不是特別長,所以對其中的內容和性質了解可能會有所偏差,在學習中如果有錯會及時修改內容府框,也歡迎萬能的朋友們批評指出催跪,謝謝

  • 文章第一版出自簡書,如果出現(xiàn)圖片或頁面顯示問題惑艇,煩請轉至 簡書 查看 也希望喜歡的朋友可以點贊蒿辙,謝謝

什么是 FlexBox 布局


  • 在 html 中,界面的搭建都是采用 CSS 的布局方式滨巴,CSS 是基于盒子模型思灌,依賴于 display、position恭取、float屬性泰偿,這對于一些比如 垂直居中 的特殊布局來說非常不方便

  • Flex 是一種全新的針對 Web 和移動開發(fā)的布局方式,它可以簡便蜈垮、完整耗跛、響應式地實現(xiàn)各種頁面布局,并且目前的所有瀏覽器已經(jīng)支持這種布局方式攒发,所以不用考慮兼容性方面的問題

  • FlexBox 從字面上可以理解成:能夠很容易變化以適應外界條件變化的通用矩形容器调塌,也就是我們常聽到的 彈性布局,它的宗旨就是 通過彈性的方式來第七和分布容器中內容的空間惠猿,使其能使用不同屏幕羔砾,為盒裝模型提供最大的靈活性(這類似于 iOS 開發(fā)中的AtuoLayout布局方式)

  • FlexBox 布局主要思想是:讓容器有能力讓其子項目改變寬度、高度甚至是順序偶妖,從而達到最佳填充可用空間的方式

  • React Native 中的 FlexBox 是這個規(guī)范的一個子集

  • 綜上所述姜凄,F(xiàn)lexBox 就是用來解決 父盒子 和 子盒子 之間的約束關系,如下圖

父盒子和子盒子之間的約束關系
  • FlexBox 在開發(fā)中能夠解決下面等問題

    • 浮動布局
    • 水平和垂直居中
    • 自動分配寬度
    • 各種機型屏幕適配
    • 動態(tài)分配子集的尺寸餐屎、位置等等
  • 如下圖所示檀葛,在 CSS 中,常規(guī)的布局是基于塊和內聯(lián)流方向腹缩,而 Flex布局是基于 Flexflow流【容器默認存在兩根軸:水平的主軸(main axis)垂直的交叉軸(cross axis)屿聋,主軸的開始位置(與邊框的交叉點)叫做 main start,結束的位置叫 main end;交叉軸的開始位置叫做 cross start,結束位置叫做 cross end空扎。項目默認沿著主軸排列,單個項目占據(jù)的主軸空間叫做 main size,占據(jù)的交叉軸空間叫做 cross size】

FlexBox主軸與側軸的關系
  • 根據(jù)伸縮項目排列方式的不同润讥,主軸和側軸方向也會變化转锈,如下圖所示
主軸從左向右排列
主軸從上向下排列

獲取主屏幕尺寸

  • 為了后面更好的展示案例,我們先來看看如何獲取主屏幕的尺寸和分辨率

    • 首先楚殿,我們需要先導入 Dimensions


        // 導入類庫
        var Dimensions = require('Dimensions');
    
    
    • 接下來就可以在需要的地方使用 Dimensions 變量獲取屏幕的高度撮慨、寬度、分辨率等等數(shù)據(jù)
        export default class TestRN extends Component {
            render() {
                return (
                <View style={styles.container}>
                    <Text>當前屏幕的寬度:{Dimensions.get('window').width}</Text>
                    <Text>當前屏幕的高度:{Dimensions.get('window').height}</Text>
                </View>
                );
            }
        }
    
    
    • 設置樣式
        // 樣式
        const styles = StyleSheet.create({
            container: {
                backgroundColor:'blue'
            },
        });
    
    

效果:
獲取屏幕尺寸
  • 既然能拿到屏幕的尺寸脆粥,那么就能夠直接將主 View 的大小設置成屏幕的尺寸砌溺,使 View 填充整個屏幕

        // 樣式
        const styles = StyleSheet.create({
            container: {
                backgroundColor:'blue',
                height:Dimensions.get('window').height,
                width:Dimensions.get('window').width
            },
        });
    
    

效果:


使View尺寸等于屏幕尺寸

FlexBox 常用容器屬性


  • 為了方便理解,我們先添加幾個視圖

        // 導入類庫
        var Dimensions = require('Dimensions');
    
        // 入口
        export default class TestRN extends Component {
            render() {
                return (
                <View style={styles.container}>
                    <View style={styles.subViewStyle1}></View>
                    <View style={styles.subViewStyle2}></View>
                    <View style={styles.subViewStyle3}></View>
                </View>
            );
        }
    }
    
        // 樣式
        const styles = StyleSheet.create({
            container: {
                backgroundColor:'blue',
                height:Dimensions.get('window').height,
                width:Dimensions.get('window').width
            },
            subViewStyle1: {
                backgroundColor:'red',
                height:60,
                width:60,
            },
            subViewStyle2: {
                backgroundColor:'yellow',
                height:60,
                width:60,
            },
            subViewStyle3: {
                backgroundColor:'green',
                height:60,
                width:60,
            },
        });
    
    

    效果:


    默認樣式
  • flexDirection(該屬性決定了項目排列的方向变隔,也就是主軸的方向)

    • row:主軸為水平方向规伐,起點在左端


        container: {
            backgroundColor:'blue',
            height:Dimensions.get('window').height,
            width:Dimensions.get('window').width,
            // 設置主軸方向
            flexDirection:'row'
        },
    
    

    效果:


    主軸向水平方向延伸
    • row-reverse:主軸為水平方向,起點在右端


          container: {
              backgroundColor:'blue',
              height:Dimensions.get('window').height,
              width:Dimensions.get('window').width,
              // 設置主軸方向
              flexDirection:'row-reverse'
          },
      
      

      效果:


      水平方向匣缘,起點在右
    • column(默認):主軸為垂直方向猖闪,起點在上


          container: {
              backgroundColor:'blue',
              height:Dimensions.get('window').height,
              width:Dimensions.get('window').width,
              // 設置主軸方向
              flexDirection:'column'
          },
      
      

      效果:


      主軸垂直,起點在上邊
    • column-reverse:主軸為垂直方向肌厨,起點在下


          container: {
              backgroundColor:'blue',
              height:Dimensions.get('window').height,
              width:Dimensions.get('window').width,
              // 設置主軸方向
              flexDirection:'column-reverse'
          },
      
      

      效果:


      主軸垂直培慌,起點在下邊
  • justifyContent(定義伸縮項目在主軸線的對齊方式)

    • flex-start(默認):伸縮項目向一行的起始位置靠齊


        container: {
            backgroundColor:'blue',
            height:Dimensions.get('window').height,
            width:Dimensions.get('window').width,
            // 設置子項目在主軸上的對齊方式
            justifyContent:'flex-start'
        },
    
    

    效果:


    伸縮項目向一行的起始位置靠齊
    • flex-end:伸縮項目向一行的結束位置靠齊


        container: {
            backgroundColor:'blue',
            height:Dimensions.get('window').height,
            width:Dimensions.get('window').width,
            // 設置子項目在主軸上的對齊方式
            justifyContent:'flex-end'
        },
    
    

    效果:


    伸縮項目向一行的結束位置靠齊
    • center:伸縮項目向一行的中間位置靠齊


        container: {
            backgroundColor:'blue',
            height:Dimensions.get('window').height,
            width:Dimensions.get('window').width,
            // 設置子項目在主軸上的對齊方式
            justifyContent:'center'
        },
    
    

    效果:


    伸縮項目向一行的中間位置靠齊
    • space-between:兩端對齊,項目之間的間隔都相等


        container: {
            backgroundColor:'blue',
            height:Dimensions.get('window').height,
            width:Dimensions.get('window').width,
            // 設置子項目在主軸上的對齊方式
            justifyContent:'space-between'
        },
    
    

    效果:


    兩端對齊柑爸,項目之間的間隔都相等
    • space-around:伸縮項目會平均分布在行內吵护,兩端保留一半的空間


        container: {
            backgroundColor:'blue',
            height:Dimensions.get('window').height,
            width:Dimensions.get('window').width,
            // 設置子項目在主軸上的對齊方式
            justifyContent:'space-around'
        },
    
    

    效果:


    伸縮項目會平均分布在行內何址,兩端保留一半的空間
  • alignItems(定義項目在交叉軸上如何對齊胁镐,可以把它看成側軸(垂直于主軸)的對齊方式)

    • flex-start(默認):側軸軸的起點對齊


        container: {
            backgroundColor:'blue',
            height:Dimensions.get('window').height,
            width:Dimensions.get('window').width,
            // 設置項目在側軸上如何對齊
            alignItems:'flex-start'
        },
    
    

    效果:


    側軸軸的起點對齊
    • flex-end:


        container: {
            backgroundColor:'blue',
            height:Dimensions.get('window').height,
            width:Dimensions.get('window').width,
            // 設置項目在側軸上如何對齊
            alignItems:'flex-end'
        },
    
    

    效果:


    側軸的終點對齊
    • center:側軸的中點對齊


        container: {
            backgroundColor:'blue',
            height:Dimensions.get('window').height,
            width:Dimensions.get('window').width,
            // 設置項目在側軸上如何對齊
            alignItems:'center'
        },
    
    

    效果:


    側軸的中點對齊
    • stretch(默認):如果項目沒有設置高度或設置為 auto,將占滿整個容器高度


        container: {
            backgroundColor:'blue',
            注釋掉高度
            // height:Dimensions.get('window').height,
            // width:Dimensions.get('window').width,
            // 設置項目在側軸上如何對齊
            alignItems:'stretch'
        },
    
    

    效果:


    如果項目沒有設置高度或設置為 auto份招,將占滿整個容器高度
  • flexWrap(默認情況下哼审,項目都排在一條軸線上,flex-wrap屬性定義如果一條軸線排不下,如何換行)

    • nowrap(默認):不換行


        container: {
            backgroundColor:'blue',
            height:Dimensions.get('window').height,
            width:Dimensions.get('window').width,
            // 設置主軸方向
            flexDirection:'row',
            // 設置換行的方式
            flexWrap:'nowrap'
        },
    
    

    效果:


    不換行
    • wrap:換行离福,第一行在上方


        container: {
            backgroundColor:'blue',
            height:Dimensions.get('window').height,
            width:Dimensions.get('window').width,
            // 設置主軸方向
            flexDirection:'row',
            // 設置換行的方式
            flexWrap:'wrap'
        },
    
    

    效果:


    換行絮识,第一行在上方

FlexBox 常用元素屬性


  • flex(flex-grow、flex-shrink、flex-basis三個屬性的縮寫,第二個參數(shù)和第三個參數(shù)是可選參數(shù)):默認值為 "0 1 auto"

    • 寬度 = 彈性寬度 * (flexGrow / sum(flexGorw))(重要)
    • 先來做一下實驗,看看flex到底是干嘛的徘郭,首先捆毫,我們先初始化一個新視圖江醇,便于理解


        // 入口
        export default class TestRN extends Component {
            render() {
                return (
                <View style={styles.container}>
                    <View style={{backgroundColor:'red', height:60, width:60}}></View>
                    <View style={{backgroundColor:'green', height:60, width:60}}></View>
                    <View style={{backgroundColor:'yellow', height:60, width:60}}></View>
                </View>
                );
            }
        }
    
        // 樣式
        const styles = StyleSheet.create({
            container: {
                backgroundColor:'blue',
                flex:1,
                // 設置主軸方向為水平,起點在左
                flexDirection:'row'
            },
        });
    
    

    效果:


    初始化視圖
    • 現(xiàn)在我們給紅色項目設置 flex 為1条辟,可以看到紅色項目的寬度填充了除去 綠色項目和黃色項目 的部分


        <View style={{backgroundColor:'red', height:60, width:60, flex:1}}></View>
    
    

    效果:


    示例一
    • 接著再給綠色項目也設置 flex 為1杭棵,可以看到紅色項目和綠色項目填充了 除黃色項目 的部分,并且紅色和綠色項目各占剩下空間的一半


        <View style={{backgroundColor:'red', height:60, width:60, flex:1}}></View>
        <View style={{backgroundColor:'green', height:60, width:60, flex:1}}></View>
    
    

    效果:


    示例二
    • 現(xiàn)在我們再設置黃色項目的 flex 為2,可以看出耘擂,紅色和綠色所占的空間和等同于黃色項目,并且紅色和綠色平分了除黃色項目以外的空間,現(xiàn)在我們應該能理解上面公式的意思了吧(項目寬度 = 父項目的寬度 * (子項目自身比例 / 所有父項目內子項目的比例))


        <View style={{backgroundColor:'red', height:60, width:60, flex:1}}></View>
        <View style={{backgroundColor:'green', height:60, width:60, flex:1}}></View>
        <View style={{backgroundColor:'yellow', height:60, width:60, flex:3}}></View>
    
    

    效果:


    示例三
    • 但是不知道各位發(fā)現(xiàn)了沒有秩霍,雖然我們每個子項目都同時設置了高度和寬度篙悯,但是卻只有寬度改變,而高度則一直保持我們設置的狀態(tài)铃绒,是不是 flex屬性 只對寬度有效呢鸽照?接下來我們來修改下代碼,看看是不是真的如我們想象的這樣 ———— 這里我們將綠色的高度去掉颠悬,可以看出矮燎,綠色項目的高度填充了整個父項目的高度


        <View style={{backgroundColor:'red', height:60, width:60, flex:1}}></View>
        <View style={{backgroundColor:'green', width:60, flex:1}}></View>
        <View style={{backgroundColor:'yellow', height:60, width:60, flex:3}}></View>
    
    

    效果:


    示例四
    • 總結以上的示例,可以看出赔癌,不管是否設置子項目的寬度诞外,flex都會忽略寬度,按照上面的公式進行縮放灾票,如果我們設置了高度峡谊,那么 flex 會遵循我們所設置的高度,不去進行拉伸刊苍,反之將會對高度進行拉伸
    • 根據(jù) flex 的特性既们,如果沒有設置 View 的尺寸情況下,使用 flex 也可以讓 View 占滿整個屏幕


        container: {
            backgroundColor:'blue',
            flex:1
        },
    
    
  • alignSelf(允許單個項目有與其它項目不一樣的對齊方式正什,可覆蓋 align-items屬性)

    • auto(默認):繼承父元素的alignItems屬性啥纸,如果沒有則切換為stretch


        subViewStyle2: {
            backgroundColor:'yellow',
            height:60,
            width:60,
            alignSelf:'auto'
        },
    
    

    效果:


    繼承父元素的alignItems屬性,如果沒有則切換為stretch
    • flex-start:項目從側軸的起點開始


        subViewStyle2: {
            backgroundColor:'yellow',
            height:60,
            width:60,
            alignSelf:'flex-start'
        },
    
    

    效果:


    項目從側軸的起點開始
    • flex-end:項目從側軸的終點開始


        subViewStyle2: {
            backgroundColor:'yellow',
            height:60,
            width:60,
            alignSelf:'flex-end'
        },
    
    

    效果:


    項目從側軸的終點開始
    • center:項目以側軸的中心為參照


        subViewStyle2: {
            backgroundColor:'yellow',
            height:60,
            width:60,
            alignSelf:'center'
        },
    
    

    效果:


    項目以側軸的中心為參照
    • stretch


        subViewStyle2: {
            backgroundColor:'yellow',
            height:60,
            width:60,
            alignSelf:'stretch'
        },
    
    

    效果:


    Snip20161027_22.png

我們 FlexBox 的使用就先簡單介紹到這里埠忘,在后續(xù)的文章中,會在實際的開發(fā)場景中帶大家更多更細致地講解 FlexBox,如果你覺得哪里寫得不好或者有誤馒索,麻煩留言或者用郵箱的方式聯(lián)系我莹妒,當然遇到問題也可以,最后如果喜歡我的文章绰上,還請點個贊并關注旨怠,讀者的肯定是對我們筆者最大的鼓勵,謝謝蜈块!

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
  • 序言:七十年代末鉴腻,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子百揭,更是在濱河造成了極大的恐慌爽哎,老刑警劉巖,帶你破解...
    沈念sama閱讀 207,248評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件器一,死亡現(xiàn)場離奇詭異课锌,居然都是意外死亡,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,681評論 2 381
  • 文/潘曉璐 我一進店門渺贤,熙熙樓的掌柜王于貴愁眉苦臉地迎上來雏胃,“玉大人,你說我怎么就攤上這事志鞍〔t亮!?“怎么了?”我有些...
    開封第一講書人閱讀 153,443評論 0 344
  • 文/不壞的土叔 我叫張陵固棚,是天一觀的道長统翩。 經(jīng)常有香客問我,道長玻孟,這世上最難降的妖魔是什么唆缴? 我笑而不...
    開封第一講書人閱讀 55,475評論 1 279
  • 正文 為了忘掉前任,我火速辦了婚禮黍翎,結果婚禮上面徽,老公的妹妹穿的比我還像新娘。我一直安慰自己匣掸,他們只是感情好趟紊,可當我...
    茶點故事閱讀 64,458評論 5 374
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著碰酝,像睡著了一般霎匈。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上送爸,一...
    開封第一講書人閱讀 49,185評論 1 284
  • 那天铛嘱,我揣著相機與錄音,去河邊找鬼袭厂。 笑死墨吓,一個胖子當著我的面吹牛,可吹牛的內容都是我干的纹磺。 我是一名探鬼主播帖烘,決...
    沈念sama閱讀 38,451評論 3 401
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼橄杨!你這毒婦竟也來了秘症?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 37,112評論 0 261
  • 序言:老撾萬榮一對情侶失蹤式矫,失蹤者是張志新(化名)和其女友劉穎乡摹,沒想到半個月后,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體采转,經(jīng)...
    沈念sama閱讀 43,609評論 1 300
  • 正文 獨居荒郊野嶺守林人離奇死亡趟卸,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 36,083評論 2 325
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片锄列。...
    茶點故事閱讀 38,163評論 1 334
  • 序言:一個原本活蹦亂跳的男人離奇死亡图云,死狀恐怖,靈堂內的尸體忽然破棺而出邻邮,到底是詐尸還是另有隱情竣况,我是刑警寧澤,帶...
    沈念sama閱讀 33,803評論 4 323
  • 正文 年R本政府宣布筒严,位于F島的核電站丹泉,受9級特大地震影響,放射性物質發(fā)生泄漏鸭蛙。R本人自食惡果不足惜摹恨,卻給世界環(huán)境...
    茶點故事閱讀 39,357評論 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望娶视。 院中可真熱鬧晒哄,春花似錦、人聲如沸肪获。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,357評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽孝赫。三九已至较木,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間青柄,已是汗流浹背伐债。 一陣腳步聲響...
    開封第一講書人閱讀 31,590評論 1 261
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留致开,地道東北人峰锁。 一個月前我還...
    沈念sama閱讀 45,636評論 2 355
  • 正文 我出身青樓,卻偏偏與公主長得像喇喉,于是被迫代替她去往敵國和親祖今。 傳聞我的和親對象是個殘疾皇子校坑,可洞房花燭夜當晚...
    茶點故事閱讀 42,925評論 2 344

推薦閱讀更多精彩內容

  • 前言 學習本系列內容需要具備一定 HTML 開發(fā)基礎拣技,沒有基礎的朋友可以先轉至 HTML快速入門(一) 學習 本人...
    珍此良辰閱讀 20,653評論 15 16
  • React Native組件View,其作用等同于iOS中的UIView, Android中的android.vi...
    哎呦有bug閱讀 819評論 0 0
  • 在React-Native中使用flexbox規(guī)則來指定某個組件的子元素的布局耍目。Flexbox可以在不同屏幕尺寸上...
    Coder_Answer閱讀 1,483評論 1 2
  • 前言 學習本系列內容需要具備一定 HTML 開發(fā)基礎膏斤,沒有基礎的朋友可以先轉至 HTML快速入門(一) 學習 本人...
    珍此良辰閱讀 3,182評論 1 12
  • 今天老師又按照成績自己挑位子,而我這次考的名次靠后邪驮,不能和我現(xiàn)在的同桌坐在一起了莫辨,因為視力不好,就選了第二排的邊...
    暖一杯咖啡閱讀 360評論 1 0