Skip to content

Object Header

Object Header is used in the object details floor plan. The recommended approach is to bind ObjectHeader together with Toolbar via a seamless background (no shadow in between). While the Toolbar stays on the top, ObjectHeader can scroll underneath the Toolbar.

Anatomy

An Object Header consists of an image, object name (headline, sub headline), attribute (stack status and KPI status), additional information (tags, footnote, body, label-items, inline statuses, description), and KPI detail view (on the second tab).

Object Header Structure for Page 1 on tablet and mobile:

Object Header Anatomy

Object Header Structure for Page 2 on tablet and mobile:

Object Header Anatomy

Example

Here is an example of an Object Header on a tablet. The content of the Object Header may split into multiple pages if a KPI (Key Performance Indicator) or chart is provided:

Object Header Example

Page 2:

Object Header Example

Object Header on a phone:

Object Header Phone Example

Usage

Object Header is used in the object details floor plan. The recommended approach is to bind ObjectHeader together with Toolbar via a seamless background (no shadow in between). While the Toolbar stays on the top, ObjectHeader can scroll underneath the Toolbar.

Construction

Object Header can be created either by the constructor in code or by declaring an ObjectHeader element in XML like this:

    <com.sap.cloud.mobile.fiori.object.ObjectHeader
        android:id="@+id/objectHeader"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_marginTop="?attr/actionBarSize"
        android:elevation="4dp"
        app:body="@string/object_header_body"
        app:description="@string/object_header_description"
        app:detailImage="@drawable/object_placeholder"
        app:detailImageDescription="@string/object_header_image_desc"
        app:footnote="@string/object_header_footnote"
        app:headline="@string/object_header_headline"
        app:subheadline="@string/object_header_subheadline">
    </com.sap.cloud.mobile.fiori.object.ObjectHeader>

The above XML declaration creates an ObjectHeader with the following attributes:

  • android:layout_marginTop="?attr/actionBarSize" This sets the margin top to be the action bar height. A trick to place the Object Header under the toolbar with the desired shadow and scrolling behavior.
  • android:elevation="4dp" Elevates the Object Header.
  • app:body="@string/object_header_body" Sets the body text.

Fields

Image

An image provides visual representation of the object and is highly recommended.

mObjectHeader.setDetailImage(R.drawable.object_placeholder);

Headline

The headline/title is the main area for text content. The headline is the only mandatory content for ObjectHeader. Headline can be specified by:

mObjectHeader.setHeadline(obj.getHeadline());

Sub Headline

The sub headline is displayed under the headline and provides additional information.

mObjectHeader.setSubheadline(obj.getSubheadline());

Tags

Tags are usually system-generated and may be used to indicate categories, types, or statuses. They use a different visual representation than plain text, and function as independent bits of information. There can be a maximum of 99 tags displayed in the header. If more than 99 are required, the information should be placed in the content area instead .

For example:

mObjectHeader.setTag(R.string.object_header_tag1, 0);
mObjectHeader.setTag(R.string.object_header_tag2, 1);
mObjectHeader.setTag(R.string.object_header_tag3, 2);

XML example:

<com.sap.cloud.mobile.fiori.common.Tag
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:text="@string/object_header_tag1"
    app:layout_header_group="TAG" />

<com.sap.cloud.mobile.fiori.common.Tag
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:text="@string/object_header_tag2"
    app:layout_header_group="TAG" />

<com.sap.cloud.mobile.fiori.common.Tag
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:text="@string/object_header_tag3"
    app:layout_header_group="TAG" />

Tip

app:layout_header_group="TAG" assigns the view to the "TAG" group. Tag is a simple customized TextView that comes with the SDK. You could also use any other "chip" components.

Label Items

Label Items are similar to tags in that they show a short text, however, unlike tags, Label Items are not contained in a Chip and they support a leading or trailing icon.

Java example of adding three Label Items to the Object Header:

mObjectHeader.setLabelItem(getResources().getString(R.string.object_header_label0), 0, R.drawable.ic_icon0, true);
mObjectHeader.setLabelItem(getResources().getString(R.string.object_header_label1), 1, 0, false);
mObjectHeader.setLabelItem(getResources().getString(R.string.object_header_label2), 2, R.drawable.ic_icon2, false);

Note that the fourth parameter is a Boolean insertAtStart that describes whether the icon should be at the start of the text. The following is an XML example:

<TextView
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:text="@string/object_header_label0"
    android:drawableStart="@drawable/ic_icon0"
    app:layout_header_group="LABEL"/>

<TextView
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:text="@string/object_header_label1"
    app:layout_header_group="LABEL"/>

<TextView
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:text="@string/object_header_label2"
    android:drawableEnd="@drawable/ic_icon2"
    app:layout_header_group="LABEL"/>

Body

The body is displayed under the sub headline and provides additional information.

cell.setBody(obj.getBody());

Footnote

The footnote is displayed under the body and provides additional information.

cell.setFootnote(obj.getFootnote());

Statuses

Up to two statuses can be displayed, with three layout options: stacked vertically (at the top corner of the screen), inline (below the tags), and cross-wise layout where one status is at the top corner of the screen and the other status is inline below the tags. A status can have both an icon and a text.

Stacked Status
cell.setStatusColor(BaseObjectHeaderActivity.sSapUiNegativeText, 0);
cell.setStatus(R.drawable.ic_error, 0, statusDescId);
cell.setStatusLabel(getResources().getString(R.string.error), 0);

//add a second status
cell.setStatusColor(BaseObjectHeaderActivity.sSapUiPositiveText, 1);
cell.setStatus(R.drawable.ic_positive, 1, statusDescId);
cell.setStatusLabel(getResources().getString(R.string.ok), 1);
Inline Status
cell.setStatusStackedLayout(false);
cell.setStatusInlineLayout(true);
cell.setStatusColor(BaseObjectHeaderActivity.sSapUiNegativeText, 0);
cell.setStatus(R.drawable.ic_error, 0, statusDescId);
cell.setStatusLabel(getResources().getString(R.string.error), 0);
Crosswise Status
// Both stack and inline layouts have to be set to true
cell.setStatusStackedLayout(true);
cell.setStatusInlineLayout(true);
cell.setStatusColor(BaseObjectHeaderActivity.sSapUiNegativeText, 0);
cell.setStatus(R.drawable.ic_error, 0, statusDescId);
cell.setStatusLabel(getResources().getString(R.string.error), 0);

To set the layout mode in XML, add the statusLayout attribute in the Object Header tag. The statusLayout attribute may take one of three values (stack, inline, crosswise). In this XML example, the Object Header is using a crosswise layout:

<com.sap.cloud.mobile.fiori.object.ObjectHeader
    android:id="@+id/objectHeader"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:layout_marginTop="?attr/actionBarSize"
    android:elevation="4dp"
    app:statusLayout="crosswise">
    <ImageView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:src="@drawable/ic_warning_black_24dp"
        app:tint="@color/sap_ui_negative_semantic_color"
        android:contentDescription="@string/error"
        app:layout_header_group="STATUS" />
    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="@string/object_header_status"
        android:textColor="@color/sap_ui_negative_semantic_color"
        app:layout_header_group="STATUS_LABEL" />
    <ImageView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:src="@drawable/ic_positive"
        app:tint="@color/sap_ui_positive_semantic_color"
        android:contentDescription="@string/ok"
        app:layout_header_group="STATUS" />
    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="@string/ok"
        android:textColor="@color/sap_ui_positive_semantic_color"
        app:layout_header_group="STATUS_LABEL" />
</com.sap.cloud.mobile.fiori.object.ObjectHeader>

KPI

This could be any View or ViewGroup for you to plug into ObjectHeader. It's usually some analytics information, thus the name KPI (Key Performance Index).

View analyticsView = View.inflate(ObjectHeaderActivity.this,
        R.layout.content_object_header_detail, null);
configureDetailText(analyticsView);
mObjectHeader.setDetailView(analyticsView);
app:layout_header_group="DETAIL"

Status KPI

There is now support for an additional KPI on the first page of the Object Header located at the top corner of the screen.

It is important to note that if this KPI is enabled it will take precedence over the statuses (if they are also at the top corner of the Object Header). As a consequence, the statuses will be moved over inline (under the tags). A subclass of KpiView named KpiItemView has been created to support this. Progress bars are currently not supported in this subclass.

//KpiItemView is a subclass of KpiView
KpiItemView kpiItem = new KpiItemView(context);
kpiItem.setMetric("100");
kpiItem.setRightUnit("k");
cell.setKpiStatusView(kpiItem);

Description

This is typically a longer string of text than that displayed in the title content. The description is displayed at the bottom of the Object Header and can consist of multiple lines.

mObjectHeader.setDescription(obj.getDescription());

Tip

The only difference between this and ObjectCell is that the app:layout_header_group attribute is used.

Orientation Listener

On tablets, the layout of Object Header depends on the orientation. Most of the work is handled in the initialization of Object Header. In the case where Object Header is not reinitialized upon orientation change, an OrientationEventListener should be attached like this:

mObjectHeader.setShouldAttachOrientationListener(true);

This can also be set in XML like this:

    <com.sap.cloud.mobile.fiori.object.ObjectHeader
        android:id="@+id/objectHeader"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_marginTop="?attr/actionBarSize"
        android:elevation="4dp"
        app:shouldAttachOrientationListener="true">
    </com.sap.cloud.mobile.fiori.object.ObjectHeader>

Toolbar Connection

To get a seamless connection between Toolbar and ObjectHeader, some tweaks must be made to Android AppBarLayout, as follows:

<?xml version="1.0" encoding="utf-8"?>
<android.support.design.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/main_content"
    android:fitsSystemWindows="true"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <!--appbar_always_elevated makes sure AppBarLayout always has 4 dp elevation. By default it's 0 dp.-->
    <android.support.design.widget.AppBarLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:stateListAnimator="@drawable/appbar_always_elevated"
        android:background="?attr/colorPrimary">

        <!--Setting titleEnabled and expandedTitleTextAppearance to get rid of title animation-->
        <android.support.design.widget.CollapsingToolbarLayout
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            app:expandedTitleTextAppearance="@style/TextAppearance.AppCompat.Title"
            app:layout_scrollFlags="scroll|enterAlways|exitUntilCollapsed"
            app:titleEnabled="false">

            <!--layout_marginTop must be the toolbar height. ObjectHeader and Toolbar are both
            elevated to 4 dp so there's no shadow between them.-->
            <com.sap.cloud.mobile.fiori.object.ObjectHeader
                android:id="@+id/objectHeader"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:layout_marginTop="?attr/actionBarSize"
                android:elevation="4dp"
                tools:layout_editor_absoluteY="8dp">
                ...
            </com.sap.cloud.mobile.fiori.object.ObjectHeader>

            <android.support.v7.widget.Toolbar
                android:id="@+id/toolbar"
                android:layout_width="match_parent"
                android:layout_height="?attr/actionBarSize"
                android:elevation="4dp"
                android:background="?attr/colorPrimary"
                app:layout_collapseMode="pin"
                app:theme="@style/AppTheme.AppBarOverlay"
                app:popupTheme="@style/AppTheme.PopupOverlay"/>
        </android.support.design.widget.CollapsingToolbarLayout>
    </android.support.design.widget.AppBarLayout>

    <!--layout_behavior must be used together with AppBarLayout to achieve desired scrolling effect.-->
    <android.support.v4.widget.NestedScrollView
        android:id="@+id/scrollView"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        app:layout_behavior="@string/appbar_scrolling_view_behavior">

        ...
    </android.support.v4.widget.NestedScrollView>
</android.support.design.widget.CoordinatorLayout>

And the appbar_always_elevated state list is defined as:

<selector xmlns:android="http://schemas.android.com/apk/res/android">
    <item>
        <objectAnimator android:propertyName="elevation"
            android:valueTo="4dp"
            android:valueType="floatType"
            android:duration="1"/>
    </item>
</selector>

Some things to consider:

  • AppBarLayout is always elevated.
  • Title transition in CollapsingToolbarLayout should be disabled.
  • android:layout_marginTop="?attr/actionBarSize" on ObjectHeader to make sure they do not overlap when not scrolled.

Style

For further information on style, refer to the Object Cell style guide. The differences are:

  • The style reference in FioriTheme becomes objectHeaderStyle.
  • The default style is called ObjectHeader.
  • The text appearances are called TextAppearance.Fiori.ObjectHeader.Body.

API Reference

See ObjectHeader


Last update: June 23, 2023