React Native 仿天猫物流跟踪时间轴

最近心血来潮开始学习ReactNative,正好最近有一个项目可能会用到时间轴,页面原型类似于天猫的物流跟踪,如下图

分析之后决定使用ListView来实现,左边的时间轴则使用Art来绘制。

分析左边的时间轴,其实就是每一行都有一条竖线,第一行和最后一行稍微特殊些,第一行需要单独绘制一下,最后一行只显示轴结点上方的线。

为了方便使用,封装成组件,具体实现如下:

import React, { Component } from 'react';
import {
    View,
    Text,
    ListView,
    StyleSheet,
    ART
} from 'react-native';

const { Surface, Shape, Path } = ART;

export default class TimeAxis extends React.Component {

    constructor(props) {
        super(props);
        this.state = {
            rowHeight: 60,
            dataSource: new ListView.DataSource({
                rowHasChanged: (row1, row2) => row1 !== row2,
            }),
        };
    }

    componentDidMount() {
        if (this.props.direction) {
            this.props.dataSource = this.props.dataSource.reverse();
        }
        this.setState({
            rowHeight: this.props.rowHeight ? this.props.rowHeight : this.state.rowHeight,
            dataSource: this.state.dataSource.cloneWithRows(this.props.dataSource ? this.props.dataSource : [])
        })
    }

    _renderRow = (rowData, sectionID, rowID) => {
        var item;
        if (this.props.row) {
            item = this.props.row(rowData, rowID, this.state.dataSource.getRowCount());
        } else {
            item = <Text>{rowData}</Text>
        }
        const line = new Path();
        const circle = new Path();

        let circleColor = "#e1e1e1";
        var back;
        if (rowID == 0) {
            line.moveTo(12, 27).lineTo(12, this.state.rowHeight).close();

            circle.moveTo(12, 9)
                .arc(0, 14, 7)
                .arc(0, -14, 7)
                .close();
            circleColor = "#59c93b";

            back = <ART.Shape style={{ zoom: 999, opacity: 0.1 }} d={new Path()
                .moveTo(12, 6)
                .arc(0, 20, 10)
                .arc(0, -20, 10)
                .close()} fill="#d3e2cf"></ART.Shape>
        }
        else {
            let y = this.state.rowHeight;
            if (rowID == this.state.dataSource.getRowCount() - 1) {
                y = this.state.rowHeight * 0.25;
            }
            line.moveTo(12, 0)
                .lineTo(12, y).close();

            circle.moveTo(12, this.state.rowHeight * 0.25)
                .arc(0, 10, 5)
                .arc(0, -10, 5)
                .close();
        }

        var itemStyles = this.props.itemStyle ? [styles.item_content, this.props.itemStyle] : styles.item_content;

        return (
            <View style={[styles.item, { height: this.state.rowHeight }]}>
                <View style={[styles.item_line]}>
                    <ART.Surface width={24} height={this.state.rowHeight}>
                        {back}
                        <ART.Shape d={circle} fill={circleColor} stroke="#e1e1e1" strokeWidth={1}></ART.Shape>
                        <ART.Shape d={line} stroke="#e1e1e1" strokeWidth={1}></ART.Shape>
                    </ART.Surface>
                </View>
                <View style={itemStyles}>{item}</View>
            </View >
        );
    }

    render() {
        return (
            <ListView
                style={{ marginTop: 5, backgroundColor: '#fff' }}
                dataSource={this.state.dataSource}
                renderRow={this._renderRow.bind(this)}
                renderFooter={this.renderFooter}
            />
        );
    }
}
const styles = StyleSheet.create({
    item: {
        marginTop: 1,
        backgroundColor: '#fff',
        flexDirection: 'row'
    },
    item_line: {
        flex: 2,
        paddingLeft: 5,

    },
    item_content: {
        flex: 13,
        borderBottomWidth: 1,
        borderColor: '#b0b0b0'
    }
});

 使用就简单了,设置好dataSource

var source = [
            { Text: "包裹等待揽收", Time: "2017-06-02 11:49:00" },
            { Text: "[北京市]XX快递 北京XX中心收件员XX已揽件", Time: "2017-06-02 15:49:05" },
            { Text: "[北京市]北京XX中心已发出", Time: "2017-06-02 16:20:11" },
            { Text: "[北京市]快件已到达XX站点", Time: "2017-06-02 20:15:04" },
            { Text: "[北京市]XX站点员:XXX正在派件", Time: "2017-06-03 07:35:18" },
            { Text: "[北京市]已完成", Time: "2017-06-03 08:21:48" }
        ];

设置行高(默认60),设置好每行的显示格式,就可以了。

<TimeAxis
                        itemStyle={{}}
                        rowHeight={60}
                        dataSource={source}
                        row={(rowData, i, count) => {
                            var fontColor = '#757575';
                            if (i == 0) {
                                fontColor = 'green';
                            }
                            return (
                                <View style={{ height: '100%', padding: 5 }}>
                                    <Text style={{ color: fontColor, flex: 1 }}>{rowData.Text}</Text>
                                    <Text style={{ color: fontColor, alignItems: 'flex-end' }}>{rowData.Time}</Text>
                                </View>
                            );
                        }}
                    />

 最张效果如图:

原文地址:https://www.cnblogs.com/efenghuo/p/7069821.html