React Native 佈局詳解
一、概述
一款優秀的APP離不開一個漂亮的UI,一個漂亮的UI又是由各種佈局組合而成,因此APP的開發過程中,佈局的實現是很重要的一部分。在React Native(以下簡稱RN)開發中,RN為我們提供了FlexBox(彈性框)進行佈局,FlexBox功能十分強大,它提供了在不同尺寸裝置上都能保持一致的佈局方式,接下來我將從FlexBox著手詳細講解RN佈局。
二、RN中的尺寸
在分析FlexBox之前,首先得清楚一個概念,即RN中的“寬、高、字型大小”。一個一個元件的高度和寬度決定了它在螢幕上的尺寸,也就是大小。在React Native中尺寸是沒有單位的,表示的是與裝置畫素密度無關的邏輯畫素點。
下面看一個簡單例子:
- RN中的佈局
<View style={{height: 100, width: 300, margin: 20, backgroundColor:'#fab27b'}}>
<Text style={ {fontSize:16,margin:20}}>尺寸</Text>
</View>
- Android原生中的佈局
<LinearLayout
android:layout_width="300dp"
android:layout_height="100dp"
android:layout_margin="20dp"
android:background="#fab27b">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_margin="20dp"
android:text="尺寸"
android:textSize="16sp"/>
</LinearLayout>
最後效果圖如下:左邊為RN,右邊為Android。
其實RN在android上執行時,View的寬300 高100 會被解釋成寬300dp和高100dp,字型大小16會解釋為16sp。
同時RN也為我們提供相關API來獲取手機螢幕的大小。
var {height, width} = Dimensions.get('window');
三、RN之彈性寬高(Flex)
很多時候,我們都有讓子元件填充父元件剩餘空間這種需求,RN中為我們提供了Flex這種彈性佈局樣式。在元件樣式中使用flex可以使其在可利用的空間中動態地擴張或收縮。
Flex樣式與android中的layout_weight屬性很類似,我們可以使用flex:1來指定某個元件擴張以撐滿所有剩餘的空間。如果有多個並列的子元件使用了flex:1,則這些子元件會平分父容器中剩餘的空間。如果這些並列的子元件的flex值不一樣,則誰的值更大,誰佔據剩餘空間的比例就更大(即佔據剩餘空間的比等於並列元件間flex值的比)。
具體可以看看如下例項:
<View style={{height:100, marginTop:10}}>
<View style={{flex:1, backgroundColor: 'powderblue'}} />
<View style={{flex:2, backgroundColor: 'skyblue'}} />
<View style={{flex:3, backgroundColor: 'steelblue'}} />
</View>
效果圖如下:
在使用flex的時候,有一個十分重要的注意點,即父佈局需要有固定的寬高或者父佈局也需要設定flex,否則,子元件是無法顯示的,如下:
<View>
<View style={{flex:1, backgroundColor: 'powderblue'}} />
<View style={{flex:2, backgroundColor: 'skyblue'}} />
<View style={{flex:3, backgroundColor: 'steelblue'}} />
</View>
由於無法知道外層view的寬高,所以子view的寬高也是無法確定的。
四、RN之Flexbox佈局
RN為我們提供了強大的佈局模式即Flexbox佈局,使用這種佈局可以簡單快速地完成某個元件的子元素的佈局,同時也可以在不同螢幕尺寸上提供一致的佈局結構。Flexbox中有三個很重要的樣式屬性(flexDirection、alignItems和 justifyContent),使用這三個樣式屬性就已經能滿足大多數佈局需求。
- flexDirection樣式
flexDirection,它決定佈局的主軸,確定子元素應該哪個軸進行排列。它可取值有:
value | description |
---|---|
row | 子元素是應該沿著水平軸方向排列 |
row-reverse | 子元素是應該沿著水平軸方向倒序排列 |
column | 子元素是應該沿著垂直軸方向排列 |
column-reverse | 子元素是應該沿著垂直軸方向倒序排列 |
預設情況下,flexDirection的取值為column,下面以例項來看看具體的效果:
<View style={{height:300, backgroundColor: '#b2d235',marginTop:10}}>
<View style={{width: 80, height: 60, backgroundColor: 'powderblue'}} ><Text>佈局一</Text></View>
<View style={{width: 80, height: 60, backgroundColor: 'skyblue'}} ><Text>佈局二</Text></View>
<View style={{width: 80, height: 60, backgroundColor: 'steelblue'}} ><Text>佈局三</Text></View>
</View>
如下圖:
<View style={{height:100, backgroundColor: '#b2d235', flexDirection:'row', marginTop:10}}>
<View style={{width: 80, height: 60, backgroundColor: 'powderblue'}} ><Text>佈局一</Text></View>
<View style={{width: 80, height: 60, backgroundColor: 'skyblue'}} ><Text>佈局二</Text></View>
<View style={{width: 80, height: 60, backgroundColor: 'steelblue'}} ><Text>佈局三</Text></View>
</View>
<View style={{height:100, backgroundColor: '#b2d235', flexDirection:'row-reverse', marginTop:10}}>
<View style={{width: 80, height: 60, backgroundColor: 'powderblue'}} ><Text>佈局一</Text></View>
<View style={{width: 80, height: 60, backgroundColor: 'skyblue'}} ><Text>佈局二</Text></View>
<View style={{width: 80, height: 60, backgroundColor: 'steelblue'}} ><Text>佈局三</Text></View>
</View>
<View style={{height:300, backgroundColor: '#b2d235', flexDirection:'column-reverse', marginTop:10}}>
<View style={{width: 80, height: 60, backgroundColor: 'powderblue'}} ><Text>佈局一</Text></View>
<View style={{width: 80, height: 60, backgroundColor: 'skyblue'}} ><Text>佈局二</Text></View>
<View style={{width: 80, height: 60, backgroundColor: 'steelblue'}} ><Text>佈局三</Text></View>
</View>
- justifyContent樣式
在元件的style中指定justifyContent可以決定其子元素沿著主軸的排列方式。例如子元素應該靠近主軸的起始端還是末尾段分佈呢亦或應該均勻分佈等等。它的可選項值如下,預設值為flex-start。
value | description |
---|---|
flex-start | 子元素沿著主軸方向上起始位置依次顯示 |
center | 子元素沿著主軸方向上居中顯示 |
flex-end | 子元素沿著主軸方向上末尾位置依次顯示 |
space-around | 子元素在主軸方向上兩側間隔相等方式顯示,因此元素之間的間隔比元素與邊框的間隔大一倍。 |
space-between | 子元素在主軸方向上兩端對齊,專案之間的間隔都相等。 |
<View style={{height:100, backgroundColor: '#b2d235', flexDirection:'row', marginTop:10}}>
<View style={{width: 80, height: 60, backgroundColor: 'powderblue'}} ><Text>佈局一</Text></View>
<View style={{width: 80, height: 60, backgroundColor: 'skyblue'}} ><Text>佈局二</Text></View>
<View style={{width: 80, height: 60, backgroundColor: 'steelblue'}} ><Text>佈局三</Text></View>
</View>
具體顯示如下圖,第一個是如上佈局顯示狀態。
- alignItems樣式
justifyContent決定子元素沿著主軸的排列方式,那麼當然存在一個樣式決定其子元素沿著次軸(與主軸垂直的軸)的排列方式,它就是alignItems樣式。它的可選項值如下,預設值為flex-start。
value | description |
---|---|
flex-start | 子元素沿著次軸方向上起始位置依次顯示 |
center | 子元素沿著次軸方向上居中顯示 |
flex-end | 子元素沿著次軸方向上末尾位置依次顯示 |
stretch | 子元素在次軸方向拉伸顯示。 |
<View style={{height:70, backgroundColor: '#b2d235',
flexDirection:'row', justifyContent:'flex-start', alignItems:'flex-start', marginTop:40}}>
<View style={{width: 90, height: 60, backgroundColor: 'powderblue'}} ><Text>佈局一</Text></View>
<View style={{width: 70, height: 40, backgroundColor: 'skyblue'}} ><Text>佈局二</Text></View>
<View style={{width: 50, height: 20, backgroundColor: 'steelblue'}} ><Text>佈局三</Text></View>
</View>
具體顯示如下圖,第一個是如上佈局顯示狀態。
需要注意的是alignItems值為stretch的情況,要使stretch選項生效的話,子元素在次軸方向上不能有固定的尺寸。如下:
能夠熟練運用如上三個樣式,基本上可以滿足我們大多數的佈局需求,如上部分僅只屬於佈局的最基礎部分,要運用好佈局,RN還提供了很多其他的樣式。
五、其他重要佈局樣式
1. alignSelf
決定了元素在父元素的次軸方向的排列方式(此樣式設定在子元素上),其值會覆蓋父元素的alignItems的值。
可取值有 enum('auto', 'flex-start', 'flex-end', 'center', 'stretch')
例如:
<View style={{height:70, backgroundColor: '#b2d235',
flexDirection:'row', justifyContent:'flex-start', alignItems:'center', marginTop:40}}>
<View style={{width: 90, height: 60, backgroundColor: 'powderblue'}} ><Text>佈局一</Text></View>
<View style={{width: 70, height: 40, backgroundColor: 'skyblue', alignSelf:'flex-start'}} ><Text>佈局二</Text></View>
<View style={{width: 50, height: 20, backgroundColor: 'steelblue', alignSelf:'center'}} ><Text>佈局三</Text></View>
<View style={{width: 50, height: 40, backgroundColor: '#4e72b8', alignSelf:'flex-end'}} ><Text>佈局四</Text></View>
<View style={{width: 50, backgroundColor: '#2a5caa', alignSelf:'stretch'}} ><Text>佈局五</Text></View>
</View>
顯示如下:
2. flexWrap
該樣式應用在父容器中,類似於android的流式佈局。 可取值有enum('nowrap ', 'wrap', 'wrap-reverse')
nowrap:預設值,不換行
wrap:換行,第一行在上方
wrap-reverse:換行,第一行在下方。(和wrap相反)
例如:
<View style={{backgroundColor: '#6d8346',marginTop:10, flexDirection:'row', flexWrap:'wrap'}}>
<View style={{width: 40, height: 40, backgroundColor: 'powderblue', margin:5}} ><Text>佈局一</Text></View>
<View style={{width: 40, height: 40, backgroundColor: 'skyblue', margin:5}} ><Text>佈局二</Text></View>
<View style={{width: 40, height: 40, backgroundColor: 'steelblue', margin:5}} ><Text>佈局三</Text></View>
<View style={{width: 40, height: 40, backgroundColor: 'powderblue', margin:5}} ><Text>佈局一</Text></View>
<View style={{width: 40, height: 40, backgroundColor: 'skyblue', margin:5}} ><Text>佈局二</Text></View>
<View style={{width: 40, height: 40, backgroundColor: 'steelblue', margin:5}} ><Text>佈局三</Text></View>
<View style={{width: 40, height: 40, backgroundColor: 'powderblue', margin:5}} ><Text>佈局一</Text></View>
<View style={{width: 40, height: 40, backgroundColor: 'skyblue', margin:5}} ><Text>佈局二</Text></View>
<View style={{width: 40, height: 40, backgroundColor: 'steelblue', margin:5}} ><Text>佈局三</Text></View>
<View style={{width: 40, height: 40, backgroundColor: 'powderblue', margin:5}} ><Text>佈局一</Text></View>
<View style={{width: 40, height: 40, backgroundColor: 'skyblue', margin:5}} ><Text>佈局二</Text></View>
<View style={{width: 40, height: 40, backgroundColor: 'steelblue', margin:5}} ><Text>佈局三</Text></View>
</View>
顯示如下:
3. position
position表示當前描述的位置是相對位置還是絕對定位的。可以取值為relative(預設值)或者absolute,與位置相關樣式設定鍵還有:top、bottom、left、right。它們都是數值型別,表示描述的位置從左或者右多少位置顯示,或者從上或者下多少位置顯示,這些值只有當 position為absolute時才有效。 例如:
<View style={{height:100, backgroundColor: '#b2d235', marginTop:40}}>
<View style={{width: 90, height: 60, backgroundColor: 'powderblue',position:'absolute'}} ><Text>佈局一</Text></View>
<View style={{width: 70, height: 40, backgroundColor: 'skyblue', position:'absolute', left: 100, top:10}} ><Text>佈局二</Text></View>
<View style={{width: 50, height: 20, backgroundColor: 'steelblue', position:'absolute', left: 100, top:60}} ><Text>佈局三</Text></View>
</View>
顯示如下:
4. 邊框相關
borderWidth:邊框寬度
borderLeftWidth:邊框左邊寬度
borderRightWidth:邊框右邊寬度
borderTopWidth:邊框上邊寬度
borderBottomWidth:邊框下邊寬度
5.外邊距相關
margin:一個元件所有外邊距的寬度,包括上下左右。
marginLeft:左邊距寬度
marginRight:右邊距寬度
marginTop:上邊距寬度
marginBottom:下邊距寬度
marginHorizontal:等價marginLeft和marginRight
marginVertical:等價marginTop和marginBottom
6、內邊距相關
padding:一個元件所有內邊距的寬度,包括上下左右。
paddingLeft:左邊距寬度
paddingRight:右邊距寬度
paddingTop:上邊距寬度
paddingBottom:下邊距寬度
paddingHorizontal:等價marginLeft和marginRight
paddingVertical:等價marginTop和marginBottom