React Native项目实战之搭建美团个人中心界面

来源:互联网 发布:人类永生不死知乎 编辑:程序博客网 时间:2024/05/23 02:03

在很多app应用型APP中,个人中心往往会单独出一个模块,而对于刚入门React Native的朋友来说,怎么去实现一些静态的页面,并且怎么着手实现,怎么分层,怎么去实现这个架构,我想是很基础的(ps,本人新书,《React Native实战经典》定义国庆前后出版,欢迎大家捧场)。
首先,看一下实现的效果:
这里写图片描述这里写图片描述

项目讲解

首先,这是一个纯静态的页面,包括顶部的个人介绍页面,已经下面的一个扩展页面。而下面扩展页面风格基本差不多,我们可以对其做一个简单的封装(MineItemCell.js),为了项目代码维护的方便,我们还可以将这些样式统一一下(text.js)。
text.js文字样式

/** * https://github.com/facebook/react-native * @flow */import React from 'react';import ReactNative, { StyleSheet, Dimensions, Text ,ReactElement} from 'react-native';export function HeadingBig({style, ...props}: Object): ReactElement {    return <Text style={[styles.h0, style]} {...props} />}export function Heading1({style, ...props}: Object): ReactElement {    return <Text style={[styles.h1, style]} {...props} />}export function Heading2({style, ...props}: Object): ReactElement {    return <Text style={[styles.h2, style]} {...props} />}export function Paragraph({style, ...props}: Object): ReactElement {    return <Text style={[styles.p, style]} {...props} />}export function Tip({style, ...props}: Object): ReactElement {    return <Text style={[styles.tip, style]} {...props} />}const styles = StyleSheet.create({    h0: {        fontSize: 40,        color: '#06C1AE',    },    h1: {        fontSize: 15,        fontWeight: 'bold',        color: '#222222',    },    h2: {        fontSize: 14,        color: '#222222',    },    p: {        fontSize: 13,        color: '#777777',    },    tip: {        fontSize: 13,        color: '#999999'    }});

MineItemCell.js

/** * Copyright (c) 2017-present, Liu Jinyong * All rights reserved. * * https://github.com/huanxsd/MeiTuan   * @flow */import React, { Component } from 'react';import { View, Text, StyleSheet, Image, TouchableOpacity } from 'react-native';import { Heading2, Paragraph } from './widght/Text'import Separator from './widght/Separator'var Dimensions = require('Dimensions');var ScreenWidth = Dimensions.get('window').width;class MineItemCell extends Component {    render() {        let icon = null;        if (this.props.image) {            icon = <Image style={styles.icon} source={this.props.image} />        }        return (            <View style={styles.container}>                <TouchableOpacity>                    <View style={[styles.content, this.props.style]}>                        {icon}                        <Heading2>{this.props.title}</Heading2>                        <View style={{ flex: 1, backgroundColor: 'blue' }} />                        <Paragraph style={{ color: '#999999' }}>{this.props.subtitle}</Paragraph>                        <Image style={styles.arrow} source={require('./image/icon_arrow.png')} />                    </View>                    <Separator />                </TouchableOpacity>            </View>        );    }}const styles = StyleSheet.create({    container: {        backgroundColor: 'white',    },    content: {        height: 44,        flexDirection: 'row',        alignItems: 'center',        paddingLeft: 15,        paddingRight: 10,    },    icon: {        width: 25,        height: 25,        marginRight: 10,    },    subtitleContainer: {        flexDirection: 'row',        justifyContent: 'flex-end',        alignItems: 'center',    },    arrow: {        width: 14,        height: 14,        marginLeft: 5,    }});export default MineItemCell;

然后到界面的绘制了,首先绘制顶部个人资料部分:

renderHeader() {        return (            <View style={styles.header}>                <View style={styles.topContainer}>                    <TouchableOpacity>                        <Image style={[styles.icon, {marginRight: 15}]}                               source={require('./image/icon_navigationItem_message_white.png')}/>                    </TouchableOpacity>                    <TouchableOpacity>                        <Image style={[styles.icon, {marginRight: 10}]}                               source={require('./image/icon_navigationItem_set_white.png')}/>                    </TouchableOpacity>                </View>                <View style={styles.userContainer}>                    <Image style={styles.avatar} source={require('./image/avatar.png')}/>                    <View>                        <View style={{flexDirection: 'row'}}>                            <Heading1 style={{color: 'white'}}>code_xzh</Heading1>                            <Image style={{marginLeft: 4}}                                   source={require('./image/beauty_technician.png')}/>                        </View>                        <Paragraph style={{color: 'white', marginTop: 4}}>个人信息 ></Paragraph>                    </View>                </View>            </View>        )    }

接着,我们在绘制下面的部分,由于下面部分我们队每个子视图做了封装,所以,我们可以这么做:通过getDataList()获取所有的值,进而绘制。
renderCells代码:

renderCells() {        let cells = []        let dataList = this.getDataList()        for (let i = 0; i < dataList.length; i++) {            let sublist = dataList[i]            for (let j = 0; j < sublist.length; j++) {                let data = sublist[j]                let cell = <MineItemCell image={data.image} title={data.title} subtitle={data.subtitle}                                         key={data.title}/>                cells.push(cell)            }            cells.push(<SpacingView key={i}/>)        }        return (            <View style={{flex: 1}}>                {cells}            </View>        )    }

getDataList()代码:

getDataList() {        return (            [                [                    {title: '我的钱包', subtitle: '办信用卡', image: require('./image/icon_mine_wallet.png')},                    {title: '余额', subtitle: '¥95872385', image: require('./image/icon_mine_balance.png')},                    {title: '抵用券', subtitle: '63', image: require('./image/icon_mine_voucher.png')},                    {title: '会员卡', subtitle: '2', image: require('./image/icon_mine_membercard.png')}                ],                [                    {title: '好友去哪', image: require('./image/icon_mine_friends.png')},                    {title: '我的评价', image: require('./image/icon_mine_comment.png')},                    {title: '我的收藏', image: require('./image/icon_mine_collection.png')},                    {title: '会员中心', subtitle: 'v15', image: require('./image/icon_mine_mineorder.png')},                    {title: '积分商城', subtitle: '好礼已上线', image: require('./image/icon_mine_member.png')}                ],                [                    {title: '客服中心', image: require('./image/icon_mine_service.png')},                    {title: '关于美团', subtitle: '我要合作', image: require('./image/icon_mine_about.png')}                ]            ]        )    }

页面完整代码:

/** * Sample React Native App * https://github.com/facebook/react-native * @flow ScrollView组件 */import React, {Component} from 'react';import {    AppRegistry,    StyleSheet,    RefreshControl,    Image,    ScrollView,    TouchableOpacity,    View} from 'react-native';import { Heading1, Heading2, Paragraph } from './widght/Text'import MineItemCell from './MineItemCell';import SpacingView from './widght/SpacingView'var Dimensions = require('Dimensions');var screenWidth = Dimensions.get('window').width;var screenHeight = Dimensions.get('window').height;class MineScene extends Component {    state: {        isRefreshing: boolean    }    constructor(props: Object) {        super(props)        this.state = {            isRefreshing: false        }    }    onHeaderRefresh() {        this.setState({isRefreshing: true})        setTimeout(() => {            this.setState({isRefreshing: false})        }, 2000);    }    renderCells() {        let cells = []        let dataList = this.getDataList()        for (let i = 0; i < dataList.length; i++) {            let sublist = dataList[i]            for (let j = 0; j < sublist.length; j++) {                let data = sublist[j]                let cell = <MineItemCell image={data.image} title={data.title} subtitle={data.subtitle}                                         key={data.title}/>                cells.push(cell)            }            cells.push(<SpacingView key={i}/>)        }        return (            <View style={{flex: 1}}>                {cells}            </View>        )    }    renderHeader() {        return (            <View style={styles.header}>                <View style={styles.topContainer}>                    <TouchableOpacity>                        <Image style={[styles.icon, {marginRight: 15}]}                               source={require('./image/icon_navigationItem_message_white.png')}/>                    </TouchableOpacity>                    <TouchableOpacity>                        <Image style={[styles.icon, {marginRight: 10}]}                               source={require('./image/icon_navigationItem_set_white.png')}/>                    </TouchableOpacity>                </View>                <View style={styles.userContainer}>                    <Image style={styles.avatar} source={require('./image/avatar.png')}/>                    <View>                        <View style={{flexDirection: 'row'}}>                            <Heading1 style={{color: 'white'}}>code_xzh</Heading1>                            <Image style={{marginLeft: 4}}                                   source={require('./image/beauty_technician.png')}/>                        </View>                        <Paragraph style={{color: 'white', marginTop: 4}}>个人信息 ></Paragraph>                    </View>                </View>            </View>        )    }    getDataList() {        return (            [                [                    {title: '我的钱包', subtitle: '办信用卡', image: require('./image/icon_mine_wallet.png')},                    {title: '余额', subtitle: '¥95872385', image: require('./image/icon_mine_balance.png')},                    {title: '抵用券', subtitle: '63', image: require('./image/icon_mine_voucher.png')},                    {title: '会员卡', subtitle: '2', image: require('./image/icon_mine_membercard.png')}                ],                [                    {title: '好友去哪', image: require('./image/icon_mine_friends.png')},                    {title: '我的评价', image: require('./image/icon_mine_comment.png')},                    {title: '我的收藏', image: require('./image/icon_mine_collection.png')},                    {title: '会员中心', subtitle: 'v15', image: require('./image/icon_mine_mineorder.png')},                    {title: '积分商城', subtitle: '好礼已上线', image: require('./image/icon_mine_member.png')}                ],                [                    {title: '客服中心', image: require('./image/icon_mine_service.png')},                    {title: '关于美团', subtitle: '我要合作', image: require('./image/icon_mine_about.png')}                ]            ]        )    }    render() {        return (            <View style={styles.container}>                <View style={{                    position: 'absolute',                    width: screenWidth,                    height: screenHeight / 2,                    backgroundColor: '#06C1AE'                }}/>                <ScrollView                    refreshControl={                        <RefreshControl                            refreshing={this.state.isRefreshing}                            onRefresh={() => this.onHeaderRefresh()}                            tintColor='gray'                        />                    }>                    {this.renderHeader()}                    <SpacingView />                    {this.renderCells()}                </ScrollView>            </View>        );    }}const styles = StyleSheet.create({    container: {        flex: 1,        backgroundColor: '#f3f3f3',    },    header: {        backgroundColor: '#06C1AE',        paddingBottom: 20    },    topContainer: {        flexDirection: 'row',        justifyContent: 'flex-end',        alignItems: 'center',        marginTop: 7,    },    icon: {        width: 27,        height: 27,    },    userContainer: {        flexDirection: 'row',        alignItems: 'center',        margin: 10,    },    avatar: {        width: 50,        height: 50,        marginRight: 10,        borderRadius: 25,        borderWidth: 2,        borderColor: '#51D3C6'    }});export default MineScene;

美团项目源码地址:react native美团项目源码