Android布局 – 如何实现固定/冻结的标题和列

我想创build一个包含大量列(7-10)的表格式视图,而标题行始终可见(即使向下滚动时),而第一列在水平滚动时也始终可见。

试图把一个列表视图内的一个Horizo​​ntalScrollView,让我显示一个列表水平和垂直滚动,但没有静态列/标题。 我试图避免使用多个视图,并在用户滚动时同步它们。

稍后,我将不得不像列/行点击一样控制视图内的事件,所以应该使用自定义适配器。

有任何想法吗?

Solutions Collecting From Web of "Android布局 – 如何实现固定/冻结的标题和列"

您可以查看我制作的这个库: https : //github.com/InQBarna/TableFixHeaders

我认为它实现了你正在寻找的小部件。

我会用TableRow填充TableLayout

以下代码演示了如何实现这一点。

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

标题是不垂直滚动的部分; 这就是你需要在列上设置固定宽度的原因。 至于你不想滚动的第一列,你必须为此设置一个固定的行高。

这是布局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> 

而刚刚加载的输出看起来像这样

在这里输入图像说明

像这样滚动到右侧和底部

在这里输入图像说明

创buildTableLayout这将是一个头,并在它下面放置一个表本身在一个ScrollView像这样:

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

当你用数据填充标题时,添加下面的代码:

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

而已。

如果想修复第一列,你可以尝试下面的布局:

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

我find了两个实例。 http://justsimpleinfo.blogspot.com/2015/04/android-scrolling-table-with-fixed.html

https://www.codeofaninja.com/2013/08/android-scroll-table-fixed-header-column.html(https://www.youtube.com/watch?v=VCjlcV20ftE )。 在第二种情况下会显示警告,所以可以使用Android IDtypes的预期资源来修复。

来自第一个链接的代码。

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

等等,对不起,答案限于30 000个字符。

多滚动视图的屏幕截图

这里是我的解决scheme,使用回收利用视图,在嵌套片段同步,在github上可用: https : //github.com/simplyAmazin87/MultiScrollView

这是它的要点,首先我们有主要的活动布局:

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

然后,我们有我们的主要片段,我们定义标题的静态部分,标题水平部分的回收站视图,以及滚动视图内的框架布局,所以我们可以添加我们想要垂直滚动的内容:

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

最后,我们有我们的最终布局,在这里我们定义可以垂直滚动的表格部分,以及具有水平方向的回收器视图,可以双向滚动。 此回收站视图必须与为标题定义的回收站视图同步才能正常工作:

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