Grid Table Row¶
A grid table is a range of labeled columns and rows used to present numbers, text, or even images. Generally, grid tables are a grid layout of columns and rows. Grid tables are available only on regular screen sizes. On compact screen sizes, the data is displayed as object cells.
Example¶
A GridTableRow
consists of a collection of columns, either image or text. When GridTableRow
is used as the table header, only text should used as the columns.
Here is an example of GridTableRow
s on a tablet:
When table content is scrolled, table header would better stay on the top and preferably raise the elevation:
Usage¶
GridTableRow
can be used inside a RecyclerView
, ListView
or other ViewGroups
. The example code below will assume the parent view is RecyclerView
. GridTableRow
is extended from ConstraintLayout
and adds guidelines automatically when you add columns.
Construction¶
GridTableRow
can be created either by the constructor in code or by declaring an GridTableRow
element in XML like this:
<com.sap.cloud.mobile.fiori.object.GridTableRow
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_height="@dimen/grid_table_row_height_header"
android:layout_width="match_parent"
android:background="@color/sap_ui_list_header_background"
app:layout_optimizationLevel="standard"
app:textLines="1"
app:isHeader="true">
</com.sap.cloud.mobile.fiori.object.GridTableRow>
Then the XML can be inflated in a RecyclerView.Adapter
.
public ViewHolder onCreateViewHolder(
ViewGroup parent, int viewType) {
Context context = parent.getContext();
LayoutInflater inflater = LayoutInflater.from(context);
if (viewType == HEADER_TYPE){
GridTableRow view = (GridTableRow) inflater.inflate(R.layout.grid_table_header, parent,
false);
return new GridTableRecyclerAdapter.HeaderViewHolder(view);
}else{
GridTableRow view = (GridTableRow) inflater.inflate(mObjectCellSpec.getLayoutId(), parent,
false);
return new GridTableRecyclerAdapter.RowViewHolder(view);
}
}
The above XML declaration creates an GridTableRow
with the following attributes:
app:textLines="1"
1 line of text is allowed, because this example is creating a table header. If it's a data row, at most 2 lines of text is allowed.app:layout_optimizationLevel="standard"
StandardContraintLayout
attribute, please check Android documentation for details.app:isHeader="true"
This is a table header. Font for header will be applied.android:background="@color/sap_ui_list_header_background"
Specify a background color so that it's opaque and it'll hide the content that scrolls underneath it.
Fields¶
Columns¶
Columns can be added either in XML or code.
<?xml version="1.0" encoding="utf-8"?>
<com.sap.cloud.mobile.fiori.object.GridTableRow
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_height="@dimen/grid_table_row_height_2lines"
android:layout_width="match_parent"
app:layout_optimizationLevel="standard"
app:textLines="2">
<ImageView
android:id="@id/row_image"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:layout_column="0"
app:layout_columnWidth="88"
android:contentDescription="@string/avatar"/>
<TextView
android:id="@id/row_headline"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textColor="@color/sap_ui_base_text"
app:layout_column="1"
app:layout_columnWidth=".20"/>
<TextView
android:id="@id/row_sub_headline"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textColor="@color/sap_ui_base_text"
app:layout_column="2"
app:layout_columnWidth="150"/>
<TextView
android:id="@id/row_description"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textColor="@color/sap_ui_base_text"
app:layout_column="3"
app:layout_columnWidth="-1"/>
<TextView
android:id="@id/row_price"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textColor="@color/sap_ui_base_text"
android:gravity="end"
app:layout_column="4"
app:layout_columnWidth="150"/>
<ImageView
android:id="@id/row_status"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:layout_column="5"
app:layout_columnWidth="68"
app:layout_constraintVertical_bias="0"
android:contentDescription="@string/warning"/>
</com.sap.cloud.mobile.fiori.object.GridTableRow>
For each child view, column index and column width can be specified.
app:layout_column="0"
This is the Nth column.app:layout_columnWidth="88"
The column width is 88 dp. Since the recommended image size is 40 dp, and left/right padding for each column is 24 dp, the total width becomes 88 dp.app:layout_columnWidth="68"
This is for a small icon of 20 dp. 20 + 24 + 24 = 68.app:layout_columnWidth=".20"
This column will be 20% of the whole width.app:layout_columnWidth="-1"
This column will use all the remaining width. There can only be one such auto-size column.android:gravity="end"
This column should be end aligned. This should be used for numbers, dates, and currencies, etc.app:layout_constraintVertical_bias="0"
This column should be top aligned. This attribute comes from the parent class ofGridTableRow
:ConstraintLayout
, whose powerful layout mechanism can be leveraged.
public ViewHolder onCreateViewHolder(
ViewGroup parent, int viewType) {
Context context = parent.getContext();
LayoutInflater inflater = LayoutInflater.from(context);
//both header and content are using GridTableRow
GridTableRow view = (GridTableRow) inflater.inflate(mObjectCellSpec.getLayoutId(), parent,
false);
//image(""), headline, sub headline, description, price, status icon("")
view.setColumnWidths(88, 0.2F, 150, -1, 150, 68);
if (viewType == HEADER_TYPE){
view.setId(R.id.grid_header_row);
view.setHeader(true);
view.setBackgroundColor(sHeaderBackgroundColor);
view.setLines(1);
TextView cImage = new TextView(context);
cImage.setId(R.id.row_image);
cImage.setText("");//no space to show header
TextView cHeadline = new TextView(context);
cHeadline.setId(R.id.row_headline);
cHeadline.setText(R.string.grid_table_column_headline);
cHeadline.setTextColor(sHeaderColor);
TextView cSubHeadline = new TextView(context);
cSubHeadline.setId(R.id.row_sub_headline);
cSubHeadline.setText(R.string.grid_table_column_sub_headline);
cSubHeadline.setTextColor(sHeaderColor);
TextView cDescription = new TextView(context);
cDescription.setId(R.id.row_description);
cDescription.setText(R.string.grid_table_column_description);
cDescription.setTextColor(sHeaderColor);
TextView cPrice = new TextView(context);
cPrice.setId(R.id.row_price);
cPrice.setText(R.string.grid_table_column_price);
cPrice.setGravity(Gravity.END);
cPrice.setTextColor(sHeaderColor);
TextView cStatus = new TextView(context);
cStatus.setId(R.id.row_status);
cStatus.setText("");
view.setColumns(cImage, cHeadline, cSubHeadline, cDescription, cPrice, cStatus);
return new HeaderViewHolder(view);
}else{
view.setLines(2);
ImageView cImage = new ImageView(context);
cImage.setId(R.id.row_image);
TextView cHeadline = new TextView(context);
cHeadline.setId(R.id.row_headline);
cHeadline.setTextColor(sDataColumnColor);
TextView cSubHeadline = new TextView(context);
cSubHeadline.setId(R.id.row_sub_headline);
cSubHeadline.setTextColor(sDataColumnColor);
TextView cDescription = new TextView(context);
cDescription.setId(R.id.row_description);
cDescription.setTextColor(sDataColumnColor);
TextView cPrice = new TextView(context);
cPrice.setId(R.id.row_price);
cPrice.setGravity(Gravity.END);
cPrice.setTextColor(sDataColumnColor);
ImageView cStatus = new ImageView(context);
cStatus.setId(R.id.row_status);
view.setColumns(cImage, cHeadline, cSubHeadline, cDescription, cPrice, cStatus);
//layout params will be created after setColumns
GridTableRow.LayoutParams layoutParams = (GridTableRow.LayoutParams)cStatus.getLayoutParams();
//top align
layoutParams.verticalBias = 0.0F;
return new RowViewHolder(view);
}
}
In java code, column width can be specified as:
view.setColumnWidths(88, 0.2F, 150, -1, 150, 68);
Which sets 6 columns with these widths respectively: 88 dp, 20%, 150 dp, auto-size, 150 dp, and 68 dp.
If you have some columns with fixed width, and you want to use percentage to arrange the rest of the columns, setPercentageOutOfRemainingWidth(true)
can be used. E.g.:
view.setColumnWidths(0.5F, 0.5F, 68);
In this case, the last column uses 68 dp, while the first and second columns use half of the remaining space respectively.
After all the columns are created, set them to GridTableRow
with setColumns
.
Style¶
GridTableRow
does not have predefined style for itself, but by default it does use specific font sizes for it's text columns depending on whether its a header or content. To use your own text appearance, call setUseDefaultTextSize(false)
and set text appearance in TextView
.
Tip
Although GridTableRow
does not enforce the ImageView
position, it's a good practice to put the primary image on the first column with 40 dp size.
Sticky Header¶
GridTableRow
can be used either as a header or data row. To make the header stay on the top during scroll, third party libraries can be used. One of the library is Sticky Header. In essence, there are only 2 things to be done in the app:
- Let the
RecyclerView.Adapter
implementStickyHeaders
andStickyHeaders.ViewSetup
, and determines which position is header and configure the header view when necessary. It could be as simple as:
@Override
public boolean isStickyHeader(int position) {
return position == 0;//use view holder type if there are multiple headers
}
@Override
public void setupStickyHeaderView(View stickyHeader) {
stickyHeader.setTranslationZ(stuckHeaderElevation);
}
- Use
StickyHeadersLinearLayoutManager
with yourRecyclerView
.
mRecyclerView.setLayoutManager(new StickyHeadersLinearLayoutManager<GridTableRecyclerAdapter>(this));