最近心血來潮開始學習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> ); }} />
最張效果如圖:

