最近心血来潮开始学习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> ); }} />
最张效果如图: