## 第四篇React-Native布局實戰(二)
在不斷深入的過程中,發現React-Native布局和樣式的坑還有很多,他沒有像瀏覽器那樣靈活和有規律可循,其中的規律需要我自己踩坑的時候發現。比如:不存在zIndex,后面的元素覆蓋前面的元素;內層元素覆蓋外層元素等等,borderRadius的設置,需要考慮到內層元素的位置等等。
### 一、實戰的內容
這里選用攜程的App首頁作為栗子,隨不是嚴格的9宮格(比9宮格稍微難點...),但是可以很好的讓我們練習flexbox.最后需要完成的結果如下:

### 二、分解內容
整個頁面我們可以分為幾個部分,大致如下:
* 頭部
* 圖片輪播
* 9宮格
* 底部活動
### 三、頭部導航欄
因為,組件還沒有講,這里只是做一個簡單的介紹。在React-Native中實現頭部導航欄很簡單,只要使用NavigatorIOS組件即可。現在開工。
1、我們在index.ios.js中添加如下代碼;同時創建文件夾pagaes和pages下創建Index.js
~~~
var React = require('react-native');
var Index = require('./pages/Index');
var {
NavigatorIOS,
AppRegistry,
StyleSheet,
} = React;
var NV = React.createClass({
render: function(){
return(
<NavigatorIOS
style={styles.container}
initialRoute={{
title: '首頁',
component: Index,
}}
/>
);
}
});
var styles = StyleSheet.create({
container: {
flex: 1,
}
});
AppRegistry.registerComponent('HelloWorld', () => NV);
~~~
分析代碼:
(1)require:引入外部模塊,就像,引入我們自己創建的/pages/Index.js一樣。
(2)引入定義NavigatorIOS、AppRegistry、StyleSheet組件和類。
(3)在render中調用NavigatorIOS組件,initialRoute是初始化路由,title是當前頁面的頭部標題;component是當前路由下顯示的組件;
(4)注意:這里NavigatorIOS的style需要設置大小,比如這里設置是flex:1,否則就不能顯示內容主體;
(5)最后我們需要注冊當前應用:AppRegistry.registerComponent('HelloWorld', () => NV);
2、創建Index.js文件,文件的內容如下, module.exports就暴露了Index模塊。
?效果如下圖:?
### 四、圖片輪播
這里圖片輪播使用的是第三方組件react-native-swiper,當然React-Native是支持transform可以直接實現一套。我們啟動npm命令行,在項目的根目錄使用如下命令安裝模塊。
~~~
$ npm install react-native-swiper --save
$ npm i react-timer-mixin --save
~~~
(2)需要關閉React packager命令行和模擬器,在xcode中重啟項目
安裝完成后,我們需要完成輪播功能。因為可以到github看看swiper暴露的接口和參數。github地址是:https://github.com/leecade/react-native-swiper
(1)引入swiper,前面也提到了require.
~~~
var Swiper = require('react-native-swiper');
~~~
(2)使用swiper,將輪播圖封裝成單獨的組件
~~~
var sliderImgs = [
'http://images3.c-ctrip.com/SBU/apph5/201505/16/app_home_ad16_640_128.png',
'http://images3.c-ctrip.com/rk/apph5/C1/201505/app_home_ad49_640_128.png',
'http://images3.c-ctrip.com/rk/apph5/D1/201506/app_home_ad05_640_128.jpg'
];
var Slider = React.createClass({
render: function(){
return (
<Swiper style={styles.wrapper} showsButtons={false} autoplay={true} height={150} showsPagination={false}>
<Image style={[styles.slide,]} source={{uri: sliderImgs[0]}}></Image>
<Image style={[styles.slide,]} source={{uri: sliderImgs[1]}}></Image>
<Image style={[styles.slide,]} source={{uri: sliderImgs[2]}}></Image>
</Swiper>
);
}
});
~~~
(3)這樣我們可以直接在render的時候直接用:`<Slider/>`
### 五、完成第一個9宮格布局,后面復制拷貝
其實4個九宮格都是一樣,這個其實可以封裝成組件,這里采用拷貝的形式,開發一個,其他3個就ok的,不會偷懶的工程師,不是好工程師[偷笑]。分析下布局:
(1)其實首先是3個列在一行的布局,那么外層組件是需要flexDirection: 'row',各占據寬度的1/3,即各自flex:1;
(2)每個列內又分兩行, 需要每個行都是flex:1,各占據高度的一半;
(3)第一列是文字圖片組合,其余都是文字組合;
(4)所有行內元素都是水平、垂直居中;
(5)這里使用了個TouchableHighlight組件,是為了出發onPress事件,類似于click或者touch事件。
~~~
<View style={[styles.sbu_red, styles.sbu_view]}>
<TouchableHighlight underlayColor={'#FA6778'} style={{flex:1}}>
<View style={[styles.sbu_flex, styles.sbu_borderRight]}>
<View style={[styles.sub_con_flex, styles.sub_text]}>
<Text style={[styles.font16]}>酒店</Text>
</View>
<View style={[styles.sub_con_flex]}>
<Image style={[styles.sbu_icon_img]} source={{uri:BUIcon[0]}}></Image>
</View>
</View>
</TouchableHighlight>
<View style={[styles.sbu_flex, styles.sbu_borderRight]}>
<View style={[styles.sub_con_flex, styles.sub_text, styles.sbu_borderBottom]}>
<Text style={[styles.font16]}>海外</Text>
</View>
<View style={[styles.sub_con_flex, styles.sub_text]}>
<Text style={[styles.font16]}>周邊</Text>
</View>
</View>
<View style={[styles.sbu_flex]}>
<View style={[styles.sub_con_flex, styles.sub_text, styles.sbu_borderBottom]}>
<Text style={[styles.font16]}>團購.特惠</Text>
</View>
<View style={[styles.sub_con_flex, styles.sub_text]}>
<Text style={[styles.font16]}>客棧.公寓</Text>
</View>
</View>
</View>
~~~
### 六、樣式類
說完了布局的原理,這里需要貼上樣式僅供參考:
~~~
var styles = StyleSheet.create({
//container
container:{
backgroundColor:'#F2F2F2',
flex:1,
},
//slider
wrapper: {
height:80,
},
slide: {
height:80,
resizeMode: Image.resizeMode.contain,
},
//sbu
sbu_view:{
height:84,
marginLeft: 5,
marginRight:5,
borderWidth:1,
borderRadius:5,
marginBottom:10,
flexDirection:'row',
},
sbu_red:{
backgroundColor: '#FA6778',
borderColor:'#FA6778',
marginTop:-70,
},
sbu_blue:{
backgroundColor: '#3D98FF',
borderColor:'#3D98FF',
},
sbu_green:{
backgroundColor: '#5EBE00',
borderColor:'#5EBE00',
},
sbu_yellow:{
backgroundColor: '#FC9720',
borderColor:'#FC9720',
},
sbu_flex:{
flex:1,
},
sbu_borderRight:{
borderColor:'#fff',
borderRightWidth: 0.5,
},
sbu_icon_img:{
height:40,
width:40,
resizeMode:Image.resizeMode.contain,
},
sub_con_flex:{
flex:1,
justifyContent: 'center',
alignItems: 'center',
},
sub_text:{
justifyContent:'center',
},
font16:{
fontSize:17,
color:'#FFF',
fontWeight:'900',
},
sbu_borderBottom:{
borderBottomWidth:0.5,
borderBottomColor:'#fff',
},
img_view:{
height:62,
marginLeft:5,
marginRight:5,
flexDirection: 'row',
marginBottom:20,
backgroundColor:'#fff',
},
img_flex:{
flex:1,
borderWidth:1,
borderColor:'#ccc',
},
img_wh: {
height:59,
borderRightWidth:0,
resizeMode:Image.resizeMode.contain,
}
});
~~~
著重說下resizeMode:Image.resizeMode.contain。在React-Native中圖片的大小是不會根據給定一個寬度或者高度而自適應大小的,因此我們需要讓圖片根據寬度或者高度來自適應,那么可以使用resizeMode:Image.resizeMode.contain。facebook提示錯誤信息的樣式表中也沒有提及,文檔中也沒有提及。所以后續還有不少的坑需要大家去一起探索。
### 七、Index.js整個代碼,僅供參考
實例代碼中會涉及ScrollView組件,主要是為了適應小屏的機器,可以滾動視圖。