/react-native-timeline-feed

Customisable timeline for react native (using flatlist)

Primary LanguageJavaScriptMIT LicenseMIT

React Native Timeline feed

Timeline component for React Native App work for Android and iOS

code style: prettier NPM Version NPM Downloads

Thanks to the contributors of react-native-timeline-listview, as this is heavily based off that and amended with the newer React Native features (incl. flatlist).

Examples

IMPORTANT

Migrating from react-native-timeline-listview? Note the following breaking changes:

  • innerCircle to innerCircleType
  • options to flatlistProps
  • renderXXX(rowData, sectionID, rowID) to renderXXX({ item, index })

Table of Contents

Installation

npm i react-native-timeline-feed --save

Expo

Playground

Basic Usage

image2

import Timeline from 'react-native-timeline-feed'

constructor(){
    super()
    this.data = [
      {time: '09:00', title: 'Event 1', description: 'Event 1 Description'},
      {time: '10:45', title: 'Event 2', description: 'Event 2 Description'},
      {time: '12:00', title: 'Event 3', description: 'Event 3 Description'},
      {time: '14:00', title: 'Event 4', description: 'Event 4 Description'},
      {time: '16:30', title: 'Event 5', description: 'Event 5 Description'}
    ]
  }

render(){
    return(
        <Timeline
          data={this.data}
        />
    )
}

Custom

image3

render(){
    return(
        <Timeline
          //..other props
          circleSize={20}
          circleColor='rgb(45,156,219)'
          lineColor='rgb(45,156,219)'
          timeContainerStyle={{minWidth:52, marginTop: -5}}
          timeStyle={{textAlign: 'center', backgroundColor:'#ff9797', color:'white', padding:5, borderRadius:13}}
          descriptionStyle={{color:'gray'}}
          flatListProps={{
            style:{paddingTop:5}
          }}
        />
    )
}

Circle Dot

image4

render(){
    return(
        <Timeline
          //..other props
          innerCircleType='dot'
        />
    )
}

Icon

image5

constructor(){
    super()

    // Either of these will work and others should as well. You can provide your own icon component to be displayed.
    // Image Component
    const archeryImgSource = require('../img/archery.png');
    const badmintonImgSource = require('../img/badminton.png');
    const lunchImgSource = require('../img/lunch.png');
    const soccerImgSource = require('../img/soccer.png');
    const dumbbellImgSource = require('../img/dumbbell.png');
    const vectorIconImgSource = await MaterialIcon.getImageSource("new-releases", 30, "black");
    const ArcheryImage = (props) => <Image source={archeryImgSource} {...props} />;
    const BadmintonImage = (props) => <Image source={badmintonImgSource} {...props} />;
    const LunchImage = (props) => <Image source={lunchImgSource} {...props} />;
    const SoccerImage = (props) => <Image source={soccerImgSource} {...props} />;
    const DumbbellImage = (props) => <Image source={dumbbellImgSource} {...props} />;
    const VectorIconImage = (props) => <Image source={vectorIconImgSource} {...props} />;

    // VectorIcon Component
    const NewIcon = (props) => <MaterialIcon name="new-releases" size={30} color="black" {...props} />;

    this.data = [
      {time: '09:00', title: 'Archery Training', description: 'The Beginner Archery and Beginner Crossbow course does not require you to bring any equipment, since everything you need will be provided for the course. ',lineColor:'#009688', icon: ArcheryImage},
      {time: '10:45', title: 'Play Badminton', description: 'Badminton is a racquet sport played using racquets to hit a shuttlecock across a net.', icon: BadmintonImage},
      {time: '12:00', title: 'Lunch', icon: LunchImage},
      {time: '14:00', title: 'Watch Soccer', description: 'Team sport played between two teams of eleven players with a spherical ball. ',lineColor:'#009688', icon: SoccerImage},
      {time: '16:30', title: 'Go to Fitness center', description: 'Look out for the Best Gym & Fitness Centers around me :)', icon: DumbbellImage}
    ]
  }
render(){
    return(
        <Timeline
          //..other props
          innerCircleType='icon'
        />
    )
}

Override Render

image6

constructor(){
    super()

    // Either of these will work and others should as well. You can provide your own icon component to be displayed.
    // Image Component
    const archeryImgSource = require('../img/archery.png');
    const badmintonImgSource = require('../img/badminton.png');
    const lunchImgSource = require('../img/lunch.png');
    const soccerImgSource = require('../img/soccer.png');
    const dumbbellImgSource = require('../img/dumbbell.png');
    const vectorIconImgSource = await MaterialIcon.getImageSource("new-releases", 30, "black");
    const ArcheryImage = (props) => <Image source={archeryImgSource} {...props} />;
    const BadmintonImage = (props) => <Image source={badmintonImgSource} {...props} />;
    const LunchImage = (props) => <Image source={lunchImgSource} {...props} />;
    const SoccerImage = (props) => <Image source={soccerImgSource} {...props} />;
    const DumbbellImage = (props) => <Image source={dumbbellImgSource} {...props} />;
    const VectorIconImage = (props) => <Image source={vectorIconImgSource} {...props} />;

    // VectorIcon Component
    const NewIcon = (props) => <MaterialIcon name="new-releases" size={30} color="black" {...props} />;

    this.data = [
      {
        time: '09:00',
        title: 'Archery Training',
        description: 'The Beginner Archery and Beginner Crossbow course does not require you to bring any equipment, since everything you need will be provided for the course. ',
        lineColor:'#009688',
        icon: ArcheryImage,
        imageUrl: 'https://cloud.githubusercontent.com/assets/21040043/24240340/c0f96b3a-0fe3-11e7-8964-fe66e4d9be7a.jpg'
      },
      {
        time: '10:45',
        title: 'Play Badminton',
        description: 'Badminton is a racquet sport played using racquets to hit a shuttlecock across a net.',
        icon: BadmintonImage,
        imageUrl: 'https://cloud.githubusercontent.com/assets/21040043/24240405/0ba41234-0fe4-11e7-919b-c3f88ced349c.jpg'
      },
      {
        time: '12:00',
        title: 'Lunch',
        icon: LunchImage,
      },
      {
        time: '14:00',
        title: 'Watch Soccer',
        description: 'Team sport played between two teams of eleven players with a spherical ball. ',
        lineColor:'#009688',
        icon: SoccerImage,
        imageUrl: 'https://cloud.githubusercontent.com/assets/21040043/24240419/1f553dee-0fe4-11e7-8638-6025682232b1.jpg'
      },
      {
        time: '16:30',
        title: 'Go to Fitness center',
        description: 'Look out for the Best Gym & Fitness Centers around me :)',
        icon: DumbbellImage,
        imageUrl: 'https://cloud.githubusercontent.com/assets/21040043/24240422/20d84f6c-0fe4-11e7-8f1d-9dbc594d0cfa.jpg'
      }
    ]
  }

renderDetail = ({ item, index })=> {
  return (
    <View style={{ flex: 1 }}>
      <Text style={[styles.title]}>{item.title}</Text>;
      <View style={{ height: 75 }}>
        {item.imageUrl && (
          <Image
            source={{ uri: item.imageUrl, width: 50, height: 50 }}
            style={{ borderRadius: 25 }}
          />
        )}
        <Text>{item.description}</Text>
      </View>
    </View>
  );
}

render(){
  return(
      <Timeline
        //..other props
        renderDetail={this.renderDetail}
      />
  )
}

Pull to refresh and load more

rflm

onRefresh = () => {
  //set initial data
}

onEndReached = () => {
  //fetch next data
}

renderFooter = () => {
    //show loading indicator
    if (this.state.waiting) {
        return <ActivityIndicator />;
    } else {
        return <Text>~</Text>;
    }
}

render(){
    return(
        <Timeline
          //..other props
          flatListProps={{
            refreshControl: (
              <RefreshControl
                refreshing={this.state.isRefreshing}
                onRefresh={this.onRefresh}
              />
            ),
            renderFooter: this.renderFooter,
            onEndReached: this.onEndReached
          }}
        />
    )
}

Column Format

Single Column Right

simulator screen shot apr 6 2560 be 5 19 51 pm

render(){
    return(
        <Timeline
          //..other props
          columnFormat='single-column-right'
        />
    )
}

Two Column

simulator screen shot apr 6 2560 be 5 05 32 pm

render(){
    return(
        <Timeline
          //..other props
          columnFormat='two-column'
        />
    )
}

Time container hiding

showTime

render(){
    return(
        <Timeline
          //..other props
          showTime={false}
        />
    )
}

Configuration

Data Object:

Property Type Default Description
time string null event time
title string null event title
description string null event description
lineWidth int same as lineWidth of 'Timeline' event line width
lineColor string same as lineColor of 'Timeline' event line color
circleSize int same as circleSize of 'Timeline' event circle size
circleColor string same as circleColor of 'Timeline' event circle color
dotColor string same as dotColor of 'Timeline' event dot color (innerCircleType = 'dot')
icon React.ReactNode (component) same as icon of 'Timeline' event icon (innerCircleType = 'color')

Timeline:

Property Type Default Description
data data object null timeline data
innerCircleType string null timeline mode : 'none', 'dot', 'icon'
separator bool true render separator line of events
columnFormat string 'single-left' can be 'single-column-left', 'single-column-right', 'two-column'
lineWidth int 2 timeline line width
lineColor string '#007AFF' timeline line color
circleSize int 16 timeline circle size
circleColor string '#007AFF' timeline circle color
dotColor string 'white' timeline dot color (innerCircleType = 'dot')
icon React.ReactNode (component) null timeline icon (innerCircleType = 'color')
style object null custom styles of Timeline container
flatlistStyle object null custom styles of inner FlatList
timeStyle object null custom styles of event time
titleStyle object null custom styles of event title
descriptionStyle object null custom styles of event description
iconStyle object null custom styles of event icon
separatorStyle object null custom styles of separator
rowContainerStyle object null custom styles of event container
timeContainerStyle object null custom styles of container of event time
lastCircleContainerStyle object null custom styles of container for the last circle (used in conjuction with endWithCircle)
detailContainerStyle object null custom styles of container of event title and event description
onEventPress function(event) null function to be invoked when event was pressed
renderTime function({ item, index }) null custom render event time
renderDetail function({ item, index }) null custom render event title and event description
renderCircle function({ item, index, isLast }) null custom render circle (isLast will be true on the last item if when endWithCircle is set to true with an index of -1)
renderFullLine bool false render event border on last timeline item
endWithCircle bool false render a circle at the end of the last timeline item
flatListProps object null FlatList properties (excling keyExtractor, see next)
keyExtractor function(item) null FlatList keyExtractor
showTime boolean true Time container options

Shift problem

Text width of event time may not be the same.

untitled-1

fix by add 'minWidth' in 'timeContainerStyle' to appropriate value

render(){
    return(
        <Timeline
          //..other props
          timeContainerStyle={{minWidth:72}}
        />
    )
}

Adapt vectorIcon to be smaller than circleSize

If you want to make the VectorIcon, or in general the Component you provide smaller than the circleSize (default 16), set an iconStyle of iconStyle: { width: iconSize || undefined height: iconSize || undefined }