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