Skip to content

Timeline

A timeline displays tasks and the order in which they need to be completed.

Anatomy

Timeline Cell Views consist of a timestamp, an icon, a node, a vertical timeline, up to two statuses, and text content that can contain a headline, description, a left attribute, and a right attribute.

Timeline Preview Cell Views consist of a timestamp, a node, a horizontal timeline, and a headline.

Timeline Views consist of a scrollable list of Timeline Cell Views displayed vertically. The cells are ordered by date and are grouped under sticky headers displaying either the month or the date. The current day is marked by a colored line. If there are no cells, a customizable image and message is displayed instead.

Timeline View Anatomy
Timeline View Anatomy

Timeline Preview Views consist of a title, a button, and a list of Timeline Preview Cell Views displayed horizontally. This list is non-scrollable and displays two cells for mobile devices, and four cells for tablets.

Timeline Preview View Anatomy
Timeline Preview View Anatomy

Usage

A Timeline Cell is used to represent an event and should lead to more details on the event upon being clicked. A Timeline View is used to display these cells in chronological order.

A Timeline Preview Cell gives a high-level overview of an event and is not clickable. A Timeline Preview View is used to display the Preview Cells along with a See All button. Clicking the Timeline Preview View should lead to the full Timeline View.

Construction

The recommended approach for creating a Timeline Cell is through binding a TimelineCellData to a TimelineCellProvider, which will be covered in detail in "Populating the Timeline". The rest of this section will go over direct creation of the components.

A Timeline Cell can be created by the constructor in code:

TimelineCellView cell = new TimelineCellView(getContext());

A Timeline Cell can also be created by declaring a TimelineCellView element in XML, like this:

<com.sap.cloud.mobile.fiori.timelineview.TimelineCellView
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        app:headline="@string/timeline_headline"
        app:headlineTextAppearance="@style/TextAppearance.Body"
        app:timelinePreviewHeadlineTextAppearance="@style/TextAppearance.Body"
        app:description="@string/timeline_description"
        app:descriptionTextAppearance="@style/TextAppearance.Body"
        app:timelineAttribute="@string/timeline_attribute"
        app:timelineAttributeTextAppearance="@style/TextAppearance.Body"
        app:timelineRightAttribute="@string/timeline_right_attribute"
        app:timelineRightAttributeTextAppearance="@style/TextAppearance.Body"
        app:timelineTimestampTextAppearance="@style/TextAppearance.Body"
        app:timelineMonthTextAppearance="@style/TextAppearance.Body"
        app:timelineTodayLineColor="@color/timeline_today_line_color"
        app:timelineDateFormat="@string/timeline_date_format"
        app:timelineTimeFormat="@string/timeline_time_format"
        app:timelineDayDateFormat="@string/timeline_day_date_format"
        app:timelineMonthFormat="@string/timeline_month_format"
        app:timelineDateHeaderFormat="@string/timeline_date_header_format"
        app:timelineButtonTextAppearance="@style/FioriButton.Flat"
        app:timelineButtonBackground="@drawable/fiori_flat_btn_ripple">
</com.sap.cloud.mobile.fiori.timelineview.TimelineCellView>

The above XML declaration creates a TimelineCellView with the following attributes of note:

  • app:timelineTodayLineColor – The color of the line displayed to mark the current day.
  • app:timelinePreviewHeadlineTextAppearance – The properties of the headline text in Preview View.
  • app:timelineButtonTextAppearance – The properties of the text on the button for Preview View.
  • app:timelineButtonBackground – The properties of the background on the button for Preview View.
  • app:timelineDateFormat – The timestamp format when the timestamp type is DATE.
  • app:timelineTimeFormat – The timestamp format when the timestamp type is TIME.
  • app:timelineDayDateFormat – The timestamp format when the timestamp type is DAY_DATE.
  • app:timelineMonthFormat – The format of the month text that appears in PREVIEW cells and MONTH states when using TIMELINE_GROUP_MODE_MONTH.
  • app:timelineDateHeaderFormat – The format of the header text when using TIMELINE_GROUP_MODE_DATE.

A Timeline can be created by the constructor in code:

TimelineView timeline = new TimelineView(getContext());

A Timeline can also be created by declaring a TimelineView element in XML, like this:

<com.sap.cloud.mobile.fiori.timelineview.TimelineView
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        app:timelineEmptyDrawable="@drawable/ic_event_note_24dp"
        app:timelineEmptyHeadline="@string/timeline_empty_headline"
        app:timelineEmptyHeadlineTextAppearance="@style/TextAppearance.Body"
        app:timelineEmptyDescription="@string/timeline_empty_description"
        app:timelineEmptyDescriptionTextAppearance="@style/TextAppearance.Body">
</com.sap.cloud.mobile.fiori.timelineview.TimelineView>

The above XML declaration creates a TimelineView with the following attributes:

  • app:timelineEmptyDrawable – The image that is displayed when there are no cells.
  • app:timelineEmptyHeadline – The headline of the message that is displayed when there are no cells.
  • app:timelineEmptyHeadlineTextAppearance – The properties of the empty headline text.
  • app:timelineEmptyDescription – The description of the message that is displayed when there are no cells.
  • app:timelineEmptyDescriptionTextAppearance – The properties of the empty description text.

Fields

Headline

The headline displays a title for the event.

cell.setHeadline(R.string.headlineText);

Description

The description describes the event. It can display up to three lines.

cell.setDescription(R.string.descriptionText);

Attribute

The attribute displays the type of task or an aspect of the event. There can be an attribute that is left-aligned as well as right-aligned.

cell.setAttribute(R.string.attributeText);
cell.setRightAttribute(R.string.rightAttributeText);

Due Date

The due date represents the time period of the event and consists of a start date and an end date. The Timeline will automatically create a cell for each date within the range and will order the cells by their start date. The start date will determine what is displayed in the timestamp.

cell.setDueDate("22/10/2020", "25/10/2020");

If only one date is provided, that date is assumed to be the start date as well as the end date.

cell.setDueDate("22/10/2020");

If no date is provided, the cell's start date and end date are assumed to be the current time.

The accepted date formats are: dd/MM/yyyy, dd/MM/yyyy HH:mm, dd-MMM-yyyy, dd-MMM-yyyy HH:mm, MMM dd yyyy, MMM dd yyyy HH:mm

Timestamp

The timestamp displays the date or time when the event takes place, depending on the start date and the timestamp type. The available timestamp types are: DATE, DAY_DATE, and TIME. By default, the timestamp type is DATE.

The timestamp format can be customized to display different date formats.

cell.setDueDate("22/10/2020 14:00");
cell.setTimestampType(TimelineCellView.TimelineCellTimestampType.DATE); // 22
cell.setDateFormat("ddd"); // 022
cell.setTimestampType(TimelineCellView.TimelineCellTimestampType.DAY_DATE); // THU\n22
cell.setDayDateFormat("EEE d"); // THU 22
cell.setTimestampType(TimelineCellView.TimelineCellTimestampType.TIME); // 2:00 PM
cell.setTimeFormat("hh:mm"); // 02:00

If consecutive cells have the same start date (YEAR, MONTH, DAY_OF_MONTH), then only the first cell in that sequence will display a timestamp. If the consecutive cells are of type TIME, then HOUR_OF_DAY and MINUTE will be taken into account.

Icon

The icon is an image displayed under the timestamp.

cell.setIcon(R.drawable.icon, R.string.icon_description);
cell.setIconColor(iconColor);

Statuses

Up to two statuses can be displayed, stacked vertically, to show aspects of the event. A status can be customized as either text or an image.

cell.setStatus(R.drawable.status_icon, 0, R.string.status_description);
cell.setStatus(R.string.status, 1);
cell.setStatusColor(statusImageColor, 0);
cell.setStatusColor(statusTextColor, 1);

Enabled/Disabled State

In TimelineView, each cell can be either enabled or disabled. The default state is enabled. The disabled state prevents the cell from being clicked.

cell.setIsEnabled(false);
Timeline Cell Enabled
Enabled and Disabled State

Node

The node represents the state of the event. The available states are:

State Definition
PAST_START Start date of the project timeline that has passed.
PAST Completed task with a due date that has passed.
PAST_UPCOMING Incomplete task with a due date that has passed.
PAST_PROGRESS In progress task with a due date that has passed.
PAST_END End date of the project timeline that has passed.
TODAY Dedicated cell for displaying the current day. The Timeline will automatically create a cell with this state.
START Upcoming start date of the project timeline.
DONE Upcoming task that has been completed.
UPCOMING Upcoming task that has not been completed.
PROGRESS Upcoming task that is in progress.
END Upcoming end date of the project timeline.
MONTH Dedicated cell for displaying the month. The Timeline will automatically create cells with this state.
ADD Dedicated cell for adding an event. The Timeline will automatically create a cell with this state if TimelineCellProvider's setShouldAddCreateCell(true) is called and the current day has no events.
NOT_SPECIFIED Default state of the cell.
cell.setState(TimelineCellView.TimelineCellState.START);

If an event with START, DONE, UPCOMING, PROGRESS, or END is passed, its state will change to PAST_START, PAST, PAST_UPCOMING, PAST_PROGRESS, or PAST_END, respectively.

Click Listener

The Timeline accepts a TimelineItemTouchListener.TimelineItemClickListener that defines click behavior for each item.

Note

As of the 7.0 update, there is no longer a distinct card element, so onCardClick takes priority as the primary click action and triggers upon a click on any area of the cell. As a result, click behavior should be defined in onCardClick instead of onClick.

TimelineItemTouchListener.TimelineItemClickListener listener = new TimelineItemTouchListener.TimelineItemClickListener() {
    @Override
    public void onCardClick(@NonNull View view, int position) {
        Toast.makeText(getApplicationContext(), "Clicked on card in cell #" + position, Toast.LENGTH_SHORT).show();
    }

    @Override
    public void onClick(@NonNull View view, int position) {
        // As of the version 7.0 update, this is no longer called. Click behavior should be defined in `OnCardClick`.
    }

    @Override
    public void onLongClick(@NonNull View view, int position) {
        Toast.makeText(getApplicationContext(), "Long-clicked on cell #" + position, Toast.LENGTH_SHORT).show();
    }
};
timeline.setClickListener(listener);

Populating the Timeline

The recommended approach for populating the timeline is through utilizing the TimelineCellData structure. The TimelineCellData holds all the same fields as TimelineCellView as listed above. All of the fields are optional, but it is recommended to at least specify the state, headline, and due date.

TimelineCellData data = new TimelineCellData(getContext());
data.setState(TimelineCellView.TimelineCellState.START);
data.setHeadline(R.string.headlineText);
data.setDescription(R.string.descriptionText);
data.setAttribute(R.string.attributeText);
data.setRightAttribute(R.string.rightAttributeText);
data.setTimestampType(TimelineCellView.TimelineCellTimestampType.DATE);
data.setDateFormat("d MMM");
data.setTimeFormat("h:mm a");
data.setDayDateFormat("EEE\nd");
data.setMonthFormat("MMMM y");
data.setDateHeaderFormat("MMMM d, y");
data.setDueDate("22/10/2020", "25/10/2020");

TimelineCellView can be added to TimelineView by creating a List<TimelineCellData> and TimelineCellProvider, like so:

List<TimelineCellData> mCellDataList = new ArrayList<>(); // member variable
TimelineView timeline = new TimelineView(getContext());
TimelineCellProvider provider = new TimelineCellProvider();

createList(); // populate mCellDataList with cell data
provider.setCellList(getContext(), mCellDataList);
timeline.setAdapter(provider);

Similarly, TimelinePreviewCellView can be added to TimelinePreviewView, except without the need for a TimelineCellProvider:

List<TimelineCellData> mCellDataList = new ArrayList<>(); // member variable
TimelinePreviewView timeline = new TimelinePreviewView(getContext());

createList(); // populate mCellDataList with cell data
timeline.setCellList(getContext(), mCellDataList);

The Timeline will automatically order the cells by due date, creating TODAY, MONTH, and other cells as needed. The Timeline can be updated at any time by calling setCellList(Context, List) with an updated List.

Add Event

The Timeline is able to automatically create a cell with the ADD state, if the current day has no events, by telling the TimelineCellProvider to do so:

TimelineCellProvider provider = new TimelineCellProvider();
provider.setShouldAddCreateCell(true);

Note

setShouldAddCreateCell(true) should be called before setCellList(Context, List) for the Timeline to properly create this cell.

Timeline View Add Event
Cell for Adding an Event

This cell should have its behavior to add event data defined in the TimelineItemTouchListener.TimelineItemClickListener:

TimelineItemTouchListener.TimelineItemClickListener listener = new TimelineItemTouchListener.TimelineItemClickListener() {
    @Override
    public void onCardClick(@NonNull View view, int position) {
        if (((TimelineCellView)view).getState() == TimelineCellView.TimelineCellState.ADD) {
            // behavior to add event data
        } else {
            // normal click behavior
        }
    }

    @Override
    public void onClick(@NonNull View view, int position) {
        // As of the version 7.0 update, this is no longer called. Click behavior should be defined in `OnCardClick`.
    }

    @Override
    public void onLongClick(@NonNull View view, int position) {
        Toast.makeText(getApplicationContext(), "Long-clicked on cell #" + position, Toast.LENGTH_SHORT).show();
    }
};

Loading

Upon loading TimelineView initially, the Timeline will display the latest items, starting with the current day at the top. Past items can be seen by scrolling upwards.

If there is data that still needs to be loaded, the current cells can be displayed along with a loading indicator at the bottom by passing in the current list of cell data and telling the TimelineCellProvider that more are loading:

List<TimelineCellData> mCellDataList = new ArrayList<>(); // member variable
TimelineView timeline = new TimelineView(getContext());
TimelineCellProvider provider = new TimelineCellProvider();

createList(); // populate mCellDataList with loaded cell data
provider.setIsLoading(true);
provider.setCellList(getContext(), mCellDataList);
timeline.setAdapter(provider);
Timeline Loading
Timeline View Loading

The Timeline can be updated at any time by calling setCellList(Context, List) with an updated List, and setIsLoading(false) should be called when all the data is loaded.

Note

setIsLoading(boolean) should be called before setCellList(Context, List) for the Timeline to reflect any changes to the state of the loading indicator.

If there are no cell data in the list passed to TimelineCellProvider or if no TimelineCellProvider has been set, then a customizable empty state will be displayed.

timeline.setEmptyDrawable(R.drawable.ic_event_note_24dp);
timeline.setEmptyHeadline(R.string.emptyHeadlineText);
timeline.setEmptyDescription(R.string.emptyDescriptionText);
Timeline Empty State
Empty Timeline View

Customization

For further customization of the cells after they have been ordered, it is possible to override TimelineCellProvider's onBindView(TimelineCellView, int, int) method to handle special cases or access methods only available to TimelineCellView.

TimelineCellProvider provider = new TimelineCellProvider() {
    @Override
    public void onBindView(@NonNull TimelineCellView view, int position, int viewType) {
        super.onBindView(view, position, viewType);
        if (position - 1 > 0 && mOrderedCellDataList.get(position - 1).getCellType() == TimelineCellView.TimelineCellType.MARKER) {
            view.setHeadline(R.string.firstEventOfMonthText);
            view.setHeadlineTextAppearance(R.style.firstEventOfMonthStyle);
            view.setTodayLineColor(R.color.todayLineColor);
            view.setStartLine(R.color.startColor);
            view.setEndLine(R.color.endColor);
            view.setLineSize(R.dimen.lineSize);
            view.setLinePadding(R.dimen.linePadding);
        }
    }
};

Last update: June 23, 2023