ReactNative之利用MVC瞬間搭建設(shè)置界面

前言

眼看很多公司都開始嘗試使用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
    }
});
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末黍瞧,一起剝皮案震驚了整個濱河市诸尽,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌雷逆,老刑警劉巖弦讽,帶你破解...
    沈念sama閱讀 207,248評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異膀哲,居然都是意外死亡往产,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,681評論 2 381
  • 文/潘曉璐 我一進店門某宪,熙熙樓的掌柜王于貴愁眉苦臉地迎上來仿村,“玉大人,你說我怎么就攤上這事兴喂“遥” “怎么了?”我有些...
    開封第一講書人閱讀 153,443評論 0 344
  • 文/不壞的土叔 我叫張陵衣迷,是天一觀的道長畏鼓。 經(jīng)常有香客問我,道長壶谒,這世上最難降的妖魔是什么云矫? 我笑而不...
    開封第一講書人閱讀 55,475評論 1 279
  • 正文 為了忘掉前任,我火速辦了婚禮汗菜,結(jié)果婚禮上让禀,老公的妹妹穿的比我還像新娘。我一直安慰自己陨界,他們只是感情好巡揍,可當(dāng)我...
    茶點故事閱讀 64,458評論 5 374
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著菌瘪,像睡著了一般腮敌。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上麻车,一...
    開封第一講書人閱讀 49,185評論 1 284
  • 那天缀皱,我揣著相機與錄音,去河邊找鬼动猬。 笑死啤斗,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的赁咙。 我是一名探鬼主播钮莲,決...
    沈念sama閱讀 38,451評論 3 401
  • 文/蒼蘭香墨 我猛地睜開眼免钻,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了崔拥?” 一聲冷哼從身側(cè)響起极舔,我...
    開封第一講書人閱讀 37,112評論 0 261
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎链瓦,沒想到半個月后拆魏,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 43,609評論 1 300
  • 正文 獨居荒郊野嶺守林人離奇死亡慈俯,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,083評論 2 325
  • 正文 我和宋清朗相戀三年渤刃,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片贴膘。...
    茶點故事閱讀 38,163評論 1 334
  • 序言:一個原本活蹦亂跳的男人離奇死亡卖子,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出刑峡,到底是詐尸還是另有隱情洋闽,我是刑警寧澤,帶...
    沈念sama閱讀 33,803評論 4 323
  • 正文 年R本政府宣布突梦,位于F島的核電站诫舅,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏宫患。R本人自食惡果不足惜骚勘,卻給世界環(huán)境...
    茶點故事閱讀 39,357評論 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望撮奏。 院中可真熱鬧,春花似錦当宴、人聲如沸畜吊。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,357評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽玲献。三九已至,卻和暖如春梯浪,著一層夾襖步出監(jiān)牢的瞬間捌年,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,590評論 1 261
  • 我被黑心中介騙來泰國打工挂洛, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留礼预,地道東北人。 一個月前我還...
    沈念sama閱讀 45,636評論 2 355
  • 正文 我出身青樓虏劲,卻偏偏與公主長得像托酸,于是被迫代替她去往敵國和親褒颈。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 42,925評論 2 344

推薦閱讀更多精彩內(nèi)容

  • Android 自定義View的各種姿勢1 Activity的顯示之ViewRootImpl詳解 Activity...
    passiontim閱讀 171,527評論 25 707
  • 說明:題目在前励堡,答案在后谷丸。希望大家看到題目的時候先思考一下答案,不要依賴答案应结,如果覺得答案不夠具體刨疼,一定要上度娘找...
    蕾蕾是女神閱讀 538評論 2 4
  • 又到周末,人的心情更加爽朗鹅龄。早上闐闐起床很利索揩慕,比昨天早醒5分鐘。 中午給同學(xué)過生日沒回家砾层,晚上回家洗漱就...
    麗萍在這閱讀 239評論 0 0
  • 一說到拉客漩绵,我首先想到的是打扮得花里胡哨的老鴇,甩著一方散發(fā)著劣質(zhì)濃香的絲帕肛炮,“大爺大爺”或者“公子公子”地叫喚著...
    老少女簌簌閱讀 309評論 0 1