Android layout - How to implement a fixed/freezed header and column
I would like to create a table-like view that contains a large number of columns (7-10) while the headers row is always visible (even when scrolling down) and the first column also always visible while scrolling horizontally.
Tried to put a list view inside an HorizontalScrollView which let me display a list with horizontal and vertical scrolling but no static column/header. I am trying to avoid using multiple views and sync between them while the user scrolls.
Later on I will h开发者_开发技巧ave to control events inside the view like row/columns clicks, so something with a custom adapter should be used.
any ideas?
I would go with TableLayout
populated by TableRow
's.
The following code demonstrates how to achieve that.
package com.test;
import android.app.Activity;
import android.graphics.Color;
import android.os.Bundle;
import android.view.Gravity;
import android.widget.TableLayout;
import android.widget.TableRow;
import android.widget.TableRow.LayoutParams;
import android.widget.TextView;
public class TableLayoutTest extends Activity {
/** Called when the activity is first created. */
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.table_layout);
TableRow.LayoutParams wrapWrapTableRowParams = new TableRow.LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);
int[] fixedColumnWidths = new int[]{20, 20, 20, 20, 20};
int[] scrollableColumnWidths = new int[]{20, 20, 20, 30, 30};
int fixedRowHeight = 50;
int fixedHeaderHeight = 60;
TableRow row = new TableRow(this);
//header (fixed vertically)
TableLayout header = (TableLayout) findViewById(R.id.table_header);
row.setLayoutParams(wrapWrapTableRowParams);
row.setGravity(Gravity.CENTER);
row.setBackgroundColor(Color.YELLOW);
row.addView(makeTableRowWithText("col 1", fixedColumnWidths[0], fixedHeaderHeight));
row.addView(makeTableRowWithText("col 2", fixedColumnWidths[1], fixedHeaderHeight));
row.addView(makeTableRowWithText("col 3", fixedColumnWidths[2], fixedHeaderHeight));
row.addView(makeTableRowWithText("col 4", fixedColumnWidths[3], fixedHeaderHeight));
row.addView(makeTableRowWithText("col 5", fixedColumnWidths[4], fixedHeaderHeight));
header.addView(row);
//header (fixed horizontally)
TableLayout fixedColumn = (TableLayout) findViewById(R.id.fixed_column);
//rest of the table (within a scroll view)
TableLayout scrollablePart = (TableLayout) findViewById(R.id.scrollable_part);
for(int i = 0; i < 10; i++) {
TextView fixedView = makeTableRowWithText("row number " + i, scrollableColumnWidths[0], fixedRowHeight);
fixedView.setBackgroundColor(Color.BLUE);
fixedColumn.addView(fixedView);
row = new TableRow(this);
row.setLayoutParams(wrapWrapTableRowParams);
row.setGravity(Gravity.CENTER);
row.setBackgroundColor(Color.WHITE);
row.addView(makeTableRowWithText("value 2", scrollableColumnWidths[1], fixedRowHeight));
row.addView(makeTableRowWithText("value 3", scrollableColumnWidths[2], fixedRowHeight));
row.addView(makeTableRowWithText("value 4", scrollableColumnWidths[3], fixedRowHeight));
row.addView(makeTableRowWithText("value 5", scrollableColumnWidths[4], fixedRowHeight));
scrollablePart.addView(row);
}
}
//util method
private TextView recyclableTextView;
public TextView makeTableRowWithText(String text, int widthInPercentOfScreenWidth, int fixedHeightInPixels) {
int screenWidth = getResources().getDisplayMetrics().widthPixels;
recyclableTextView = new TextView(this);
recyclableTextView.setText(text);
recyclableTextView.setTextColor(Color.BLACK);
recyclableTextView.setTextSize(20);
recyclableTextView.setWidth(widthInPercentOfScreenWidth * screenWidth / 100);
recyclableTextView.setHeight(fixedHeightInPixels);
return recyclableTextView;
}
}
Header is the part that doesn't scroll vertically; that's the reason you need to set fixed width on columns. As of the first column that you don't want to scroll, you'll have to set a fixed height on rows for that purpose.
Here's the layout XML
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:gravity="center_horizontal"
android:id="@+id/fillable_area">
<TableLayout
android:id="@+id/table_header"
android:layout_width="fill_parent"
android:layout_height="wrap_content"/>
<ScrollView
android:layout_width="fill_parent"
android:layout_height="wrap_content">
<LinearLayout android:orientation="horizontal"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:gravity="center_horizontal"
android:id="@+id/fillable_area">
<TableLayout
android:id="@+id/fixed_column"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
<HorizontalScrollView
android:layout_width="fill_parent"
android:layout_height="wrap_content">
<TableLayout
android:id="@+id/scrollable_part"
android:layout_width="fill_parent"
android:layout_height="fill_parent"/>
</HorizontalScrollView>
</LinearLayout>
</ScrollView>
</LinearLayout>
And the output looks like this when just loaded
and like this when scrolled to the right and to the bottom
You can check this library that I made: https://github.com/InQBarna/TableFixHeaders
I think that it implements the widget you're looking for.
Create TableLayout that will be a header and under it place a Table itself within a ScrollView like this:
<TableLayout
android:id="@+id/tbl_header"
android:orientation="horizontal"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:divider="@drawable/table_divider"
android:showDividers="middle"
android:background="@drawable/table_header_backdround"
/>
<ScrollView android:layout_width="fill_parent"
android:layout_height="wrap_content">
<TableLayout
android:id="@+id/tbl_relesed_wake_locks"
android:orientation="horizontal"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:divider="@drawable/table_divider"
android:showDividers="middle"
android:stretchColumns="1,2"
android:background="@drawable/table_backdround"
/>
</ScrollView>
When you will populate your header with data add next code:
table.post(new Runnable() {
@Override
public void run() {
TableRow tableRow = (TableRow)table.getChildAt(0);
for(int i = 0; i < headerRow.getChildCount(); i++){
headerRow.getChildAt(i).setLayoutParams(new TableRow.LayoutParams(tableRow.getChildAt(i).getMeasuredWidth(), tableRow.getChildAt(i).getMeasuredHeight()));
}
}
});
That's it.
If wanna fix first column, you can try the following layout:
<TableLayout
android:id="@+id/tbl_header"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentLeft="true"
android:background="@drawable/cell_shape_header"
android:divider="?android:dividerHorizontal"
android:orientation="horizontal"
android:showDividers="middle">
<TableRow
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:padding="0.5dp">
<TextView
style="@style/TextViewStyle"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:text="Fragment A" />
</TableRow>
<TableRow
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:padding="0.5dp">
<TextView
style="@style/TextViewStyle"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:text="Fragment A" />
</TableRow>
<TableRow
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:padding="0.5dp">
<TextView
style="@style/TextViewStyle"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:text="Fragment A" />
</TableRow>
</TableLayout>
<HorizontalScrollView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentRight="true"
android:layout_toRightOf="@+id/tbl_header">
<TableLayout
android:id="@+id/tbl_relesed_wake_locks"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="@drawable/cell_shape_header"
android:divider="?android:dividerHorizontal"
android:orientation="horizontal"
android:showDividers="middle"
android:stretchColumns="1,2">
<TableRow
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:padding="0.5dp">
<TextView
style="@style/TextViewStyle"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:text="Fragment 01" />
<TextView
style="@style/TextViewStyle"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:text="Fragment 01" />
<TextView
style="@style/TextViewStyle"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:text="Fragment 01" />
</TableRow>
<TableRow
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:padding="0.5dp">
<TextView
style="@style/TextViewStyle"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:text="Fragment 01" />
<TextView
style="@style/TextViewStyle"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:text="Fragment 01" />
<TextView
style="@style/TextViewStyle"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:text="Fragment 01" />
</TableRow>
<TableRow
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:padding="0.5dp">
<TextView
style="@style/TextViewStyle"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:text="Fragment 01" />
<TextView
style="@style/TextViewStyle"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:text="Fragment 01" />
<TextView
style="@style/TextViewStyle"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:text="Fragment 01" />
</TableRow>
</TableLayout>
</HorizontalScrollView>
github link
Recently I came across a situation where I need first two row & first column freeze. I got this library I modified it according to my requirement & fixed some bugs. Now work smoothly.
Ten years on, and this is still amazingly difficult! Jetpack Compose now has a DataTable control, but this is not yet available for Android: Jetpack Compose: Data Tables.
I have been working on a Kotlin App for my own learning, and wanted to display a data table. I have taken the ideas from this thread, together with the linked scrolling from: Synchronise ScrollView scroll positions - android.
The full code is available on GitHub: CovidStatistics.
The table is shown in the screenshot below. You can see that the Data Table has grid lines, and scrolls in both directions. Also, it display icons on some of the cells.
My solution adds the following to those presented above in this thread:
- The data cell is defined in a layout file, not in code, which makes it easier to display complex layouts in a cell. The icons are shown randomly as an example of this.
- The column widths are automatically set after the data is added to the table, rather than having to be chosen beforehand.
I had hoped to use RecyclerViews, instead of creating rows and columns in code. I got part way towards this but just couldn't get the horizontal scroll bar to work with RecyclerView.
This is the layout code for the table fragment:
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:gravity="center_horizontal"
android:id="@+id/main_area"
android:layout_marginTop="0in"
android:layout_marginBottom="0in"
android:layout_marginLeft="0in"
android:layout_marginRight="0in"
android:background="@android:color/holo_green_dark">
<ProgressBar
android:id="@+id/progressBar1"
style="?android:attr/progressBarStyleLarge"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_centerHorizontal="true"
android:tooltipText="Loading data"
android:visibility="visible" />
<LinearLayout android:orientation="horizontal"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:gravity="center_horizontal"
android:id="@+id/header_area"
>
<!-- Top left cell, in a table of its own-->
<TableLayout
android:id="@+id/top_left_cell"
android:layout_width="wrap_content"
android:layout_height="fill_parent"
app:layout_constraintStart_toStartOf="parent"
android:paddingLeft="0in"
android:paddingRight="0in"
android:paddingTop="0in"
android:paddingBottom="0in"
/>
<!-- Column header horizontal scroll-->
<com.ant_waters.covidstatistics.ui.ObservableHorizontalScrollView
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:id="@+id/column_header_scroll"
>
<!-- Column Headers-->
<TableLayout
android:id="@+id/table_header"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
>
</TableLayout>
</com.ant_waters.covidstatistics.ui.ObservableHorizontalScrollView>
</LinearLayout>
<!-- Data area vertical scroll-->
<ScrollView
android:layout_width="fill_parent"
android:layout_height="fill_parent"
>
<LinearLayout android:orientation="horizontal"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:gravity="center_horizontal"
android:id="@+id/fillable_area"
>
<!-- Data row headers-->
<TableLayout
android:id="@+id/fixed_column"
android:layout_width="wrap_content"
android:layout_height="fill_parent"
app:layout_constraintStart_toStartOf="@+id/table_header"
android:paddingLeft="0in"
android:paddingRight="0in"
android:paddingTop="0in"
android:paddingBottom="0in"
/>
<!-- Data rows horizontal scroll-->
<com.ant_waters.covidstatistics.ui.ObservableHorizontalScrollView
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:id="@+id/data_horizontal_scroll"
>
<!-- Data rows-->
<TableLayout
android:id="@+id/scrollable_part"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:paddingLeft="0in"
android:paddingRight="0in"
android:paddingTop="0in"
android:paddingBottom="0in"
/>
</com.ant_waters.covidstatistics.ui.ObservableHorizontalScrollView>
</LinearLayout>
</ScrollView>
</LinearLayout>
These are the layout codes for other key pieces:
Header_cell:
<!--This defines the layout for a header cell in the data table-->
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:orientation="horizontal"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="@+id/cell_linear_layout"
android:layout_marginTop="0in"
android:layout_marginBottom="0in"
android:layout_marginLeft="0in"
android:layout_marginRight="0in"
>
<!-- android:gravity="center_horizontal"-->
<!-- android:background="@android:color/holo_green_dark"-->
<TextView
android:id="@+id/cell_text_view"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginStart="2dp"
android:layout_marginTop="2dp"
android:layout_marginEnd="2dp"
android:layout_marginBottom="2dp"
android:textColor="@color/black"
android:textSize="20.0sp"
android:layout_gravity="center_horizontal|center_vertical"
android:paddingStart="15sp"
android:paddingEnd="15sp"
android:paddingTop="5sp"
android:paddingBottom="5sp"
android:background="#4b8ba1"
></TextView>
</LinearLayout>
Data cell containing an icon:
<!--This defines the layout for a data cell that includes a warning icon in the data table-->
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="@+id/cell_linear_layout"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="horizontal">
<!-- This layer is needed to set the margin, as that doesn't seem to work at the top level -->
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginStart="2dp"
android:layout_marginTop="2dp"
android:layout_marginEnd="2dp"
android:layout_marginBottom="2dp"
android:background="@android:color/white"
android:orientation="horizontal">
<ImageView
android:layout_width="20dp"
android:layout_height="20dp"
android:layout_gravity="center_vertical"
android:src="@drawable/ic_baseline_warning_24" />
<TextView
android:id="@+id/cell_text_view"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal|center_vertical"
android:paddingStart="15sp"
android:paddingTop="5sp"
android:paddingEnd="15sp"
android:paddingBottom="5sp"
android:textColor="@color/black"
android:textSize="20.0sp"></TextView>
</LinearLayout>
</LinearLayout>
Header cell background:
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle">
<solid android:color="@android:color/darker_gray" />
</shape>
While the table is built it fills in a 2-d array of Views for all the cells being display.
fun displayTheDataTable(inflater: LayoutInflater)
{
if (MainViewModel.DataInitialised.value==enDataLoaded.All) {
// Display the table by creating Views for cells, headers etc.
val allCells = displayDataTable(inflater)
// Add a callback to set the column widths at the end (when onGlobalLayout is called)
val content: View = _binding!!.mainArea
content.viewTreeObserver.addOnGlobalLayoutListener(object : OnGlobalLayoutListener {
override fun onGlobalLayout() {
//Remove the observer so we don't get this callback for EVERY layout pass
content.viewTreeObserver.removeGlobalOnLayoutListener(this)
//Resize the columns to match the maximum width
setColumnWidths(allCells, fun (v: View, w: Int) {
val tv = v.findViewById<View>(com.ant_waters.covidstatistics.R.id.cell_text_view) as TextView
var lp = LayoutParams(w, LayoutParams.WRAP_CONTENT)
v.layoutParams = lp
tv.setGravity(Gravity.CENTER)
})
}
})
}
}
This is used to set the column widths at the end:
fun setColumnWidths(allCells: Array<Array<View?>>, setItemWidth: (v: View, w: Int) -> Unit)
{
val numColumns: Int = allCells[0].size
val colWidths = Array<Int>(numColumns, {0})
for (r in 0..allCells.size-1)
{
if ((allCells[r] == null) || (allCells[r][0] == null)) { continue } // Row was skipped
for (c in 0..numColumns-1)
{
val vw : View = allCells[r][c]!!
if (vw.width > colWidths[c]) { colWidths[c] = vw.width}
}
}
for (r in 0..allCells.size-1)
{
if ((allCells[r] == null) || (allCells[r][0] == null)) { continue } // Row was skipped
for (c in 0..numColumns-1)
{
val vw = allCells[r][c]!! as LinearLayout
setItemWidth(vw, colWidths[c])
}
}
}
These are the methods to build the individual cells from the "templates" defined in layout files:
fun createHeaderCellFromTemplate(inflater: LayoutInflater, text: String?): View {
val cellView: View = inflater.inflate(com.ant_waters.covidstatistics.R.layout.header_cell, null)
val tv = cellView.findViewById<View>(com.ant_waters.covidstatistics.R.id.cell_text_view) as TextView
tv.text = text
return cellView
}
fun <TRowHdr>createRowHeaderCellFromTemplate(inflater: LayoutInflater, rowHdr: TRowHdr): View {
val cellView: View = inflater.inflate(com.ant_waters.covidstatistics.R.layout.header_cell, null)
val tv = cellView.findViewById<View>(com.ant_waters.covidstatistics.R.id.cell_text_view) as TextView
if (rowHdr is Date)
{
val dt = rowHdr as Date
var formatter = SimpleDateFormat("dd/MM/yy")
tv.text = formatter.format(dt)
}
else {
tv.text = rowHdr.toString()
}
return cellView
}
fun <Tval>createDataCellFromTemplate(inflater: LayoutInflater, theVal: Tval,
showWarning: Boolean, countryName: String
): View {
var templateId = com.ant_waters.covidstatistics.R.layout.data_cell
var text = theVal.toString()
if (theVal is Double) {
val df1 = DecimalFormat("#")
val df2 = DecimalFormat("#.0")
text = getProportionalDisplayText(text.toDouble(), df1, df2)
}
if (showWarning) { templateId = com.ant_waters.covidstatistics.R.layout.warning_data_cell }
val cellView: View = inflater.inflate(templateId, null)
val tv = cellView.findViewById<View>(com.ant_waters.covidstatistics.R.id.cell_text_view) as TextView
tv.text = text
if (DataManager.CountriesByName.containsKey(countryName)) {
cellView.setOnClickListener(View.OnClickListener {
val cpf = CountryPopupFragment()
// Supply country as an argument.
val args = Bundle()
args.putString("geoId", DataManager.CountriesByName[countryName]!!.geoId)
cpf.setArguments(args)
cpf.show(requireActivity()?.getSupportFragmentManager(), "countrypopup_from_datatable")
})
}
return cellView
}
For the rest of the code see the Github repo.
I found two working examples. http://justsimpleinfo.blogspot.com/2015/04/android-scrolling-table-with-fixed.html
and
https://www.codeofaninja.com/2013/08/android-scroll-table-fixed-header-column.html (https://www.youtube.com/watch?v=VCjlcV20ftE). In the second case a warning is shown, so it can be fixed with Android - Expected Resource of type ID.
A code from the first link.
MainActivity.java
public class MainActivity extends Activity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Table table = new Table(this);
setContentView(table);
}
}
Table.java
public class Table extends LinearLayout {
public static final String PREVIOUS_ARROW = "\u2190";
public static final String NEXT_ARROW = "\u2192";
public static final int HEADER_BACKROUND_COLOR = Color.parseColor("#339999");
public static final int BODY_BACKROUND_COLOR = Color.parseColor("#99cccc");
public static String LEFT_BODY_SCROLLVIEW_TAG = "LEFT_BODY_SCROLLVIEW_TAG";
public static String RIGHT_BODY_SCROLLVIEW_TAG = "RIGHT_BODY_SCROLLVIEW_TAG";
/**
* @IS_TWO_COLUMN_HEADER = set this to true if you want two column header with span.
*/
public static final boolean IS_TWO_COLUMN_HEADER = true;
LinkedHashMap<Object, Object[]> leftHeaders = new LinkedHashMap<Object, Object[]>();
LinkedHashMap<Object, Object[]> rightHeaders = new LinkedHashMap<Object, Object[]>();
BodyTable rightTable;
BodyTable leftTable;
/**
* @leftHeaderChildrenWidht = value will be set on adjust header width to match in screen width
*/
Integer[] leftHeaderChildrenWidth ;
/**
* rightHeaderChildrenWidht = value will be set on adjust header width to match in screen width
*/
Integer[] rightHeaderChildrenWidht ;
LoadingDialog loadingDialog;
public Table(Context context) {
super(context);
this.headers();
this.properties();
this.init();
this.resizeFirstLvlHeaderHeight();
this.resizeSecondLvlHeaderHeight();
this.resizeHeaderSecondLvlWidhtToMatchInScreen();
this.leftTable.setHeaderChildrenWidth(this.leftHeaderChildrenWidth);
this.rightTable.setHeaderChildrenWidth(this.rightHeaderChildrenWidht);
this.createTestData();
this.loadData();
}
public final static String NAME = "Name";
public final static String GENDER = "Gender";
public final static String TICKET_SET_SEQUENCE = "Set Sequence";
public final static String TICKET_NUMBER = "Ticket Number";
public final static String TICKET_VALID_UNTIL = " Valid Until ";
public final static String COUNTRY_FROM = " Country From ";
public final static String COUNTRY_TO = " Country To ";
public void headers(){
leftHeaders.put("Passenger Info", new String[]{NAME,GENDER});
rightHeaders.put("Ticket Info", new String[]{TICKET_VALID_UNTIL,TICKET_NUMBER,TICKET_SET_SEQUENCE});
rightHeaders.put("Country Info", new String[]{COUNTRY_FROM,COUNTRY_TO});
}
List<Passenger> testData = new ArrayList<Table.Passenger>();
List<Passenger> dataToBeLoad = new ArrayList<Table.Passenger>();
int pagination = 20;
int totalPage = 0;
int pageNumber = 1;
public void loadData() {
// TODO Auto-generated method stub
this.dataToBeLoad = this.getDataToBeLoad();
leftTable.loadData(dataToBeLoad);
rightTable.loadData(dataToBeLoad);
this.resizeBodyChildrenHeight();
}
private void createTestData(){
for(int x = 0 ; x < 102; x++){
Passenger passenger = new Passenger();
passenger.name = "Passenger "+x;
passenger.gender = x%2 == 0 ? 'F':'M';
passenger.ticketNum = x;
passenger.setSequence = "Set "+x;
passenger.validUntil = "May 01, 2015";
passenger.countryFrom = "Country "+x;
passenger.countryTo = x%2 == 0 ? "Philippines" :"Country "+x;
testData.add(passenger);
}
this.totalPage = this.totalPage(testData, pagination);
/*this.dataToBeLoad = this.getDataToBeLoad();*/
}
private List<Passenger> getDataToBeLoad(){
List<Passenger> passengers = new ArrayList<Table.Passenger>();
int startingIndex = (pageNumber -1) * pagination;
int totalPassenger = testData.size();
//dataToBeLoad.clear();
for(int x = 0 ; x < pagination ; x++){
int index = startingIndex + x;
if(index < totalPassenger){
passengers.add(testData.get(index));
}else{
Log.e("no data","no data");
}
}
return passengers;
}
private int totalPage(List<Passenger> testData,int pagination){
int totalPage = testData.size() / pagination;
totalPage = totalPage + (testData.size() % 20 == 0 ? 0 : 1);
return totalPage;
}
private void properties(){
this.setBackgroundColor(Color.WHITE);
this.setOrientation(LinearLayout.HORIZONTAL);
}
private void init(){
this.loadingDialog = new LoadingDialog(this.getContext());
this.rightTable = new BodyTable(this.getContext(),this, rightHeaders, RIGHT_BODY_SCROLLVIEW_TAG);
this.leftTable = new BodyTable(this.getContext(),this,leftHeaders, LEFT_BODY_SCROLLVIEW_TAG);
this.addView(this.leftTable);
this.addView(this.rightTable);
}
private void resizeFirstLvlHeaderHeight(){
int rightHeaderLinearLayoutChildCount = rightTable.headerHorizontalLinearLayout.getChildCount();
int rightHeaderFirstLvlHeighestHeight = 0;
int rightHeaderFirstLvlHighestHeightIndex = 0;
for(int x = 0 ; x < rightHeaderLinearLayoutChildCount; x++){
HeaderRow row = (HeaderRow) rightTable.headerHorizontalLinearLayout.getChildAt(x);
int height = ViewSizeUtils.getViewHeight(row.firtLvlLinearLayout);
if(rightHeaderFirstLvlHeighestHeight <= height){
rightHeaderFirstLvlHeighestHeight = height;
rightHeaderFirstLvlHighestHeightIndex = x;
}
}
int leftHeaderLinearLayoutChildCount = leftTable.headerHorizontalLinearLayout.getChildCount();
int leftHeaderFirstLvlHeighestHeight = 0;
int leftHeaderFirstLvlHighestHeightIndex = 0;
for(int x = 0 ; x < leftHeaderLinearLayoutChildCount; x++){
HeaderRow row = (HeaderRow) leftTable.headerHorizontalLinearLayout.getChildAt(x);
int height = ViewSizeUtils.getViewHeight(row.firtLvlLinearLayout);
if(leftHeaderFirstLvlHeighestHeight <= height){
leftHeaderFirstLvlHeighestHeight = height;
leftHeaderFirstLvlHighestHeightIndex = x;
}
}
boolean isHighestHighInLeft = false;
if(leftHeaderFirstLvlHeighestHeight < rightHeaderFirstLvlHeighestHeight){
// apply right header height in left and right except for the index in highest height
isHighestHighInLeft = false;
}else{
isHighestHighInLeft = true;
}
for(int x = 0 ; x < rightHeaderLinearLayoutChildCount; x++){
LinearLayout firstLvlLinearLayout = ((HeaderRow) rightTable.headerHorizontalLinearLayout.getChildAt(x)).firtLvlLinearLayout;
if(isHighestHighInLeft){
LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(LayoutParams.MATCH_PARENT,leftHeaderFirstLvlHeighestHeight);
params.weight = 1;
firstLvlLinearLayout.setLayoutParams(params);
}else{
if(rightHeaderFirstLvlHeighestHeight != rightHeaderFirstLvlHighestHeightIndex){
LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(LayoutParams.MATCH_PARENT,rightHeaderFirstLvlHeighestHeight);
params.weight = 1;
firstLvlLinearLayout.setLayoutParams(params);
}
}
}
for(int x = 0 ; x < leftHeaderLinearLayoutChildCount; x++){
LinearLayout firstLvlLinearLayout = ((HeaderRow) leftTable.headerHorizontalLinearLayout.getChildAt(x)).firtLvlLinearLayout;
if(isHighestHighInLeft){
LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(LayoutParams.MATCH_PARENT,leftHeaderFirstLvlHeighestHeight);
params.weight = 1;
firstLvlLinearLayout.setLayoutParams(params);
}else{
if(leftHeaderFirstLvlHeighestHeight != leftHeaderFirstLvlHighestHeightIndex){
LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(LayoutParams.MATCH_PARENT,rightHeaderFirstLvlHeighestHeight);
params.weight = 1;
firstLvlLinearLayout.setLayoutParams(params);
}
}
}
}
private void resizeSecondLvlHeaderHeight(){
int rightHeaderLinearLayoutChildCount = rightTable.headerHorizontalLinearLayout.getChildCount();
int rightHeaderFirstLvlHeighestHeight = 0;
int rightHeaderFirstLvlHighestHeightIndex = 0;
for(int x = 0 ; x < rightHeaderLinearLayoutChildCount; x++){
HeaderRow row = (HeaderRow) rightTable.headerHorizontalLinearLayout.getChildAt(x);
int height = ViewSizeUtils.getViewHeight(row.secondLvlLinearLayout);
if(rightHeaderFirstLvlHeighestHeight <= height){
rightHeaderFirstLvlHeighestHeight = height;
rightHeaderFirstLvlHighestHeightIndex = x;
}
}
int leftHeaderLinearLayoutChildCount = leftTable.headerHorizontalLinearLayout.getChildCount();
int leftHeaderFirstLvlHeighestHeight = 0;
int leftHeaderFirstLvlHighestHeightIndex = 0;
for(int x = 0 ; x < leftHeaderLinearLayoutChildCount; x++){
HeaderRow row = (HeaderRow) leftTable.headerHorizontalLinearLayout.getChildAt(x);
int height = ViewSizeUtils.getViewHeight(row.secondLvlLinearLayout);
if(leftHeaderFirstLvlHeighestHeight <= height){
leftHeaderFirstLvlHeighestHeight = height;
leftHeaderFirstLvlHighestHeightIndex = x;
}
}
boolean isHighestHighInLeft = false;
if(leftHeaderFirstLvlHeighestHeight < rightHeaderFirstLvlHeighestHeight){
// apply right header height in left and right except for the index in highest height
isHighestHighInLeft = false;
}else{
isHighestHighInLeft = true;
}
for(int x = 0 ; x < rightHeaderLinearLayoutChildCount; x++){
LinearLayout secondLvlLinearLayout = ((HeaderRow) rightTable.headerHorizontalLinearLayout.getChildAt(x)).secondLvlLinearLayout;
if(isHighestHighInLeft){
LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(LayoutParams.MATCH_PARENT,leftHeaderFirstLvlHeighestHeight);
params.weight = 1;
secondLvlLinearLayout.setLayoutParams(params);
}else{
if(rightHeaderFirstLvlHeighestHeight != rightHeaderFirstLvlHighestHeightIndex){
LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(LayoutParams.MATCH_PARENT,rightHeaderFirstLvlHeighestHeight);
params.weight = 1;
secondLvlLinearLayout.setLayoutParams(params);
}
}
}
for(int x = 0 ; x < leftHeaderLinearLayoutChildCount; x++){
LinearLayout secondLvlLinearLayout = ((HeaderRow) leftTable.headerHorizontalLinearLayout.getChildAt(x)).secondLvlLinearLayout;
if(isHighestHighInLeft){
LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(LayoutParams.MATCH_PARENT,leftHeaderFirstLvlHeighestHeight);
params.weight = 1;
secondLvlLinearLayout.setLayoutParams(params);
}else{
if(leftHeaderFirstLvlHeighestHeight != leftHeaderFirstLvlHighestHeightIndex){
LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(LayoutParams.MATCH_PARENT,rightHeaderFirstLvlHeighestHeight);
params.weight = 1;
secondLvlLinearLayout.setLayoutParams(params);
}
}
}
}
private void resizeHeaderSecondLvlWidhtToMatchInScreen(){
int screenWidth = ScreenUtils.getScreenWidth(this.getContext());
int leftHeaderChildrenTotalWidth = this.leftSecondLvlHeaderChildrenTotalWidth();
int rightHeaderChildrenTotalWidth = this.rightHeaderChildrenTotalWidth();
int leftHeaderSecondLvlChildrenCount = this.leftSecondLvlHeaderChildrenCount();
int rightHeaderSecondLvlChildrenCount = this.rightSecondLvlHeaderChildrenCount();
float availableWidth = screenWidth - (leftHeaderChildrenTotalWidth + rightHeaderChildrenTotalWidth);
if(availableWidth <=0){
// set the header width
this.leftHeaderChildrenWidth = this.getLeftHeaderChildrenWidth();
this.rightHeaderChildrenWidht = this.getRightHeaderChildrenWidth();
return;
}
int widthForEachHeaderChild = (int) Math.ceil(availableWidth / (leftHeaderSecondLvlChildrenCount + rightHeaderSecondLvlChildrenCount));
this.addWidthForEachHeaderLeftAndRightChild(widthForEachHeaderChild);
// set the header width
this.leftHeaderChildrenWidth = this.getLeftHeaderChildrenWidth();
this.rightHeaderChildrenWidht = this.getRightHeaderChildrenWidth();
}
/**
* get children count in left header
* @return
*/
private int leftSecondLvlHeaderChildrenCount(){
int totalChildren = 0;
int leftHeaderLinearLayoutChildCount = leftTable.headerHorizontalLinearLayout.getChildCount();
for(int x = 0 ; x < leftHeaderLinearLayoutChildCount ; x++){
LinearLayout secondLvlLinearLayout = ((HeaderRow) leftTable.headerHorizontalLinearLayout.getChildAt(x)).secondLvlLinearLayout;
totalChildren += secondLvlLinearLayout.getChildCount();
}
return totalChildren;
}
/**
* get children count in right header
* @return
*/
private int rightSecondLvlHeaderChildrenCount(){
int totalChildren = 0;
int leftHeaderLinearLayoutChildCount = rightTable.headerHorizontalLinearLayout.getChildCount();
for(int x = 0 ; x < leftHeaderLinearLayoutChildCount ; x++){
LinearLayout secondLvlLinearLayout = ((HeaderRow) rightTable.headerHorizontalLinearLayout.getChildAt(x)).secondLvlLinearLayout;
totalChildren += secondLvlLinearLayout.getChildCount();
}
return totalChildren;
}
/**
* Compute total header width in left header
* @return
*/
private int leftSecondLvlHeaderChildrenTotalWidth(){
int totalWidth = 0;
int leftHeaderLinearLayoutChildCount = leftTable.headerHorizontalLinearLayout.getChildCount();
for(int x = 0 ; x < leftHeaderLinearLayoutChildCount ; x++){
LinearLayout secondLvlLinearLayout = ((HeaderRow) leftTable.headerHorizontalLinearLayout.getChildAt(x)).secondLvlLinearLayout;
int leftColumnChildrenCount = secondLvlLinearLayout.getChildCount();
for(int y = 0 ; y < leftColumnChildrenCount ; y++){
View view = secondLvlLinearLayout.getChildAt(y);
LinearLayout.LayoutParams params = (LayoutParams) view.getLayoutParams();
int width = params.width <=0 ? ViewSizeUtils.getViewWidth(view) : params.width;
totalWidth += width;
}
}
return totalWidth;
}
/**
* Compute total right header children width
* @return
*/
private int rightHeaderChildrenTotalWidth(){
int totalWidth = 0;
int leftHeaderLinearLayoutChildCount = rightTable.headerHorizontalLinearLayout.getChildCount();
for(int x = 0 ; x < leftHeaderLinearLayoutChildCount ; x++){
LinearLayout secondLvlLinearLayout = ((HeaderRow) rightTable.headerHorizontalLinearLayout.getChildAt(x)).secondLvlLinearLayout;
int leftColumnChildrenCount = secondLvlLinearLayout.getChildCount();
for(int y = 0 ; y < leftColumnChildrenCount ; y++){
View view = secondLvlLinearLayout.getChildAt(y);
LinearLayout.LayoutParams params = (LayoutParams) view.getLayoutParams();
int width = params.width <=0 ? ViewSizeUtils.getViewWidth(view) : params.width;
totalWidth += width;
}
}
return totalWidth;
}
/**
* Add width in left and right children width if needed to match screen width.
* @param widthToBeAdded
*/
private void addWidthForEachHeaderLeftAndRightChild(int widthToBeAdded){
int leftHeaderColumnCount = leftTable.headerHorizontalLinearLayout.getChildCount();
int rightHeaderColumnCount = rightTable.headerHorizontalLinearLayout.getChildCount();
for(int x = 0 ; x < leftHeaderColumnCount ; x++){
HeaderRow tableRow = (HeaderRow) leftTable.headerHorizontalLinearLayout.getChildAt(x);
int headerRowChildCount = tableRow.secondLvlLinearLayout.getChildCount();
for(int y = 0 ; y < headerRowChildCount ; y++){
View view = tableRow.secondLvlLinearLayout.getChildAt(y);
LinearLayout.LayoutParams params = (LayoutParams) view.getLayoutParams();
int width = params.width <=0 ? ViewSizeUtils.getViewWidth(view) + widthToBeAdded : params.width +widthToBeAdded;
params.width = width;
}
}
for(int x = 0 ; x < rightHeaderColumnCount ; x++){
HeaderRow tableRow = (HeaderRow) rightTable.headerHorizontalLinearLayout.getChildAt(x);
int headerRowChildCount = tableRow.secondLvlLinearLayout.getChildCount();
for(int y = 0 ; y < headerRowChildCount ; y++){
View view = tableRow.secondLvlLinearLayout.getChildAt(y);
LinearLayout.LayoutParams params = (LayoutParams) view.getLayoutParams();
int width = params.width <=0 ? ViewSizeUtils.getViewWidth(view) + widthToBeAdded : params.width +widthToBeAdded;
params.width = width;
}
}
}
/**
* Get each width of left header child
* @return
*/
private Integer[] getLeftHeaderChildrenWidth(){
List<Integer> headerChildrenWidth = new ArrayList<Integer>();
int leftHeaderColumnCount = leftTable.headerHorizontalLinearLayout.getChildCount();
for(int x = 0 ; x < leftHeaderColumnCount ; x++){
HeaderRow tableRow = (HeaderRow) leftTable.headerHorizontalLinearLayout.getChildAt(x);
int headerRowChildCount = tableRow.secondLvlLinearLayout.getChildCount();
for(int y = 0 ; y < headerRowChildCount ; y++){
View view = tableRow.secondLvlLinearLayout.getChildAt(y);
LinearLayout.LayoutParams params = (LayoutParams) view.getLayoutParams();
int width = params.width <=0 ? ViewSizeUtils.getViewWidth(view): params.width ;
headerChildrenWidth.add(width);
}
}
return headerChildrenWidth.toArray(new Integer[headerChildrenWidth.size()]);
}
/**
* Get each width of right header child
* @return
*/
private Integer[] getRightHeaderChildrenWidth(){
List<Integer> headerChildrenWidth = new ArrayList<Integer>();
int rightHeaderColumnCount = rightTable.headerHorizontalLinearLayout.getChildCount();
for(int x = 0 ; x < rightHeaderColumnCount ; x++){
HeaderRow tableRow = (HeaderRow) rightTable.headerHorizontalLinearLayout.getChildAt(x);
int headerRowChildCount = tableRow.secondLvlLinearLayout.getChildCount();
for(int y = 0 ; y < headerRowChildCount ; y++){
View view = tableRow.secondLvlLinearLayout.getChildAt(y);
LinearLayout.LayoutParams params = (LayoutParams) view.getLayoutParams();
int width = params.width <=0 ? ViewSizeUtils.getViewWidth(view) : params.width ;
headerChildrenWidth.add(width);
}
}
return headerChildrenWidth.toArray(new Integer[headerChildrenWidth.size()]);
}
/**
* Resize each body column to match each other
*/
private void resizeBodyChildrenHeight(){
int leftHeaderFirstLvlHighestHeight = 0;
for(LinearLayout lin : leftTable.bodyLinearLayoutTempMem){
int childCount = lin.getChildCount();
for(int x = 0 ; x < childCount; x++){
int width = ViewSizeUtils.getViewHeight(lin.getChildAt(x));
if(leftHeaderFirstLvlHighestHeight < width){
leftHeaderFirstLvlHighestHeight = width;
}
}
}
int rightHeaderFirstLvlHighestHeight = 0;
//int rightHeaderFirstLvlHighestHeightIndex = 0;
for(LinearLayout lin : rightTable.bodyLinearLayoutTempMem){
int childCount = lin.getChildCount();
for(int x = 0 ; x < childCount; x++){
int width = ViewSizeUtils.getViewHeight(lin.getChildAt(x));
if(rightHeaderFirstLvlHighestHeight < width){
rightHeaderFirstLvlHighestHeight = width;
//rightHeaderFirstLvlHighestHeightIndex = x;
}
}
}
boolean isHighestHighInLeft = leftHeaderFirstLvlHighestHeight > rightHeaderFirstLvlHighestHeight;
for(LinearLayout lin : leftTable.bodyLinearLayoutTempMem){
int childCount = lin.getChildCount();
for(int x = 0 ; x < childCount; x++){
LinearLayout.LayoutParams params = (LayoutParams) lin.getChildAt(x).getLayoutParams();
params.height = isHighestHighInLeft ? leftHeaderFirstLvlHighestHeight : rightHeaderFirstLvlHighestHeight;
}
}
for(LinearLayout lin : rightTable.bodyLinearLayoutTempMem){
int childCount = lin.getChildCount();
for(int x = 0 ; x < childCount; x++){
LinearLayout.LayoutParams params = (LayoutParams) lin.getChildAt(x).getLayoutParams();
params.height = isHighestHighInLeft ? leftHeaderFirstLvlHighestHeight : rightHeaderFirstLvlHighestHeight;
}
}
}
/**
*
* @author lau
*
*/
class LoadingDialog extends Dialog{
LoadingDialog(Context context) {
super(context);
this.setCancelable(false);
this.requestWindowFeature(Window.FEATURE_NO_TITLE);
this.init(context);
}
private void init(Context context){
TextView textView = new TextView(context);
textView.setText("Please wait loading data..");
this.setContentView(textView);
}
}
class Passenger{
String name;
char gender;
int ticketNum;
String validUntil;
String setSequence;
String countryFrom;
String countryTo;
}
}
And so on, sorry, an answer is limited to 30 000 characters.
Screenshot of multi-scroll view
Here is my solution using recycler views that sync within nested fragments, available on github: https://github.com/simplyAmazin87/MultiScrollView
Here is the gist of it, first we have the main activity layout:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="match_parent"
android:background="@color/colorlight"
android:layout_height="match_parent">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@drawable/tbl_border2"
android:orientation="horizontal">
<TextView
android:text="MultiScroll Table View"
android:id="@+id/statText"
android:textSize="24sp"
android:paddingRight="20dp"
android:textColor="@color/colorDarkBlue"
android:gravity="center_horizontal|center_vertical"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
</LinearLayout>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:id="@+id/main_content"
tools:context=".activities.MainActivity">
<!-- TODO: Update blank fragment layout -->
</FrameLayout>
</LinearLayout>
Then we have our main fragment where we define the static portion of the header, a recycler view for the horizontal portion of the header, and also a frame layout within a scrollview so we can add the content that we want to scroll vertically:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:splitMotionEvents="true"
android:layout_width="match_parent"
android:background="@color/colorlight"
android:layout_margin="2dp"
android:layout_height="match_parent">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:splitMotionEvents="false"
android:orientation="horizontal">
<RelativeLayout
android:layout_width="80dp"
android:layout_height="wrap_content">
<TextView
android:layout_width="match_parent"
android:textAppearance="?android:attr/textAppearanceLarge"
android:gravity="center_horizontal"
android:background="@drawable/tbl_border"
android:layout_height="wrap_content"
android:text="Static1"
android:id="@+id/hdr_Col_St1"
android:textSize="20dp"
android:padding="4dp"
android:textColor="@color/colorlight"/>
</RelativeLayout>
<RelativeLayout
android:layout_width="80dp"
android:layout_height="wrap_content">
<TextView
android:layout_width="match_parent"
android:textAppearance="?android:attr/textAppearanceLarge"
android:gravity="center_horizontal"
android:background="@drawable/tbl_border"
android:layout_height="wrap_content"
android:text="Static2"
android:id="@+id/hdr_Col_St2"
android:textSize="20dp"
android:padding="4dp"
android:textColor="@color/colorlight"/>
</RelativeLayout>
<android.support.v7.widget.RecyclerView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@drawable/tbl_border"
android:id="@+id/hdr_recycler_view"
></android.support.v7.widget.RecyclerView>
</LinearLayout>
<android.support.v4.widget.NestedScrollView
android:id="@+id/vertical_scroll"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<FrameLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"
android:id="@+id/detail_content">
</FrameLayout>
</android.support.v4.widget.NestedScrollView>
</LinearLayout>
Finally we have our final layout where we define the portion of the table that can scroll vertically, along with a recycler view with a horizontal orientation that will be able to scroll both ways. This recycler view must sync with the recycler view defined for the header in order to work correctly:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="2dp"
android:splitMotionEvents="false"
android:orientation="horizontal">
<RelativeLayout
android:layout_width="80dp"
android:layout_height="wrap_content"
android:background="@drawable/tbl_border2">
<TextView
android:layout_width="match_parent"
android:textAppearance="?android:attr/textAppearanceLarge"
android:layout_height="wrap_content"
android:gravity="center_horizontal"
android:text="A1"
android:layout_marginTop="5dp"
android:id="@+id/ColA1"
android:textSize="20dp"
android:padding="4dp"
android:textColor="@color/colorDarkBlue"
/>
<TextView
android:layout_width="match_parent"
android:textAppearance="?android:attr/textAppearanceLarge"
android:layout_height="wrap_content"
android:text="A2"
android:gravity="center_horizontal"
android:layout_marginTop="5dp"
android:layout_below="@id/ColA1"
android:id="@+id/ColA2"
android:textSize="20dp"
android:padding="4dp"
android:textColor="@color/colorDarkBlue"
/>
<TextView
android:layout_width="match_parent"
android:textAppearance="?android:attr/textAppearanceLarge"
android:layout_height="wrap_content"
android:text="A3"
android:layout_marginTop="5dp"
android:gravity="center_horizontal"
android:layout_below="@id/ColA2"
android:id="@+id/ColA3"
android:textSize="20dp"
android:padding="4dp"
android:textColor="@color/colorDarkBlue"
/>
<TextView
android:layout_width="match_parent"
android:textAppearance="?android:attr/textAppearanceLarge"
android:layout_height="wrap_content"
android:text="A4"
android:layout_marginTop="5dp"
android:layout_below="@id/ColA3"
android:id="@+id/ColA4"
android:textSize="20dp"
android:gravity="center_horizontal"
android:padding="4dp"
android:textColor="@color/colorDarkBlue"
/>
<TextView
android:layout_width="match_parent"
android:textAppearance="?android:attr/textAppearanceLarge"
android:layout_height="wrap_content"
android:text="A5"
android:layout_marginTop="5dp"
android:layout_below="@id/ColA4"
android:id="@+id/ColA5"
android:textSize="20dp"
android:gravity="center_horizontal"
android:padding="4dp"
android:textColor="@color/colorDarkBlue"
/>
<TextView
android:layout_width="match_parent"
android:textAppearance="?android:attr/textAppearanceLarge"
android:layout_height="wrap_content"
android:text="A6"
android:layout_marginTop="5dp"
android:layout_below="@id/ColA5"
android:id="@+id/ColA6"
android:textSize="20dp"
android:gravity="center_horizontal"
android:padding="4dp"
android:textColor="@color/colorDarkBlue"
/>
<TextView
android:layout_width="match_parent"
android:textAppearance="?android:attr/textAppearanceLarge"
android:layout_height="wrap_content"
android:text="A7"
android:layout_marginTop="5dp"
android:layout_below="@id/ColA6"
android:id="@+id/ColA7"
android:textSize="20dp"
android:gravity="center_horizontal"
android:padding="4dp"
android:textColor="@color/colorDarkBlue"
/>
<TextView
android:layout_width="match_parent"
android:textAppearance="?android:attr/textAppearanceLarge"
android:layout_height="wrap_content"
android:text="A8"
android:layout_marginTop="5dp"
android:layout_below="@id/ColA7"
android:id="@+id/ColA8"
android:textSize="20dp"
android:gravity="center_horizontal"
android:padding="4dp"
android:textColor="@color/colorDarkBlue"
/>
<TextView
android:layout_width="match_parent"
android:textAppearance="?android:attr/textAppearanceLarge"
android:layout_height="wrap_content"
android:text="A9"
android:layout_marginTop="5dp"
android:layout_below="@id/ColA8"
android:id="@+id/ColA9"
android:textSize="20dp"
android:gravity="center_horizontal"
android:padding="4dp"
android:textColor="@color/colorDarkBlue"
/>
<TextView
android:layout_width="match_parent"
android:textAppearance="?android:attr/textAppearanceLarge"
android:layout_height="wrap_content"
android:text="A10"
android:layout_marginTop="5dp"
android:layout_below="@id/ColA9"
android:id="@+id/ColA10"
android:textSize="20dp"
android:gravity="center_horizontal"
android:padding="4dp"
android:textColor="@color/colorDarkBlue"
/>
<TextView
android:layout_width="match_parent"
android:textAppearance="?android:attr/textAppearanceLarge"
android:layout_height="wrap_content"
android:text="A11"
android:layout_marginTop="5dp"
android:layout_below="@id/ColA10"
android:id="@+id/ColA11"
android:textSize="20dp"
android:gravity="center_horizontal"
android:padding="4dp"
android:textColor="@color/colorDarkBlue"
/>
<TextView
android:layout_width="match_parent"
android:textAppearance="?android:attr/textAppearanceLarge"
android:layout_height="wrap_content"
android:text="A12"
android:layout_marginTop="5dp"
android:layout_below="@id/ColA11"
android:id="@+id/ColA12"
android:textSize="20dp"
android:padding="4dp"
android:gravity="center_horizontal"
android:textColor="@color/colorDarkBlue"
/>
<TextView
android:layout_width="match_parent"
android:textAppearance="?android:attr/textAppearanceLarge"
android:layout_height="wrap_content"
android:text="A13"
android:layout_marginTop="5dp"
android:layout_below="@id/ColA12"
android:id="@+id/ColA13"
android:textSize="20dp"
android:padding="4dp"
android:gravity="center_horizontal"
android:textColor="@color/colorDarkBlue"
/>
<TextView
android:layout_width="match_parent"
android:textAppearance="?android:attr/textAppearanceLarge"
android:layout_height="wrap_content"
android:text="A14"
android:layout_marginTop="5dp"
android:layout_below="@id/ColA13"
android:id="@+id/ColA14"
android:textSize="20dp"
android:padding="4dp"
android:gravity="center_horizontal"
android:textColor="@color/colorDarkBlue"
/>
<TextView
android:layout_width="match_parent"
android:textAppearance="?android:attr/textAppearanceLarge"
android:layout_height="wrap_content"
android:text="A15"
android:layout_marginTop="5dp"
android:layout_below="@id/ColA14"
android:id="@+id/ColA15"
android:textSize="20dp"
android:padding="4dp"
android:gravity="center_horizontal"
android:textColor="@color/colorDarkBlue"
/>
</RelativeLayout>
<RelativeLayout
android:layout_width="80dp"
android:layout_height="wrap_content"
android:background="@drawable/tbl_border2">
<TextView
android:layout_width="match_parent"
android:textAppearance="?android:attr/textAppearanceLarge"
android:layout_height="wrap_content"
android:gravity="center_horizontal"
android:text="B1"
android:layout_marginTop="5dp"
android:id="@+id/ColB1"
android:textSize="20dp"
android:padding="4dp"
android:textColor="@color/colorDarkBlue"
/>
<TextView
android:layout_width="match_parent"
android:textAppearance="?android:attr/textAppearanceLarge"
android:layout_height="wrap_content"
android:text="B2"
android:gravity="center_horizontal"
android:layout_marginTop="5dp"
android:layout_below="@id/ColB1"
android:id="@+id/ColB2"
android:textSize="20dp"
android:padding="4dp"
android:textColor="@color/colorDarkBlue"
/>
<TextView
android:layout_width="match_parent"
android:textAppearance="?android:attr/textAppearanceLarge"
android:layout_height="wrap_content"
android:text="B3"
android:layout_marginTop="5dp"
android:gravity="center_horizontal"
android:layout_below="@id/ColB2"
android:id="@+id/ColB3"
android:textSize="20dp"
android:padding="4dp"
android:textColor="@color/colorDarkBlue"
/>
<TextView
android:layout_width="match_parent"
android:textAppearance="?android:attr/textAppearanceLarge"
android:layout_height="wrap_content"
android:text="B4"
android:layout_marginTop="5dp"
android:layout_below="@id/ColB3"
android:id="@+id/ColB4"
android:textSize="20dp"
android:gravity="center_horizontal"
android:padding="4dp"
android:textColor="@color/colorDarkBlue"
/>
<TextView
android:layout_width="match_parent"
android:textAppearance="?android:attr/textAppearanceLarge"
android:layout_height="wrap_content"
android:text="B5"
android:layout_marginTop="5dp"
android:layout_below="@id/ColB4"
android:id="@+id/ColB5"
android:textSize="20dp"
android:gravity="center_horizontal"
android:padding="4dp"
android:textColor="@color/colorDarkBlue"
/>
<TextView
android:layout_width="match_parent"
android:textAppearance="?android:attr/textAppearanceLarge"
android:layout_height="wrap_content"
android:text="B6"
android:layout_marginTop="5dp"
android:layout_below="@id/ColB5"
android:id="@+id/ColB6"
android:textSize="20dp"
android:gravity="center_horizontal"
android:padding="4dp"
android:textColor="@color/colorDarkBlue"
/>
<TextView
android:layout_width="match_parent"
android:textAppearance="?android:attr/textAppearanceLarge"
android:layout_height="wrap_content"
android:text="B7"
android:layout_marginTop="5dp"
android:layout_below="@id/ColB6"
android:id="@+id/ColB7"
android:textSize="20dp"
android:gravity="center_horizontal"
android:padding="4dp"
android:textColor="@color/colorDarkBlue"
/>
<TextView
android:layout_width="match_parent"
android:textAppearance="?android:attr/textAppearanceLarge"
android:layout_height="wrap_content"
android:text="B8"
android:layout_marginTop="5dp"
android:layout_below="@id/ColB7"
android:id="@+id/ColB8"
android:textSize="20dp"
android:gravity="center_horizontal"
android:padding="4dp"
android:textColor="@color/colorDarkBlue"
/>
<TextView
android:layout_width="match_parent"
android:textAppearance="?android:attr/textAppearanceLarge"
android:layout_height="wrap_content"
android:text="B9"
android:layout_marginTop="5dp"
android:layout_below="@id/ColB8"
android:id="@+id/ColB9"
android:textSize="20dp"
android:gravity="center_horizontal"
android:padding="4dp"
android:textColor="@color/colorDarkBlue"
/>
<TextView
android:layout_width="match_parent"
android:textAppearance="?android:attr/textAppearanceLarge"
android:layout_height="wrap_content"
android:text="B10"
android:layout_marginTop="5dp"
android:layout_below="@id/ColB9"
android:id="@+id/ColB10"
android:textSize="20dp"
android:gravity="center_horizontal"
android:padding="4dp"
android:textColor="@color/colorDarkBlue"
/>
<TextView
android:layout_width="match_parent"
android:textAppearance="?android:attr/textAppearanceLarge"
android:layout_height="wrap_content"
android:text="B11"
android:layout_marginTop="5dp"
android:layout_below="@id/ColB10"
android:id="@+id/ColB11"
android:textSize="20dp"
android:gravity="center_horizontal"
android:padding="4dp"
android:textColor="@color/colorDarkBlue"
/>
<TextView
android:layout_width="match_parent"
android:textAppearance="?android:attr/textAppearanceLarge"
android:layout_height="wrap_content"
android:text="B12"
android:layout_marginTop="5dp"
android:layout_below="@id/ColB11"
android:id="@+id/ColB12"
android:textSize="20dp"
android:padding="4dp"
android:gravity="center_horizontal"
android:textColor="@color/colorDarkBlue"
/>
<TextView
android:layout_width="match_parent"
android:textAppearance="?android:attr/textAppearanceLarge"
android:layout_height="wrap_content"
android:text="B13"
android:layout_marginTop="5dp"
android:layout_below="@id/ColB12"
android:id="@+id/ColB13"
android:textSize="20dp"
android:padding="4dp"
android:gravity="center_horizontal"
android:textColor="@color/colorDarkBlue"
/>
<TextView
android:layout_width="match_parent"
android:textAppearance="?android:attr/textAppearanceLarge"
android:layout_height="wrap_content"
android:text="B14"
android:layout_marginTop="5dp"
android:layout_below="@id/ColB13"
android:id="@+id/ColB14"
android:textSize="20dp"
android:padding="4dp"
android:gravity="center_horizontal"
android:textColor="@color/colorDarkBlue"
/>
<TextView
android:layout_width="match_parent"
android:textAppearance="?android:attr/textAppearanceLarge"
android:layout_height="wrap_content"
android:text="B15"
android:layout_marginTop="5dp"
android:layout_below="@id/ColB14"
android:id="@+id/ColB15"
android:textSize="20dp"
android:padding="4dp"
android:gravity="center_horizontal"
android:textColor="@color/colorDarkBlue"
/>
</RelativeLayout>
<android.support.v7.widget.RecyclerView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@drawable/tbl_border2"
android:id="@+id/dtl_recyler_view"
></android.support.v7.widget.RecyclerView>
</LinearLayout>
精彩评论