前言
眼看很多公司都開始嘗試使用ReactNative,達到跨平臺開發(fā)轨奄,最近也寫了很多文章净宵,希望讓更多想了解的同學(xué)快速上手ReactNative.
如果喜歡我的文章敲才,可以關(guān)注我微博:袁崢Seemygo
ReactNative之利用MVC瞬間搭建設(shè)置界面
- 在RN中,沒有分組樣式的ListView,而設(shè)置界面一般都需要分組樣式择葡,因此又得自己封裝一套了紧武。
- 這里我采用MVC的思想快速搭建設(shè)置界面。
- 組與組之間的間距:就用每一組的頭部視圖去做敏储。
先看如何使用
- 用法非常簡單浇雹,就配置下模型裕膀,界面就換了.
- 點擊cell跳轉(zhuǎn),也封裝到模型中了.
constructor(props){
super(props);
var groups = [];
this.setupGroup0(groups);
this.setupGroup1(groups);
this.state = {
groups:groups
}
}
// 設(shè)置第0組
setupGroup0(groups){
// 創(chuàng)建行模型
var item0 = new CommonSwitchItem('','消息推送','');
var item1 = new CommonSwitchItem('','圖書借閱','');
var item2 = new CommonArrowItem('','解綁設(shè)備','');
// 創(chuàng)建第0組
var group = new CommonGroupItem([item0,item1,item2],10);
groups.push(group);
}
// 設(shè)置第1組
setupGroup1(groups){
// 創(chuàng)建行模型
var item0 = new CommonArrowItem('','意見反饋','');
var item1 = new CommonArrowItem('','關(guān)于技術(shù)圈','');
// 創(chuàng)建第1組
var group = new CommonGroupItem([item0,item1],10);
groups.push(group);
}
render() {
return (
<View style={styles.viewStyle}>
<CommonNavigationBar title={this.props.title}
leftBarButtonItem={this.renderLeftBarButtonItem()}
/>
<CommonGroupListView commonGroupListViewStyle={{backgroundColor:Common.bgColor}}
dataBlob={this.state.groups}
subTitleStyle={{position:'absolute',right:0}}
navigator={this.props.navigator}
renderFooter={this._renderFooter.bind(this)}
/>
</View>
);
}
// 渲染底部View
_renderFooter(){
return (
<TouchableOpacity style={{height:60,justifyContent:'flex-end',alignItems:'center'} }>
<Text style={styles.loginStyle}>立即登錄</Text>
</TouchableOpacity>
)
}
}
- 效果
效果.png
思路:1.自定義分組ListView
- 暴露屬性
static propTypes = {
// 組模型數(shù)據(jù)CommonGroupItem
dataBlob:PropTypes.array,
// listView樣式
commonGroupListViewStyle:PropTypes.object,
// cell title樣式:因為一個ListViewcell就一種樣式,就定義在ListView中,如果不一樣,就定義在模型
titleStyle:PropTypes.oneOfType([PropTypes.object,PropTypes.string]),
// cell image樣式
imageStyle:PropTypes.oneOfType([PropTypes.object,PropTypes.string]),
// cell 子標題樣式
subTitleStyle:PropTypes.oneOfType([PropTypes.object,PropTypes.string]),
// 渲染頭部
renderHeader:PropTypes.func,
// 渲染尾部
renderFooter:PropTypes.func
};
- CommonGroupListView代碼
/**
* Created by ithinkeryz on 2017/5/17.
*/
/**
* Created by ithinkeryz on 2017/5/15.
*/
import React, { Component,PropTypes } from 'react';
import {
AppRegistry,
StyleSheet,
Text,
View,
ListView
} from 'react-native';
import CommonArrowItem from './CommonArrowItem'
import CommonRowCell from './CommonRowCell'
export default class CommonGroupListView extends Component {
static propTypes = {
// 組模型數(shù)據(jù)CommonGroupItem
dataBlob:PropTypes.array,
// listView樣式
commonGroupListViewStyle:PropTypes.object,
// cell title樣式:因為一個ListViewcell就一種樣式,就定義在ListView中,如果不一樣,就定義在模型
titleStyle:PropTypes.oneOfType([PropTypes.object,PropTypes.string]),
// cell image樣式
imageStyle:PropTypes.oneOfType([PropTypes.object,PropTypes.string]),
// cell 子標題樣式
subTitleStyle:PropTypes.oneOfType([PropTypes.object,PropTypes.string]),
// 渲染頭部
renderHeader:PropTypes.func,
// 渲染尾部
renderFooter:PropTypes.func
};
constructor(props){
super(props);
var ds = new ListView.DataSource({
rowHasChanged:(r1,r2)=>r1 != r2,
sectionHeaderHasChanged:(s1,s2)=>s1!=s2
});
// 處理組數(shù)據(jù),把傳遞過來的組模型,轉(zhuǎn)換為{s1:[rowData]}
var dataBlob = this.props.dataBlob;
var sectionData = {};
dataBlob.forEach((obj,index)=>{
sectionData[index.toString()] = obj.rowData;
});
ds = ds.cloneWithRowsAndSections(sectionData);
this.state = {
ds:ds
}
}
render() {
console.log(this.props.renderFooter);
return (
<ListView dataSource={this.state.ds}
renderRow={this._renderRow.bind(this)}
renderSectionHeader={this._renderSectionHeader.bind(this)}
style={this.props.commonGroupListViewStyle}
renderFooter={this.props.renderFooter?this.props.renderFooter:undefined}
renderHeader={this.props.renderHeader?this.props.renderHeader:undefined}
/>
);
}
// 渲染行
_renderRow(rowData, sectionID, rowID){
return (
<CommonRowCell rowData={rowData} {...this.props}/>
)
}
// 渲染組頭部視圖
_renderSectionHeader(sectionData, sectionID){
var sectionData = this.props.dataBlob[sectionID];
return (
<View style={[styles.sectionHeaderStyle,{height:sectionData.sectionHeight}]}>
</View>
)
}
}
var styles = StyleSheet.create({
viewStyle:{
backgroundColor:'red',
flex:1
},
sectionHeaderStyle:{
backgroundColor:'transparent'
}
});
思路:2.設(shè)計組模型
function CommonGroupItem(rowData,sectionHeight) {
// 組與組之間間距,每組頭部視圖的高度
this.sectionHeight = sectionHeight;
// 每一組的數(shù)據(jù)
this.rowData = rowData;
}
module.exports = CommonGroupItem;
思路:3.設(shè)計行模型
因為Cell有不同的樣式,比如有開關(guān)祝旷,有箭頭,可以根據(jù)不同類型cell模型贞滨,展示不同的cell樣式,搞個基本的cell行模型拙吉,存放公用的屬性
基本cell模型
function CommonRowItem(image,title,subTitle) {
this.image = image;
this.title = title;
this.subTitle = subTitle;
// 跳轉(zhuǎn)界面
this.route = null;
// 標題樣式?jīng)]必要定義在模型,樣式并不是每個都不一樣
// 樣式應(yīng)該定義到ListView,每個ListView一個
}
module.exports = CommonRowItem;
- 開關(guān)cell模型
- 箭頭cell模型
import CommonRowItem from './CommonRowItem'
function CommonSwitchItem(image,title,subTitle) {
CommonRowItem.call(this,image,title,subTitle);
// 開關(guān)
this.isOn = false;
// 不能使用,一般開關(guān)cell不需要點擊
this.disabled = true;
// 標題樣式?jīng)]必要定義在模型,樣式并不是每個都不一樣
// 樣式應(yīng)該定義到ListView,每個ListView一個
}
module.exports = CommonSwitchItem;
思路:4.自定義cell
- 暴露屬性
static propTypes = {
rowData:PropTypes.object,
cellStyle:PropTypes.oneOfType([PropTypes.object,PropTypes.string]),
titleStyle:PropTypes.oneOfType([PropTypes.object,PropTypes.string]),
imageStyle:PropTypes.oneOfType([PropTypes.object,PropTypes.string]),
subTitleStyle:PropTypes.oneOfType([PropTypes.object,PropTypes.string]),
};
- 設(shè)置右邊樣式
- 根據(jù)類型判斷,每個對象的構(gòu)造方法的名稱就是類名
- 監(jiān)聽cell點擊缆蝉,點擊的時候跳轉(zhuǎn)宇葱,記得把navigator傳遞進來瘦真,模型保存route屬性
this.props.rowData.constructor.name
- 完整代碼
/**
* Created by ithinkeryz on 2017/5/19.
*/
import React, { Component,PropTypes } from 'react';
import {
AppRegistry,
StyleSheet,
Text,
View,
Image,
Switch,
TouchableOpacity
} from 'react-native';
export default class CommonRowCell extends Component {
static propTypes = {
rowData:PropTypes.object,
cellStyle:PropTypes.oneOfType([PropTypes.object,PropTypes.string]),
titleStyle:PropTypes.oneOfType([PropTypes.object,PropTypes.string]),
imageStyle:PropTypes.oneOfType([PropTypes.object,PropTypes.string]),
subTitleStyle:PropTypes.oneOfType([PropTypes.object,PropTypes.string]),
};
constructor(props){
super(props);
this.state = {
isOn:this.props.rowData.isOn
}
}
render() {
return (
<TouchableOpacity style={styles.cellStyle}
disabled={this.props.rowData.disabled}
onPressOut={this.clickCell.bind(this)}
>
{/*image*/}
{this.props.rowData.image?<Image source={{uri:this.props.rowData.image}} style={[styles.imageStyle,this.props.imageStyle]}/>:null}
<View style={styles.middleViewStyle}>
{/*title*/}
<Text style={[styles.titleStyle,this.props.titleStyle]}>{this.props.rowData.title}</Text>
{/*subtitle*/}
<Text style={[styles.subTitleStyle,this.props.subTitleStyle]}>{this.props.rowData.subTitle}</Text>
</View>
{/*accessoryView*/}
{this.setupAccessoryView()}
</TouchableOpacity>
);
}
// onValueChange={(value)=>{}
// 設(shè)置右邊附近View
setupAccessoryView(){
// console.log(typeof this.props.rowData);
// 如何判斷當(dāng)前對象屬于哪個類,獲取構(gòu)造方法名稱,構(gòu)造方法名稱都是類名
if (this.props.rowData.constructor.name === 'CommonArrowItem'){
return <Image source={require('./icon_shike_arrow.png')} style={{marginLeft:10,width:7,height:12,marginRight:10}}/>
} else if (this.props.rowData.constructor.name === 'CommonSwitchItem') {
return <Switch style={{marginLeft:10,marginRight:10}}
onValueChange={(value => {
this.setState({
isOn:value,
});
this.props.rowData.isOn = value
})}
value={this.state.isOn}
/>
}
}
// 點擊Cell
clickCell(){
if (this.props.rowData.route){
this.props.navigator.push({
component: this.props.rowData.route.component,
title: this.props.rowData.route.title,
passPros: this.props.rowData.route.passPros,
backButtonIcon: this.props.rowData.route.backButtonIcon,
backButtonTitle: this.props.rowData.route.backButtonTitle,
leftButtonIcon: this.props.rowData.route.leftButtonIcon,
leftButtonTitle: this.props.rowData.route.leftButtonTitle,
onLeftButtonPress: this.props.rowData.route.onLeftButtonPress,
rightButtonIcon: this.props.rowData.route.rightButtonIcon,
rightButtonTitle: this.props.rowData.route.rightButtonTitle,
onRightButtonPress: this.props.rowData.route.onRightButtonPress
})
}
}
}
var cellH = 44;
var styles = StyleSheet.create({
imageStyle:{
width:20,
height:20,
marginLeft:10
},
cellStyle:{
flexDirection:'row',
alignItems:'center',
height:cellH,
backgroundColor:'white',
borderBottomWidth:1,
borderBottomColor:'#e5e5e5'
},
middleViewStyle:{
height:cellH,
flexDirection:'row',
alignItems:'center',
flex:1,
marginLeft:10
},
titleStyle:{
color:'rgb(96,96,96)'
},
subTitleStyle:{
color:'rgb(207,207,207)',
marginLeft:10
}
});
思路:5.創(chuàng)建組模型,搭建界面
/**
* Created by ithinkeryz on 2017/5/19.
*/
import React, { Component } from 'react';
import {
AppRegistry,
StyleSheet,
Text,
View,
TouchableOpacity
} from 'react-native';
import CommonNavigationBar from '../Common/CommonNavigationBar'
import CommonHighButton from '../Common/CommonHighButton'
import Common from './../Common/Common'
import CommonGroupListView from '../CommonGroupListView/CommonGroupListView'
import CommonGroupItem from '../CommonGroupListView/CommonGroupItem'
import CommonArrowItem from '../CommonGroupListView/CommonArrowItem'
import CommonSwitchItem from '../CommonGroupListView/CommonSwitchItem'
export default class Setting extends Component {
constructor(props){
super(props);
var groups = [];
this.setupGroup0(groups);
this.setupGroup1(groups);
this.state = {
groups:groups
}
}
// 設(shè)置第0組
setupGroup0(groups){
// 創(chuàng)建行模型
var item0 = new CommonSwitchItem('','消息推送','');
var item1 = new CommonSwitchItem('','圖書借閱','');
var item2 = new CommonArrowItem('','解綁設(shè)備','');
// 創(chuàng)建第0組
var group = new CommonGroupItem([item0,item1,item2],10);
groups.push(group);
}
// 設(shè)置第1組
setupGroup1(groups){
// 創(chuàng)建行模型
var item0 = new CommonArrowItem('','意見反饋','');
var item1 = new CommonArrowItem('','關(guān)于技術(shù)圈','');
// 創(chuàng)建第1組
var group = new CommonGroupItem([item0,item1],10);
groups.push(group);
}
render() {
return (
<View style={styles.viewStyle}>
<CommonNavigationBar title={this.props.title}
leftBarButtonItem={this.renderLeftBarButtonItem()}
/>
<CommonGroupListView commonGroupListViewStyle={{backgroundColor:Common.bgColor}}
dataBlob={this.state.groups}
subTitleStyle={{position:'absolute',right:0}}
navigator={this.props.navigator}
renderFooter={this._renderFooter.bind(this)}
/>
</View>
);
}
// 渲染底部View
_renderFooter(){
return (
<TouchableOpacity style={{height:60,justifyContent:'flex-end',alignItems:'center'} }>
<Text style={styles.loginStyle}>立即登錄</Text>
</TouchableOpacity>
)
}
renderLeftBarButtonItem(){
return (
<CommonHighButton imageUri='btn_backitem'
imageStyle={{width:20,height:20}}
buttonStyle={{position:'absolute',left:5}}
onPressOut={()=>{
this.props.navigator.pop();
}}
/>
)
}
}
var styles = StyleSheet.create({
viewStyle:{
backgroundColor:Common.bgColor,
flex:1
},
loginStyle:{
height:35,
width:Common.screenW,
textAlign:'center',
color:'red',
backgroundColor:'white',
lineHeight:35,
fontSize:15
}
});