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 Structure for Page 2 on tablet and mobile:
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:
Page 2:
Object Header on a phone:
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"
onObjectHeader
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
becomesobjectHeaderStyle
. - The default style is called
ObjectHeader
. - The text appearances are called
TextAppearance.Fiori.ObjectHeader.Body
.
API Reference¶
See ObjectHeader