代碼在這里:
https://github.com/future-challenger/petshop/tree/master/client/petshop/src/controller
回頭看看RN的填坑之旅系列,發(fā)現(xiàn)一路寫下來都是我在開發(fā)中遇到的問題如何解決的蔑水。興之所至锌云,不問順序腰素。于是出現(xiàn)一個問題书幕,填坑系列和學(xué)習(xí)知識的順序不是很一致嚎花。比如今天要說的布局問題悼瘾。其實在一個app開發(fā)之前龟再,就應(yīng)該有所了解书闸。否則的話每次看到的<View style={{flex: 1}} />
代表的是什么呢?上來就是一個疑問利凑。
在這個系列進行到一定程度的時候捺信,我會花時間重新整理全系列的文章擂煞,讓各位可以按照知識本來學(xué)習(xí)的順序循序漸進的學(xué)習(xí)React Native的知識,避免在開發(fā)中遇到不應(yīng)該遇到的問題。
正文開始宿刮。本文主要是介紹基礎(chǔ)知識校哎,但是不適用基礎(chǔ)的代碼吏夯。所以静浴,如果你在看的時候有什么問題弄不清楚的話,隨時查閱官網(wǎng)适荣。那么問題是什么现柠?三個View放在一個父View里顯示出來會是設(shè)么樣子的?這五個子View每次只要顯示一個的話應(yīng)該如何處理弛矛?
首先我們先來一點開胃小菜:
NavigationBar的布局
默認(rèn)的情況下NavigationBar的左側(cè)回退按鈕看起來是這樣的:
圖中可見够吩,按鈕緊貼上沿。這個時候的布局是這樣的:
<TouchableHighlight
style={{backgroundColor: 'red', width: 50}}
onPress={() => {
if (index > 0) {
navigator.pop();
}
}}>
<Text style={{
marginLeft: 10,
backgroundColor: 'yellow'
}}>Back</Text>
</TouchableHighlight>
如何讓NavigationBar的按鈕豎直居中呢丈氓?不要想在TouchableHighlight
上添加的樣式可以起作用周循。只有在外層再包裹一層View才可以。并給外層的View設(shè)置樣式万俗,讓其中的內(nèi)容豎直居中才可以湾笛。
<View style={{flex:1, justifyContent: 'center'}}>
<TouchableHighlight
style={{backgroundColor: 'red', width: 50}}
onPress={() => {
if (index > 0) {
navigator.pop();
}
}}>
<Text style={{
marginLeft: 10,
backgroundColor: 'yellow'
}}>Back</Text>
</TouchableHighlight>
</View>
開始填坑
下面要實現(xiàn)一個效果。我們已經(jīng)有三個橫向排列的闰歪,等寬度的View嚎研。對應(yīng)的還有三個按鈕,每一個按鈕對應(yīng)一個View课竣。但是嘉赎,不要三個View都顯示出來置媳。每次只顯示一個于樟。點一個按鈕就顯示出對應(yīng)的View來公条。
Flex的方向
先來看看制造問題的代碼重現(xiàn):
<View style={{flex: 1, marginTop: 64}}>
<View style={{flex: 1, backgroundColor: 'red'}}></View>
<View style={{flex: 1, backgroundColor: 'orange'}}></View>
<View style={{flex: 1, backgroundColor: 'yellow'}}></View>
</View>
看起來是這樣的:
默認(rèn)的,在一個View里的子View都是豎直依次排列的迂曲。
React Native使用Flexbox來實現(xiàn)布局的靶橱。Flexbox兩個方向,一個是column路捧,一個是row关霸。
- column 是默認(rèn)的flexbox方向,是豎直的杰扫,從上到下的方向队寇。如上例的圖片中截面里紅、橙章姓、黃三個顏色的view排列的方向佳遣。
- row是橫向的,從左到右的方向凡伊。
我們來看看flexbox在row方向的樣子:
<View style={{flex: 1, flexDirection: 'row', marginTop: 64}}>
<View style={{flex: 1, backgroundColor: 'red'}}></View>
<View style={{flex: 1, backgroundColor: 'orange'}}></View>
<View style={{flex: 1, backgroundColor: 'yellow'}}></View>
</View>
添加了按鈕以后的界面看起來是這樣的:
JustifyContent & AlignItems
在flow已經(jīng)決定了子view排列的方向的時候零渐。還需要進一步的調(diào)整子view的時候就會用到justifyContent
和alignItems
。
在和flow指定的方向同一方向上調(diào)整的時候使用justifyContent
系忙。flow指定的方向為主方向诵盼。要在次方向上指定子view如何排列就是用alignItems
。如果flexDirection
指定的是column
(豎直方向)银还,那么主方向就是豎直的风宁,次方向就是水平的。
Flex的值
上面介紹了flex的方向蛹疯,這里來說說flex的值杀糯。
在兄弟姐妹關(guān)系的View中,如果他們的flex都是1苍苞,那么他們評分父view的空間固翰。如果,有一個flex的值是2羹呵,那么就是說這個子View的寬(高)是其他的兄弟姐妹的2倍骂际。
在flex為0的時候,View的寬高就完全需要靠自己了冈欢。也就是這個view的寬和高需要設(shè)置具體的數(shù)值歉铝。系統(tǒng)不會替你計算。
如果flow為-1
凑耻,那么View的寬度和高度太示,由width和height決定柠贤。*在空間不夠的情況下,view的寬度和高度會縮小到minWidth
和minHeight
类缤。
看看我們要實現(xiàn)的效果和代碼
效果:
實現(xiàn)代碼:
export default class FlexDemo extends React.Component {
_onPress: (buttonIndex: number) => void;
constructor(props) {
super(props);
this.state = {
view1Style: {flex: 1, width: 0}, // If flex is 1, width does not work.
view2Style: {flex: 0, width: 0},
view3Style: {flex: 0, width: 0}
};
this._onPress = this._onPress.bind(this);
}
_onPress(buttonIndex) {
switch(buttonIndex) {
case 0:
this.setState({
view1Style: {flex: 1, width: 0}, // If flex is 1, width does not work.
view2Style: {flex: 0, width: 0},
view3Style: {flex: 0, width: 0}
});
break;
case 1:
this.setState({
view1Style: {flex: 0, width: 0}, // If flex is 1, width does not work.
view2Style: {flex: 1, width: 0},
view3Style: {flex: 0, width: 0}
});
break;
case 2:
this.setState({
view1Style: {flex: 0, width: 0}, // If flex is 1, width does not work.
view2Style: {flex: 0, width: 0},
view3Style: {flex: 1, width: 0}
});
break;
default:
this.setState({
view1Style: {flex: 1, width: 0}, // If flex is 1, width does not work.
view2Style: {flex: 0, width: 0},
view3Style: {flex: 0, width: 0}
});
break;
}
}
render() {
return (
<View style={{flex: 1, flexDirection: 'row', marginTop: 64}}>
<View key="view1" style={[this.state.view1Style, {backgroundColor: 'red'}]}></View>
<View key="view2" style={[this.state.view2Style, {backgroundColor: 'orange'}]}></View>
<View key="view3" style={[this.state.view3Style, {backgroundColor: 'yellow'}]}></View>
<View style={{
flex: 1,
flexDirection: 'row',
justifyContent: 'space-between',
alignItems: 'center',
position: 'absolute',
height: 50,
left:0,
right: 0,
bottom: 0,
backgroundColor: 'black',
opacity: 0.6
}}>
<View style={{flex: 1, justifyContent:'center'}} key='b1'>
<TouchableOpacity
style={styles.button}
onPress={()=>this._onPress(0)}>
<Text style={styles.buttonText}>1</Text>
</TouchableOpacity>
</View>
<View style={{flex: 1, justifyContent: 'center'}} key='b2'>
<TouchableOpacity
style={styles.button}
onPress={()=>this._onPress(1)}>
<Text style={styles.buttonText}>2</Text>
</TouchableOpacity>
</View>
<View style={{flex: 1, justifyContent: 'center'}} key='b3'>
<TouchableOpacity
style={styles.button}
onPress={()=>this._onPress(2)}>
<Text style={styles.buttonText}>3</Text>
</TouchableOpacity>
</View>
</View>
</View>
);
}
};
實現(xiàn)原理:
如何去改變一個組件的外觀布局臼勉?自然少不了setState
方法。一開始餐弱,我們就把這幾個子view的布局都放在state
里宴霸。
在下面的三個按鈕的點擊事件中,設(shè)置不同的state膏蚓,那么赤瓢谢、橙和黃三個view就會發(fā)生變化。
前面提高flex的值為0的時候width
和height
起作用驮瞧,flex不為0的時候不起作用氓扛。這就是核心算法之所在了。在一開始讓紅色的view的flex為1
论笔。其他的view的flex為0
采郎,并且寬度也為0
。
之后每次點擊了一個按鈕的時候翅楼,對應(yīng)的view的布局設(shè)置為flex等于1
尉剩,其他的view的flex為0
。這樣就實現(xiàn)了上面的效果毅臊。
小小的練習(xí)
最后留一個練習(xí)題理茎,上面的效果對于一個簡單的View來說也可以使用conditional render來搞定。那么就請你做一個這樣的練習(xí)管嬉。
最后
上面的講解都是我遇到的問題的講解皂林。包含了一些flexbox布局的基礎(chǔ),但是更難理解一下蚯撩。React Native的布局包括的東西還有很多础倍。后續(xù)會在本文或者系列的其他的文章中講解。