React Native 探索(四)Flexbox 佈局詳解

NiZerin發表於2020-02-19

相關文章
React Native探索系列

前言

在Android開發中我們有很多種佈局,比如LinearLayout和RelativeLayout,同樣在React Native也有它的佈局,這個佈局就是Flexbox佈局。在CSS、React Native和Android等都有它的身影。這一篇文章,我們就通過各種小例子來掌握React Native中的Flexbox佈局。

1.Flexbox佈局概述

Flexbox譯為彈性佈局(這裡我們簡稱Flex),是CSS的一種佈局方案,可以簡單、完整、響應式的實現各種頁面佈局。不只是在CSS中應用,在React Native也使用了Flex,基本和CSS中的Flex類似。甚至在Android開發中我們也會用到Flex,谷歌提供了基於Flex的FlexboxLayout,以便於處理複雜的佈局,因此,學習Flex佈局對於Android開發也是有幫助的。
採用Flex佈局的元素,稱為Flex容器(flex container),簡稱容器,它的所有子元素則是Flex容器的成員稱為Flex專案(flex item),簡稱專案。如下圖所示。

React Native 探索(四)Flexbox 佈局詳解

容器預設存在兩根軸:水平的主軸(main axis)和垂直的交叉軸(cross axis)。主軸的開始位置叫做main start,結束位置叫做main end。相似的,交叉軸的開始位置叫做cross start,結束位置叫做cross end。專案預設沿主軸排列,它在主軸上的長度叫做main size,交叉軸上的長度叫做cross size。

2.Flexbox容器屬性

在CSS(React)中容器屬性有6種,而在React Native中容器屬性有5種,它們分別是:

  • flexDirection
  • justifyContent
  • alignItems
  • alignContent
  • flexWrap

下面通過小例子來分別介紹這些Flexbox容器屬性。

flexDirection

flexDirection屬性可以決定主軸的方向(即專案的排列方向),它有以下取值:

  • column(預設值):主軸為垂直方向,起點在頂端。
  • row:主軸為水平方向,起點在左端。
  • column-reverse:主軸為垂直方向,起點在下端。
  • row-reverse:主軸為水平方向,起點在右端。

我們先將flexDirection設定為row,程式碼如下所示。

import React, {Component} from 'react';
import {AppRegistry, View} from 'react-native';
class FlexDirection extends Component {
    render() {
        return (
            <View style={{flex: 1, flexDirection: 'row', backgroundColor: 'ivory'}}>
                <View style={{width: 60, height: 60, backgroundColor: 'powderblue'}}/>
                <View style={{width: 60, height: 60, backgroundColor: 'skyblue'}}/>
                <View style={{width: 60, height: 60, backgroundColor: 'dodgerblue'}}/>
            </View>
        );
    }
}
AppRegistry.registerComponent('AwesomeProject', () => FlexDirection);複製程式碼

執行效果如下圖所示。

React Native 探索(四)Flexbox 佈局詳解

可以看出專案(子元件)是水平排列的,並且起點在左端。關於例子中的顏色設定可以檢視官網文件。我們也可以將flexDirection設定為row-reverse,來檢視效果:

React Native 探索(四)Flexbox 佈局詳解

可以看出Flex專案同樣是水平排列的,只是起點在右端。

justifyContent

justifyContent屬性用於定義專案在主軸上的對齊方式。它的取值有以下幾種:

  • flex-start(預設值):專案與父容器左端對齊。
  • flex-end:專案與父容器右端對齊。
  • center:居中。
  • space-between: 兩端對齊,並且專案間隔相等。
  • space-around:每個專案的兩側間隔相等,因此,專案之間的間隔是專案與父容器邊緣間隔的2倍。

我們將justifyContent設定為flex-end,程式碼如下所示。

import React, {Component} from 'react';
import {AppRegistry, View} from 'react-native';
class FlexDirection extends Component {
    render() {
        return (
            <View style={{flex: 1, flexDirection: 'row', justifyContent: 'flex-end', backgroundColor: 'ivory'}}>
                <View style={{width: 60, height: 60, backgroundColor: 'powderblue'}}/>
                <View style={{width: 60, height: 60, backgroundColor: 'skyblue'}}/>
                <View style={{width: 60, height: 60, backgroundColor: 'dodgerblue'}}/>
            </View>
        );
    }
}
AppRegistry.registerComponent('AwesomeProject', () => FlexDirection);複製程式碼

效果如下所示。

React Native 探索(四)Flexbox 佈局詳解

接下來我們分別設定justifyContent為flex-startcenter,效果分別如下所示。

React Native 探索(四)Flexbox 佈局詳解
......
React Native 探索(四)Flexbox 佈局詳解

接下來我們分別設定justifyContent為space-betweenspace-around來檢視它們有什麼區別,效果分別如下所示。

React Native 探索(四)Flexbox 佈局詳解
......
React Native 探索(四)Flexbox 佈局詳解

上面左圖是設定了space-between,可以看出最左邊和最右邊的專案都和父容器沒有間隔,並且專案之間的間隔是相等的。右圖的是space-around,最左邊和最右邊的專案都和父容器有間隔,並且專案之間的間隔是專案與父容器的間隔的2倍。

alignItems

alignItems用於定義專案在交叉軸上的對齊方式。它的取值有以下幾種:

  • flex-start:專案與父容器的頂部對齊。
  • flex-end:專案與父容器的底部對齊。
  • center:居中。
  • baseline :專案的第一行文字的基線對齊。
  • stretch:(預設值)如果專案未設定高度或者高度設為auto,專案將佔滿整個容器的高度,否則該取值不會生效。

將alignItems設定為flex-end,程式碼如下所示。

import React, {Component} from 'react';
import {AppRegistry, View} from 'react-native';
class FlexDirection extends Component {
    render() {
        return (
            <View style={{
                flex: 1,
                flexDirection: 'row',
                justifyContent: 'center',
                alignItems: 'flex-end',
                backgroundColor: 'ivory'
            }}>
                <View style={{width: 60, height: 60, backgroundColor: 'powderblue'}}/>
                <View style={{width: 60, height: 60, backgroundColor: 'skyblue'}}/>
                <View style={{width: 60, height: 60, backgroundColor: 'dodgerblue'}}/>
            </View>
        );
    }
}
AppRegistry.registerComponent('AwesomeProject', () => FlexDirection);複製程式碼

效果如下圖所示。

React Native 探索(四)Flexbox 佈局詳解

看到flex-end的效果,flex-start和center的效果也很容易知道。我們接下來將alignItems設定為stretch,需要注意的是,當專案沒有設定高度或者高度設為auto時,stretch才會生效。這裡為了驗證效果,將所有專案的高度設定為auto。

import React, {Component} from 'react';
import {AppRegistry, View} from 'react-native';
class FlexDirection extends Component {
    render() {
        return (
            <View style={{
                flex: 1,
                flexDirection: 'row',
                justifyContent: 'center',
                alignItems: 'stretch',
                backgroundColor: 'ivory'
            }}>
                <View style={{width: 60, height: 'auto', backgroundColor: 'powderblue'}}/>
                <View style={{width: 60, height: 'auto', backgroundColor: 'skyblue'}}/>
                <View style={{width: 60, height: 'auto', backgroundColor: 'dodgerblue'}}/>
            </View>
        );
    }
}
AppRegistry.registerComponent('AwesomeProject', () => FlexDirection);複製程式碼

效果如下圖所示。

React Native 探索(四)Flexbox 佈局詳解

可以看出,當alignItems設定為stretch時,專案會佔滿整個容器的高度。

alignContent

alignContent用於多行專案在交叉軸上的對齊方式。如果專案只有一行,該屬性是不起作用的。它的取值有 flex-start 、flex-end 、 center 、space-between 、 space-around 和 stretch,只比justifyContent的取值多了一個stretch(預設值,含義和alignItems的stretch類似),alignContent的取值的含義和justifyContent的取值的含義類似,這裡就不做舉例了。

flexWrap

flexWrap用於設定如果一行排不下,如何換行。它的取值有以下幾種:

  • nowrap(預設):不換行。
  • wrap:換行,第一行在上方。

我們將flexWrap設定為wrap,程式碼如下所示。

import React, {Component} from 'react';
import {AppRegistry, View} from 'react-native';
class FlexDirection extends Component {
    render() {
        return (
            <View style={{
                flex: 1,
                flexDirection: 'row',
                alignItems: 'flex-start',
                flexWrap: 'wrap',
                backgroundColor: 'ivory'
            }}>
                <View style={{width: 100, height: 60, backgroundColor: 'powderblue'}}/>
                <View style={{width: 100, height: 60, backgroundColor: 'skyblue'}}/>
                <View style={{width: 100, height: 60, backgroundColor: 'dodgerblue'}}/>
                <View style={{width: 100, height: 60, backgroundColor: 'blue'}}/>
            </View>
        );
    }
}
AppRegistry.registerComponent('AwesomeProject', () => FlexDirection);複製程式碼

效果如下所示。

React Native 探索(四)Flexbox 佈局詳解

3.Flexbox專案屬性

在React Native中專案屬性有很多中,具體的可以參考:Layout Props。這裡介紹flexGrow、flexShrink、flexBasis、flex和alignSelf。

flexGrow

flexGrow屬性定義專案的放大比例,預設為0,即如果存在剩餘空間,也不放大。

import React, {Component} from 'react';
import {AppRegistry, View} from 'react-native';
class FlexDirection extends Component {
    render() {
        return (
            <View style={{
                flex: 1,
                flexDirection: 'row',
                alignItems: 'flex-start',
                backgroundColor: 'ivory'
            }}>
                <View style={{width: 50, height: 50, flexGrow: 1, backgroundColor: 'powderblue'}}/>
                <View style={{width: 50, height: 50, flexGrow: 2, backgroundColor: 'skyblue'}}/>
                <View style={{width: 50, height: 50, flexGrow: 1, backgroundColor: 'dodgerblue'}}/>
            </View>
        );
    }
}
AppRegistry.registerComponent('AwesomeProject', () => FlexDirection);複製程式碼

我們將第二個專案flexGrow設定為2,其他的專案flexGrow設定為1,這樣第二個專案所佔的剩餘空間是其他專案的兩倍。如下圖所示。

React Native 探索(四)Flexbox 佈局詳解

flexShrink

flexShrink屬性定義了專案的縮小比例,預設為1,即如果空間不足,該專案將縮小。

import React, {Component} from 'react';
import {AppRegistry, View} from 'react-native';
class FlexDirection extends Component {
    render() {
        return (
            <View style={{
                flex: 1,
                flexDirection: 'row',
                alignItems: 'flex-start',
                backgroundColor: 'ivory'
            }}>
                <View style={{width: 120, height: 50, flexShrink: 1, backgroundColor: 'powderblue'}}/>
                <View style={{width: 120, height: 50, flexShrink: 0, backgroundColor: 'skyblue'}}/>
                <View style={{width: 120, height: 50, flexShrink: 1, backgroundColor: 'dodgerblue'}}/>
                <View style={{width: 120, height: 50, flexShrink: 1, backgroundColor: 'blue'}}/>
            </View>
        );
    }
}
AppRegistry.registerComponent('AwesomeProject', () => FlexDirection);複製程式碼

我們將第二個專案的flexShrink設定為0,其他的專案都為1,這樣當空間不足時,第二個專案不會縮小,如下圖所示。

React Native 探索(四)Flexbox 佈局詳解

flexBasis

flexBasis屬性定義了專案的初始寬度。它的預設值為auto,即專案的本來的寬度。我們知道width也可以用來設定專案的寬度,如果專案同時設定了width和flexBasis,那麼flexBasis會覆蓋width的值。

import React, {Component} from 'react';
import {AppRegistry, View} from 'react-native';
class FlexDirection extends Component {
    render() {
        return (
            <View style={{
                flex: 1,
                flexDirection: 'row',
                alignItems: 'flex-start',
                backgroundColor: 'ivory'
            }}>
                <View style={{width: 120, height: 50, flexBasis: 60, backgroundColor: 'powderblue'}}/>
                <View style={{width: 120, height: 50, backgroundColor: 'skyblue'}}/>
                <View style={{width: 120, height: 50, backgroundColor: 'dodgerblue'}}/>
                <View style={{width: 120, height: 50, backgroundColor: 'blue'}}/>
            </View>
        );
    }
}
AppRegistry.registerComponent('AwesomeProject', () => FlexDirection);複製程式碼

效果如下圖所示。

React Native 探索(四)Flexbox 佈局詳解

flex

如果我們每次都要設定flex-grow、flex-shrink和 flex-basis屬性,顯然有些麻煩,這時我們可以用flex 屬性,它是 flex-grow、flex-shrink 和 flex-basis 屬性的簡寫屬性,預設值為0 1 auto,其中後兩個屬性可選。關於flex這裡就不做舉例了。

alignSelf

alignSelf屬性和alignItems屬性類似,只不過alignSelf作用於專案,它允許單個專案有與其他專案不一樣的對齊方式,並且覆蓋alignItems屬性。alignSelf預設值為為auto,表示繼承父元素的alignItems屬性,如果沒有父元素,則等同於stretch。alignSelf有五種取值:auto、flex-start、flex-end、center、baseline和stretch,除了多了auto,其他的取值都和alignItems的取值含義一樣。

import React, {Component} from 'react';
import {AppRegistry, View} from 'react-native';
class FlexDirection extends Component {
    render() {
        return (
            <View style={{
                flex: 1,
                flexDirection: 'row',
                alignItems: 'flex-start',
                backgroundColor: 'ivory'
            }}>
                <View style={{width: 60, height: 60, alignSelf: 'flex-end', backgroundColor: 'powderblue'}}/>
                <View style={{width: 60, height: 60, alignSelf: 'center', backgroundColor: 'skyblue'}}/>
                <View style={{width: 60, height: 'auto', alignSelf: 'stretch', backgroundColor: 'dodgerblue'}}/>
                <View style={{width: 60, height: 60, alignSelf: 'auto', backgroundColor: 'blue'}}/>
            </View>
        );
    }
}
AppRegistry.registerComponent('AwesomeProject', () => FlexDirection);複製程式碼

執行效果如下所示。

React Native 探索(四)Flexbox 佈局詳解

好了,關於Flexbox佈局就講到這,還有很多屬性這裡沒有提到,比如:margin、padding、marginRight和maxWidth等等,這些屬性我們一看名字就知道它的作用(Android開發者角度),因此這裡就不多介紹了,更多的屬性請查閱官方文件

參考資料
官方文件
Flex 佈局教程:語法篇---阮一峰
React-Native之flexbox佈局篇


歡迎關注我的微信公眾號,第一時間獲得部落格更新提醒,以及更多成體系的Android相關原創技術乾貨。
掃一掃下方二維碼或者長按識別二維碼,即可關注。

React Native 探索(四)Flexbox 佈局詳解

相關文章