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

在很多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美团项目源码

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏非著名程序员

基础篇章:关于 React Native 之 Modal 组件的讲解

(友情提示:RN学习,从最基础的开始,大家不要嫌弃太基础,会的同学请自行略过,希望不要耽误已经会的同学的宝贵时间) Modal是模态视图,它的作用是可以用来覆盖...

2547
来自专栏转载gongluck的CSDN博客

GDI透明贴图

网上下载的图片,有一些会有水印。水印的实现可以用透明贴图来做。透明贴图就是让两张图片合并的时候,重叠的部分中使一些颜色不显示,从而达到透明的效果。 如果用GDI...

4336
来自专栏老司机的简书

老司机带你走进Core Animation 之几种动画的简单应用

之所以要写这几种简单应用呢,是为了帮大家扩展一下思维,基于CAAnimation和CADisplayLink其实我们可以做到很多事情,不过我们都还是需要一个思路...

1182
来自专栏一“技”之长

iOS开发封装一个可以响应超链接的label——基于RCLabel的交互扩展

        iOS系统是一个十分注重用户体验的系统,在iOS系统中,用户交互的方案也十分多,然而要在label中的某部分字体中添加交互行为确实不容易的,如果...

971
来自专栏编程之旅

高性能设置圆角,告别离屏渲染

今天来写一个老生常谈的话题,也是一个面试的高频问题,我也在面试时不止一次被问到过这个问题——如何高性能的设置圆角。就用他作为2017年春节上班之后的第一篇文章。

2071
来自专栏数据小魔方

leaflet在线地图进阶宝典之——高级辅助特性

本文跟大家分享leaflet在线地图的高级附加属性,这些属性通常来讲仅仅作为我们数据额可视化项目的修饰元素,而并不会影响数据元素。 但是有了这些辅助修饰元素,往...

3494
来自专栏iOS开发攻城狮的集散地

iOS 性能监测之FPS

3273
来自专栏编程语言

iOS:AVCaptureSession 通过摄像头获取某一帧的画面

2722
来自专栏PPV课数据科学社区

【学习】七天搞定SAS(四):数据输出

弄清楚了基本的PROC之后,开始研究SAS的输出...毕竟有了数据处理的结果之后,还要有一个比较舒服的输出格式才可以嘛。 SAS的结果发送系统:ODS SAS里...

3858
来自专栏菩提树下的杨过

ExtJs学习笔记(7)_获取GridPanel选中行的详细信息

这一节,我们将学习如何获取Grid当前选中行的信息 1.xml数据源内容: <?xml version="1.0" encoding="UTF-8"?> <D...

22410

扫码关注云+社区

领取腾讯云代金券