• [RN] React Native 好用的时间线 组件


     React Native 好用的时间线 组件

    效果如下:

     

    实现方法:

    一、组件封装

    CustomTimeLine.js

    "use strict";
    
    import React, {Component} from "react";
    import {
        StyleSheet,
        ListView,
        Image,
        View,
        Text,
        TouchableOpacity
    } from "react-native";
    
    const ds = new ListView.DataSource({
        rowHasChanged: (r1, r2) => r1 !== r2,
        sectionHeaderHasChanged: (s1, s2) => s1 !== s2
    });
    
    const defaultCircleSize = 16;
    const defaultCircleColor = "#007AFF";
    const defaultLineWidth = 2;
    const defaultLineColor = "#007AFF";
    const defaultTimeTextColor = "black";
    const defaultDotColor = "white";
    const defaultInnerCircle = "none";
    
    export default class CustomTimeLine extends Component {
        static defaultProps = {
            circleSize: defaultCircleSize,
            circleColor: defaultCircleColor,
            lineWidth: defaultLineWidth,
            lineColor: defaultLineColor,
            innerCircle: defaultInnerCircle,
            columnFormat: "single-column-left",
            separator: false,
            showTime: true
        };
    
        constructor(props, context) {
            super(props, context);
    
            this._renderRow = this._renderRow.bind(this);
            this.renderTime = (this.props.renderTime
                    ? this.props.renderTime
                    : this._renderTime
            ).bind(this);
            this.renderDetail = (this.props.renderDetail
                    ? this.props.renderDetail
                    : this._renderDetail
            ).bind(this);
            this.renderCircle = (this.props.renderCircle
                    ? this.props.renderCircle
                    : this._renderCircle
            ).bind(this);
            this.renderEvent = this._renderEvent.bind(this);
    
            this.state = {
                data: this.props.data,
                dataSource: ds.cloneWithRows(this.props.data),
                x: 0,
                 0
            };
        }
    
        componentWillReceiveProps(nextProps) {
            this.setState({
                data: nextProps.data,
                dataSource: ds.cloneWithRows(nextProps.data)
            });
        }
    
        render() {
            return (
                <View style={[styles.container, this.props.style]}>
                    <ListView
                        ref="listView"
                        style={[styles.listview, this.props.listViewStyle]}
                        dataSource={this.state.dataSource}
                        renderRow={this._renderRow}
                        automaticallyAdjustContentInsets={false}
                        {...this.props.options}
                    />
                </View>
            );
        }
    
        _renderRow(rowData, sectionID, rowID) {
            let content = null;
    
            switch (this.props.columnFormat) {
                case "single-column-left":
                    content = (
                        <View style={[styles.rowContainer, this.props.rowContainerStyle]}>
                            {this.renderTime(rowData, sectionID, rowID)}
                            {this.renderEvent(rowData, sectionID, rowID)}
                            {this.renderCircle(rowData, sectionID, rowID)}
                        </View>
                    );
                    break;
                case "single-column-right":
                    content = (
                        <View style={[styles.rowContainer, this.props.rowContainerStyle]}>
                            {this.renderEvent(rowData, sectionID, rowID)}
                            {this.renderTime(rowData, sectionID, rowID)}
                            {this.renderCircle(rowData, sectionID, rowID)}
                        </View>
                    );
                    break;
                case "two-column":
                    content =
                        rowID % 2 === 0 ? (
                            <View style={[styles.rowContainer, this.props.rowContainerStyle]}>
                                {this.renderTime(rowData, sectionID, rowID)}
                                {this.renderEvent(rowData, sectionID, rowID)}
                                {this.renderCircle(rowData, sectionID, rowID)}
                            </View>
                        ) : (
                            <View style={[styles.rowContainer, this.props.rowContainerStyle]}>
                                {this.renderEvent(rowData, sectionID, rowID)}
                                {this.renderTime(rowData, sectionID, rowID)}
                                {this.renderCircle(rowData, sectionID, rowID)}
                            </View>
                        );
                    break;
            }
            return <View key={rowID}>{content}</View>;
        }
    
        _renderTime(rowData, sectionID, rowID) {
            if (!this.props.showTime) {
                return null;
            }
            var timeWrapper = null;
            switch (this.props.columnFormat) {
                case "single-column-left":
                    timeWrapper = {
                        alignItems: "flex-end"
                    };
                    break;
                case "single-column-right":
                    timeWrapper = {
                        alignItems: "flex-start"
                    };
                    break;
                case "two-column":
                    timeWrapper = {
                        flex: 1,
                        alignItems: rowID % 2 === 0 ? "flex-end" : "flex-start"
                    };
                    break;
            }
            return (
                <View style={timeWrapper}>
                    <View style={[styles.timeContainer, this.props.timeContainerStyle]}>
                        <Text style={[styles.time, this.props.timeStyle]}>
                            {rowData.time}
                        </Text>
                    </View>
                </View>
            );
        }
    
        _renderEvent(rowData, sectionID, rowID) {
            const lineWidth = rowData.lineWidth
                ? rowData.lineWidth
                : this.props.lineWidth;
            const isLast = this.props.renderFullLine
                ? !this.props.renderFullLine
                : this.state.data.slice(-1)[0] === rowData;
            const lineColor = isLast
                ? "rgba(0,0,0,0)"
                : rowData.lineColor ? rowData.lineColor : this.props.lineColor;
            let opStyle = null;
    
            switch (this.props.columnFormat) {
                case "single-column-left":
                    opStyle = {
                        borderColor: lineColor,
                        borderLeftWidth: lineWidth,
                        borderRightWidth: 0,
                        marginLeft: 20,
                        paddingLeft: 20
                    };
                    break;
                case "single-column-right":
                    opStyle = {
                        borderColor: lineColor,
                        borderLeftWidth: 0,
                        borderRightWidth: lineWidth,
                        marginRight: 20,
                        paddingRight: 20
                    };
                    break;
                case "two-column":
                    opStyle =
                        rowID % 2 == 0
                            ? {
                                borderColor: lineColor,
                                borderLeftWidth: lineWidth,
                                borderRightWidth: 0,
                                marginLeft: 20,
                                paddingLeft: 20
                            }
                            : {
                                borderColor: lineColor,
                                borderLeftWidth: 0,
                                borderRightWidth: lineWidth,
                                marginRight: 20,
                                paddingRight: 20
                            };
                    break;
            }
    
            return (
                <View
                    style={[styles.details, opStyle]}
                    onLayout={evt => {
                        if (!this.state.x && !this.state.width) {
                            const {x, width} = evt.nativeEvent.layout;
                            this.setState({x, width});
                        }
                    }}
                >
                    <TouchableOpacity
                        disabled={this.props.onEventPress == null}
                        style={[this.props.detailContainerStyle]}
                        onPress={() =>
                            this.props.onEventPress ? this.props.onEventPress(rowData) : null
                        }
                    >
                        <View style={styles.detail}>
                            {this.renderDetail(rowData, sectionID, rowID)}
                        </View>
                        {this._renderSeparator()}
                    </TouchableOpacity>
                </View>
            );
        }
    
        _renderDetail(rowData, sectionID, rowID) {
            let title = rowData.description ? (
                <View>
                    <Text style={[styles.title, this.props.titleStyle]}>
                        {rowData.title}
                    </Text>
                    <Text style={[styles.description, this.props.descriptionStyle]}>
                        {rowData.description}
                    </Text>
                </View>
            ) : (
                <Text style={[styles.title, this.props.titleStyle]}>{rowData.title}</Text>
            );
            return <View style={styles.container}>{title}</View>;
        }
    
        _renderCircle(rowData, sectionID, rowID) {
            var circleSize = rowData.circleSize
                ? rowData.circleSize
                : this.props.circleSize ? this.props.circleSize : defaultCircleSize;
            var circleColor = rowData.circleColor
                ? rowData.circleColor
                : this.props.circleColor ? this.props.circleColor : defaultCircleColor;
            var lineWidth = rowData.lineWidth
                ? rowData.lineWidth
                : this.props.lineWidth ? this.props.lineWidth : defaultLineWidth;
    
            var circleStyle = null;
    
            switch (this.props.columnFormat) {
                case "single-column-left":
                    circleStyle = {
                         this.state.x ? circleSize : 0,
                        height: this.state.x ? circleSize : 0,
                        borderRadius: circleSize / 2,
                        backgroundColor: circleColor,
                        left: this.state.x - circleSize / 2 + (lineWidth - 1) / 2
                    };
                    break;
                case "single-column-right":
                    circleStyle = {
                         this.state.width ? circleSize : 0,
                        height: this.state.width ? circleSize : 0,
                        borderRadius: circleSize / 2,
                        backgroundColor: circleColor,
                        left: this.state.width - circleSize / 2 - (lineWidth - 1) / 2
                    };
                    break;
                case "two-column":
                    circleStyle = {
                         this.state.width ? circleSize : 0,
                        height: this.state.width ? circleSize : 0,
                        borderRadius: circleSize / 2,
                        backgroundColor: circleColor,
                        left: this.state.width - circleSize / 2 - (lineWidth - 1) / 2
                    };
                    break;
            }
    
            var innerCircle = null;
            switch (this.props.innerCircle) {
                case "icon":
                    let iconSource = rowData.icon ? rowData.icon : this.props.icon;
                    let iconStyle = {
                        height: circleSize,
                         circleSize
                    };
                    innerCircle = (
                        <Image
                            source={iconSource}
                            style={[iconStyle, this.props.iconStyle]}
                        />
                    );
                    break;
                case "dot":
                    let dotStyle = {
                        height: circleSize / 2,
                         circleSize / 2,
                        borderRadius: circleSize / 4,
                        backgroundColor: rowData.dotColor
                            ? rowData.dotColor
                            : this.props.dotColor ? this.props.dotColor : defaultDotColor
                    };
                    innerCircle = <View style={[styles.dot, dotStyle]}/>;
                    break;
            }
            return (
                <View style={[styles.circle, circleStyle, this.props.circleStyle]}>
                    {innerCircle}
                </View>
            );
        }
    
        _renderSeparator() {
            if (!this.props.separator) {
                return null;
            }
            return <View style={[styles.separator, this.props.separatorStyle]}/>;
        }
    }
    
    const styles = StyleSheet.create({
        container: {
            flex: 1
        },
        listview: {
            flex: 1
        },
        sectionHeader: {
            marginBottom: 15,
            backgroundColor: "#007AFF",
            height: 30,
            justifyContent: "center"
        },
        sectionHeaderText: {
            color: "#FFF",
            fontSize: 18,
            alignSelf: "center"
        },
        rowContainer: {
            flexDirection: "row",
            flex: 1,
            //alignItems: 'stretch',
            justifyContent: "center"
        },
        timeContainer: {
            minWidth: 45
        },
        time: {
            textAlign: "right",
            color: defaultTimeTextColor
        },
        circle: {
             16,
            height: 16,
            borderRadius: 10,
            position: "absolute",
            left: -8,
            alignItems: "center",
            justifyContent: "center"
        },
        dot: {
             8,
            height: 8,
            borderRadius: 4,
            backgroundColor: defaultDotColor
        },
        title: {
            fontSize: 16,
            fontWeight: "bold"
        },
        details: {
            borderLeftWidth: defaultLineWidth,
            flexDirection: "column",
            flex: 1
        },
        detail: {paddingTop: 10, paddingBottom: 10},
        description: {
            marginTop: 10
        },
        separator: {
            height: 1,
            backgroundColor: "#aaa",
            marginTop: 10,
            marginBottom: 10
        }
    });

    代码调用:

    import React, {Component} from 'react';
    import {StyleSheet, View} from 'react-native';
    import Timeline from './CustomTimeLine';
    
    export default class TestTimeLine extends Component {
        constructor() {
            super()
            this.data = [
                {time: '09:00', title: '商家已接单', description: 'Event 1 Description'},
                {time: '10:45', title: '正在沟通', description: 'Event 2 Description'},
                {time: '12:00', title: '合同签订', description: 'Event 3 Description'},
                {time: '14:00', title: '订单完成', description: 'Event 4 Description'},
                {time: '16:30', title: '用户评价', description: 'Event 5 Description'}
            ]
        }
    
        render() {
            return (
                <View style={styles.container}>
                    <Timeline
                        style={styles.list}
                        data={this.data}
                        showTime={true}
                    />
                </View>
            );
        }
    }
    
    const styles = StyleSheet.create({
        container: {
            flex: 1,
            padding: 20,
            paddingTop: 65,
            backgroundColor: 'white'
        },
        list: {
            flex: 1,
            marginTop: 20,
        },
    });

    更多使用方法,参考:

    https://github.com/thegamenicorus/react-native-timeline-listview

    本博客地址: wukong1688

    本文原文地址:https://www.cnblogs.com/wukong1688/p/11049014.html

    转载请著名出处!谢谢~~

  • 相关阅读:
    Spark小课堂Week3 FirstSparkApp(RDD开发)
    Catalyst揭秘 Day5 optimizer解析
    Spark小课堂Week2 Hello Streaming
    Spark小课堂Week1 Hello Spark
    Catalyst揭秘 Day4 analyzer解析
    Catalyst揭秘 Day3 sqlParser解析
    Catalyst揭秘 Day2 Catalyst源码初探
    Catalyst揭秘 Day1 Catalyst本地解析
    java泛型
    java中数组以及集合
  • 原文地址:https://www.cnblogs.com/wukong1688/p/11049014.html
Copyright © 2020-2023  润新知