tablas studio gridlayout generar ejemplo editables diseño dinamicas create crear como activity android android-layout

studio - Diseño de Android: cómo implementar un encabezado/columna fijo/congelado



tablas editables en android studio (6)

Me gustaría crear una vista de tabla que contenga una gran cantidad de columnas (7-10) mientras que la fila de encabezados siempre está visible (incluso cuando se desplaza hacia abajo) y la primera columna también siempre visible mientras se desplaza horizontalmente.

Traté de poner una vista de lista dentro de un HorizontalScrollView que me permitió mostrar una lista con desplazamiento horizontal y vertical, pero no columna / encabezado estático. Estoy tratando de evitar el uso de múltiples vistas y sincronizarlas mientras el usuario se desplaza.

Más adelante, tendré que controlar los eventos dentro de la vista como clics de fila / columna, por lo que se debe usar algo con un adaptador personalizado.

¿algunas ideas?


Me gustaría ir con TableLayout poblado por TableRow .

El siguiente código demuestra cómo lograr eso.

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; } }

El encabezado es la parte que no se desplaza verticalmente; esa es la razón por la que necesita establecer ancho fijo en columnas. A partir de la primera columna que no desea desplazarse, tendrá que establecer una altura fija en las filas para ese fin.

Aquí está el diseño 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>

Y la salida se ve así cuando acaba de cargar

y así cuando se desplaza hacia la derecha y hacia abajo



Cree TableLayout que será un encabezado y debajo de él colocará una tabla en sí misma dentro de un ScrollView como este:

<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>

Cuando complete su encabezado con datos, agregue el siguiente código:

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())); } } });

Eso es.


Si quieres arreglar la primera columna, puedes probar el siguiente diseño:

<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>


Encontré dos ejemplos de trabajo. http://justsimpleinfo.blogspot.com/2015/04/android-scrolling-table-with-fixed.html

y

https://www.codeofaninja.com/2013/08/android-scroll-table-fixed-header-column.html ( https://www.youtube.com/watch?v=VCjlcV20ftE ). En el segundo caso, se muestra una advertencia, por lo que se puede solucionar con Android - Recurso esperado del tipo ID .

Un código del primer enlace.

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; } }

Y así sucesivamente, lo siento, una respuesta está limitada a 30 000 caracteres.


Captura de pantalla de vista de desplazamiento múltiple

Aquí está mi solución usando vistas de reciclador que se sincronizan con fragmentos anidados, disponible en github: https://github.com/simplyAmazin87/MultiScrollView

Aquí está la esencia de esto, primero tenemos el diseño de la actividad principal:

<?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>

Luego tenemos nuestro fragmento principal donde definimos la parte estática del encabezado, una vista de reciclador para la parte horizontal del encabezado y también un diseño de marco dentro de una vista de desplazamiento para que podamos agregar el contenido que queremos desplazar verticalmente:

<?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>

Finalmente tenemos nuestro diseño final donde definimos la parte de la tabla que puede desplazarse verticalmente, junto con una vista de reciclador con una orientación horizontal que podrá desplazarse en ambos sentidos. Esta vista de reciclador debe sincronizarse con la vista de reciclador definida para el encabezado para que funcione correctamente:

<?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>