FlexBox
React Native是采用FlexBox(彈性)布局催式,使用FlexBox規(guī)則來(lái)指定某個(gè)組件的子元素的布局,F(xiàn)lexBox提供了在不同尺寸設(shè)備上都能保持一致的布局方式推姻,它是CSS3彈性框布局規(guī)范,因此熟悉前端的同學(xué)可能對(duì)此感到很親切,不過(guò)React Native的FlexBox與web上的CSS也存在少許差異置森。
首先是默認(rèn)值不同:flexDirection的默認(rèn)值是column而不是row(這一點(diǎn)與手機(jī)客戶端開(kāi)發(fā)一致),而flex也只能指定一個(gè)數(shù)字值。
FlexBox類(lèi)似android開(kāi)發(fā)中的LinearLayout(線性布局)赠叼,不過(guò)還是有許多不同之處,千萬(wàn)不能用LinearLayout的知識(shí)生搬硬套违霞。
在學(xué)習(xí)FlexBox屬性之前嘴办,讓我們先了解一個(gè)概念:主軸和次軸
- 主軸即子元素線性排列的方向,如圖水平軸為主軸买鸽,即子元素按水平方向排列涧郊。
- 次軸即與主軸垂直的軸,在圖中為縱軸眼五。
父視圖屬性(容器屬性)
- flexDirection
- flexWrap
- justifyContent
- alignItems
flexDirection
flexDirection指定布局的主軸方向妆艘,定義了父視圖中的子元素子元素是應(yīng)該沿著水平軸(row)方向排列彤灶,還是沿著豎直軸(column)方向排列。如果未指定批旺,默認(rèn)值是豎直軸(column)方向幌陕。(這點(diǎn)與css中不同,但與android的LinearLayout是一致的汽煮,默認(rèn)豎直方向排列)
flexDirection: row | row-reverse | column | column-reverse;
- row: 從左向右依次排列
- row-reverse: 從右向左依次排列
- column(default): 默認(rèn)的排列方式搏熄,從上向下排列
- column-reverse: 從下向上排列
代碼示例:
import React,{Component} from 'react';
import {
Text,
View,
StyleSheet
} from 'react-native';
export default class FlexDirectionDemo extends Component {
render() {
return (
<View style={Styles.container}>
<Text style={Styles.subtitle}>flexDirectionDemo:row</Text>
<View style={Styles.box1}>
<Text style={Styles.item}>1</Text>
<Text style={Styles.item}>2</Text>
<Text style={Styles.item}>3</Text>
<Text style={Styles.item}>4</Text>
</View>
<Text style={Styles.subtitle}>flexDirectionDemo:row-reverse</Text>
<View style={Styles.box2}>
<Text style={Styles.item}>1</Text>
<Text style={Styles.item}>2</Text>
<Text style={Styles.item}>3</Text>
<Text style={Styles.item}>4</Text>
</View>
<Text style={Styles.subtitle}>flexDirectionDemo:column</Text>
<View style={Styles.box3}>
<Text style={Styles.item}>1</Text>
<Text style={Styles.item}>2</Text>
<Text style={Styles.item}>3</Text>
<Text style={Styles.item}>4</Text>
</View>
<Text style={Styles.subtitle}>flexDirectionDemo:column-reverse</Text>
<View style={Styles.box4}>
<Text style={Styles.item}>1</Text>
<Text style={Styles.item}>2</Text>
<Text style={Styles.item}>3</Text>
<Text style={Styles.item}>4</Text>
</View>
</View>
);
}
}
const Styles = StyleSheet.create({
container: {
backgroundColor: "#ffffff",
flex: 1,
},
subtitle:{
backgroundColor: '#ffffff',
alignItems: 'center'
},
box1:{
height: 60,
backgroundColor: '#333333',
flexDirection:"row",
},
box2:{
height: 60,
backgroundColor: '#333333',
flexDirection:"row-reverse",
},
box3:{
height: 180,
backgroundColor: '#333333',
flexDirection:"column",
},
box4:{
height: 180,
backgroundColor: '#333333',
flexDirection:"column-reverse",
},
item: {
backgroundColor: "#f0f",
width:30,
margin: 4,
height: 30,
},
})
flexWrap
flexWrap定義了子元素在父視圖內(nèi)是否允許多行排列,默認(rèn)為nowrap(不換行)
flexWrap: nowrap | wrap ;
- nowrap (默認(rèn)):不換行逗物,可能導(dǎo)致溢出。
- wrap 換行瑟俭,子元素在一行排列不下時(shí)翎卓,就進(jìn)行多行排列。
代碼示例:
import React,{Component} from 'react';
import {
Text,
View,
StyleSheet
} from 'react-native';
export default class FlexWrapDemo extends Component {
render() {
return (
<View style={Styles.container}>
<Text style={Styles.subtitle}>flexWrap:nowrap</Text>
<View style={Styles.box1}>
<Text style={Styles.item}>1</Text>
<Text style={Styles.item}>2</Text>
<Text style={Styles.item}>3</Text>
<Text style={Styles.item}>4</Text>
</View>
<Text style={Styles.subtitle}>flexWrap:wrap</Text>
<View style={Styles.box2}>
<Text style={Styles.item}>1</Text>
<Text style={Styles.item}>2</Text>
<Text style={Styles.item}>3</Text>
<Text style={Styles.item}>4</Text>
</View>
</View>
);
}
}
const Styles = StyleSheet.create({
container: {
backgroundColor: "#ffffff",
flex: 1,
},
subtitle:{
backgroundColor: '#ffffff',
alignItems: 'center'
},
box1:{
height: 150,
backgroundColor: '#333333',
flexDirection:"row",
flexWrap:"nowrap",
},
box2:{
height: 150,
backgroundColor: '#333333',
flexDirection:"row",
flexWrap:"wrap",
},
item: {
backgroundColor: "#f0f",
width:100,
margin: 4,
height: 50,
},
})
justifyContent
justifyContent定義了子元素在主軸上的對(duì)齊方式摆寄。
justifyContent: flex-start | flex-end | center | space-between | space-
around;
- flex-start(默認(rèn)值):左對(duì)齊
- flex-end:右對(duì)齊
- center: 居中
- space-between:兩端對(duì)齊失暴,子元素之間的間隔都相等。
- space-around:每個(gè)子元素兩側(cè)的間隔相等微饥。所以逗扒,子元素之間的間隔比子元素與邊框的間隔大一倍。
import React,{Component} from 'react';
import {
Text,
View,
StyleSheet
} from 'react-native';
export default class JustifyContentDemo extends Component {
render() {
return (
<View style={Styles.container}>
<Text style={Styles.subtitle}>JustifyContent:flex-start</Text>
<View style={Styles.box1}>
<Text style={Styles.item}>1</Text>
<Text style={Styles.item}>2</Text>
<Text style={Styles.item}>3</Text>
</View>
<Text style={Styles.subtitle}>JustifyContent:flex-end</Text>
<View style={Styles.box2}>
<Text style={Styles.item}>1</Text>
<Text style={Styles.item}>2</Text>
<Text style={Styles.item}>3</Text>
</View>
<Text style={Styles.subtitle}>JustifyContent:center</Text>
<View style={Styles.box3}>
<Text style={Styles.item}>1</Text>
<Text style={Styles.item}>2</Text>
<Text style={Styles.item}>3</Text>
</View>
<Text style={Styles.subtitle}>JustifyContent:space-between</Text>
<View style={Styles.box4}>
<Text style={Styles.item}>1</Text>
<Text style={Styles.item}>2</Text>
<Text style={Styles.item}>3</Text>
</View>
<Text style={Styles.subtitle}>JustifyContent:space-around</Text>
<View style={Styles.box5}>
<Text style={Styles.item}>1</Text>
<Text style={Styles.item}>2</Text>
<Text style={Styles.item}>3</Text>
</View>
</View>
);
}
}
const Styles = StyleSheet.create({
container: {
backgroundColor: "#0ff",
flex: 1,
},
subtitle:{
backgroundColor: '#ffffff',
alignItems: 'center'
},
box1:{
height: 100,
backgroundColor: '#333333',
flexDirection:"row",
justifyContent:"flex-start",
},
box2:{
height: 100,
backgroundColor: '#333333',
flexDirection:"row",
justifyContent:"flex-end",
},
box3:{
height: 100,
backgroundColor: '#333333',
flexDirection:"row",
justifyContent:"center",
},
box4:{
height: 100,
backgroundColor: '#333333',
flexDirection:"row",
justifyContent:"space-between",
},
box5:{
height: 100,
backgroundColor: '#333333',
flexDirection:"row",
justifyContent:"space-around",
},
item: {
backgroundColor: "#f0f",
width:50,
margin: 4,
height: 50,
},
})
alignItems
alignItems定義子元素在次軸(與主軸垂直的軸)上的對(duì)齊方式欠橘。
alignItems: flex-start | flex-end | center | stretch;
- flex-start:次軸的起點(diǎn)對(duì)齊矩肩。
- flex-end:次軸的終點(diǎn)對(duì)齊。
- center:次軸的中點(diǎn)對(duì)齊肃续。
- stretch(默認(rèn)值):子元素在次軸方向充滿整個(gè)容器的高度或?qū)挾取?/li>
注意:要使stretch選項(xiàng)生效的話黍檩,子元素在次軸方向上不能有固定的尺寸
import React,{Component} from 'react';
import {
Text,
View,
StyleSheet
} from 'react-native';
export default class AlignItemsDemo extends Component {
render() {
return (
<View style={Styles.container}>
<Text style={Styles.subtitle}>alignItems</Text>
<View style={Styles.box}>
<Text style={Styles.item}>1</Text>
<Text style={Styles.item}>2</Text>
<Text style={Styles.item}>3</Text>
<Text style={Styles.item_flex_end}>4</Text>
<Text style={Styles.item}>5</Text>
</View>
</View>
);
}
}
const Styles = StyleSheet.create({
container: {
backgroundColor: "#0ff",
height: 300,
},
subtitle:{
backgroundColor: '#ffffff',
alignItems: 'center'
},
box:{
flex: 1,
backgroundColor: '#333333',
flexDirection:"row",
alignItems:"flex-end", //通過(guò)設(shè)置flex-start | flex-end | center | stretch;各種值可以看看效果
},
item: {
backgroundColor: "#f0f",
flexGrow: 1,
margin: 4,
height: 100,
},
item_flex_end: {
backgroundColor: "#f0f",
flexGrow: 1,
margin: 4,
height: 100,
alignSelf: "flex-end",
}
})
子視圖屬性
- alignSelf
- flex
alignSelf
alignSelf屬性以屬性定義了flex容器內(nèi)被選中子元素的對(duì)齊方式。允許該子元素有與其他子元素不一樣的對(duì)齊方式始锚,可覆蓋alignItems 屬性刽酱。
alignSelf: auto | flex-start | flex-end | center | stretch;
默認(rèn)值為auto,表示繼承父元素的alignItems屬性瞧捌,如果沒(méi)有父元素棵里,則等同于stretch。
該屬性可能取5個(gè)值姐呐,除了auto殿怜,其他都與alignItems屬性完全一致。
以下圖為例曙砂,該圖中父元素的alignItems屬性為flex-start稳捆,所以子元素按照圖alignItems
中的flex-start所示,而第三個(gè)子元素設(shè)置了其alignSelf屬性為flex-end, 因此第三個(gè)子元素的alignSelf屬性覆蓋父元素的alignItems屬性變?yōu)榕c底部對(duì)齊麦轰。
代碼示例:
import React,{Component} from 'react';
import {
Text,
View,
StyleSheet
} from 'react-native';
export default class AlignSelfDemo extends Component {
render() {
return (
<View style={AlignSelfDemoStyle.container}>
<Text style={AlignSelfDemoStyle.subtitle}>alignSelf</Text>
<View style={AlignSelfDemoStyle.box}>
<Text style={AlignSelfDemoStyle.item}>1</Text>
<Text style={AlignSelfDemoStyle.item}>2</Text>
<Text style={AlignSelfDemoStyle.item}>3</Text>
<Text style={AlignSelfDemoStyle.item_flex_end}>4</Text>
<Text style={AlignSelfDemoStyle.item}>5</Text>
</View>
</View>
);
}
}
const AlignSelfDemoStyle = StyleSheet.create({
container: {
backgroundColor: "#0ff",
height: 300,
},
subtitle:{
backgroundColor: '#ffffff',
alignItems: 'center'
},
box:{
flex: 1,
backgroundColor: '#333333',
flexDirection:"row",
},
item: {
backgroundColor: "#f0f",
flexGrow: 1,
margin: 4,
height: 100,
},
item_flex_end: {
backgroundColor: "#f0f",
flexGrow: 1,
margin: 4,
height: 100,
alignSelf: "flex-end",
}
})
flex
flex 屬性定義了一個(gè)可伸縮元素的能力(flex的屬性值大于0的時(shí)候才可伸縮)乔夯。
flex: number
如果父元素只有一個(gè)子元素設(shè)置 flex的值砖织,通常flex:1, 指定該子元素?cái)U(kuò)展以充滿所有剩余空間末荐。
如果有多個(gè)子元素都設(shè)置了flex值侧纯,則根據(jù)flex的值的比值,瓜分所有剩余空間甲脏。
舉個(gè)簡(jiǎn)單的例子:A眶熬、B、C三個(gè)元素块请,其flex的值分別為1,2,3娜氏。則其三個(gè)所占空間大小為1:2:3,如下圖:
代碼示例:
import React,{Component} from 'react';
import {
Text,
View,
} from 'react-native';
export default class FlexDemo extends Component {
render() {
return (
<View style={ {flexDirection:'row',height:40, backgroundColor:"darkgray"}}>
<View style={ {flex:1,backgroundColor:"red"}}>
<Text style={ {fontSize:16}}>flex:1</Text>
</View>
<View style={ {flex:2,backgroundColor:"blue"}}>
<Text style={ {fontSize:16}}>flex:2</Text>
</View>
<View style={ {flex:3,backgroundColor:"green"}}>
<Text style={ {fontSize:16}}>flex:3</Text>
</View>
</View>
);
}
}
如果將三個(gè)子元素的flex都改為1墩新,則三個(gè)子元素所占空間大小也是1:1:1
定位position
position 屬性設(shè)置元素的定位方式贸弥,為將要定位的元素定義定位規(guī)則。
position : absolute | relative
絕對(duì)定位和相對(duì)定位海渊。
- absolute:絕對(duì)定位绵疲,生成絕對(duì)定位的元素,元素的位置通過(guò) "left", "top", "right" 以及 "bottom" 屬性進(jìn)行規(guī)定臣疑。
- relative:相對(duì)定位盔憨,生成相對(duì)定位的元素,相對(duì)于其正常位置進(jìn)行定位讯沈。
如果你之前是做Android開(kāi)發(fā)的郁岩,這里會(huì)感覺(jué)很不適應(yīng),這個(gè)absolute和relative與Android中的AbsoluteLayout和RelativeLayout大不相同缺狠,特別是relative驯用,可以說(shuō)是完全不同。
網(wǎng)上有很多人總結(jié)說(shuō)“react native 相對(duì)定位不是相對(duì)于父容器儒老,而是相對(duì)于兄弟節(jié)點(diǎn)”蝴乔,我覺(jué)得說(shuō)得很不準(zhǔn)確。一個(gè)元素如果不設(shè)定position去定位的話驮樊,默認(rèn)會(huì)形成文檔流薇正。每個(gè)元素會(huì)按順序出現(xiàn)在文檔流中,排到自己的位置上囚衔。而如果該元素設(shè)置了相對(duì)定位position:'relative'挖腰,則會(huì)相對(duì)于自己原本該在文檔流的位置進(jìn)行偏移,并且不影響其相鄰的元素的位置擺放练湿。因此總結(jié)下來(lái)猴仑,react native 相對(duì)定位不是相對(duì)于父容器,也不是相對(duì)于兄弟節(jié)點(diǎn),而是相對(duì)于自己在文檔流中正常位置進(jìn)行定位辽俗。
絕對(duì)定位absolute則是相對(duì)于父容器進(jìn)行絕對(duì)定位疾渣,脫離了文檔流。
舉個(gè)例子崖飘,有三個(gè)view榴捡,普通排列,由于rn是默認(rèn)flexbox布局,所以會(huì)是從上到下一個(gè)挨著一個(gè)排列:
import React,{Component} from 'react';
import {
Text,
View,
ScrollView,
StyleSheet
} from 'react-native';
export default class PositionDemo extends Component {
render() {
return (
<ScrollView>
<View style={{flex:1}}>
<Text>FlexBox布局</Text>
<View style={styles.container}>
<View style={styles.box1}/>
<View style={[styles.box2]}/>
<View style={[styles.box3]}/>
</View>
<Text>第二個(gè)元素position=relative,top:20朱浴,left20</Text>
<View style={styles.container}>
<View style={styles.box1}/>
<View style={[styles.box2,{position:'relative',top:20,left:20}]}></View>
<View style={styles.box3}/>
</View>
<Text>第二個(gè)元素position=absolute,top:20吊圾,left20</Text>
<View style={styles.container}>
<View style={styles.box1}/>
<View style={[styles.box2,{position:'absolute',top:20,left:20}]}></View>
<View style={styles.box3}/>
</View>
</View>
</ScrollView>
);
}
}
const styles = StyleSheet.create({
container: {
height: 180,
backgroundColor: '#CCCCCC',
marginBottom: 10,
},
box1: {
width: 50,
height: 50,
backgroundColor: '#FF0000'
},
box2: {
width: 50,
height: 50,
backgroundColor: '#00FF00'
},
box3: {
width: 50,
height: 50,
backgroundColor: '#0000FF'
}
});
如上圖所示,第二組中翰蠢,我將第二元素設(shè)置為相對(duì)定位
positon:relative, top:20, left:20
项乒,可以看到第二個(gè)元素偏離原來(lái)的位置,但其仍然沒(méi)有脫離文檔流梁沧,只是相對(duì)于它原本的位置進(jìn)行偏移檀何。
在第三組中,我將第二個(gè)元素設(shè)置為絕對(duì)定位
positon:absolute, top:20, left:20
趁尼,可以看到第二個(gè)元素脫離了文檔流埃碱,相對(duì)于父容器進(jìn)行偏移猖辫,剩下第一個(gè)元素和第三個(gè)元素酥泞,還規(guī)規(guī)矩矩的排在那里。
好奇的朋友可以在第一組中為第二個(gè)元素設(shè)置一下top:20, left:20
啃憎,
<View style={[styles.box2,{top:20,left:20}]}/>
看看會(huì)出現(xiàn)什么樣的結(jié)果呢芝囤?
如上圖,它與第二組的情況一樣辛萍,所以我們可以看出元素默認(rèn)的position是relative悯姊。即我們?nèi)绻辉O(shè)值position的話,默認(rèn)按相對(duì)定位來(lái)處理贩毕。
其他屬性
margin 外邊距
marginBottom 底部外邊距
marginLeft 左外邊距
marginRight 右外邊距
marginTop 上外邊距
marginVertical 上下外邊距悯许,如果marginTop與marginBottom一樣的話,可以直接用這個(gè)值代替
marginHorizontal 左右外邊距
borderColor 整體邊框顏色
borderRadius 整體邊框的圓角
borderWidth 整體邊框的寬
borderStyle 邊框樣式 dotted solid double dashed等
borderBottomColor 底邊框顏色
borderBottomWidth 底邊框?qū)挾?borderLeftColor 左邊框顏色
borderLeftWidth 左邊框?qū)挾?borderRightColor 右邊框顏色
borderRightWidth 右邊框?qū)挾?borderTopColor 上邊框顏色
borderTopWidth 上邊框?qū)挾?borderBottomLeftRadius 左下角圓角邊框
borderBottomRightRadius 右下角圓角邊框
borderTopLeftRadius 上邊框左圓角
borderTopRightRadius 上邊框右圓角
padding 內(nèi)邊距
paddingBottom 底部?jī)?nèi)邊距
paddingTop 頂部?jī)?nèi)邊距
paddingLeft 左內(nèi)邊距
paddingRight 右內(nèi)邊距
paddingHorizontal 左右內(nèi)邊距
paddingVertical 上下內(nèi)邊距
height 元素高度辉阶,包含padding與border
width 元素寬度先壕,包含padding與border
Demo
本文的示例代碼在: https://github.com/mronion0603/ReactNativeExercise/tree/master/src/02_flex