Question

Okay, so I've got this TableLayout, and its full of data - with all of the rows added programmatically. I've got the TableLayout inside of a HorizontalScrollView, which in turn is inside a ScrollView - this gives me scrolling both horizontally and vertically. What I'm trying to do now is add a header row to it that will not scroll. I've tried moving things around so that both of my scroll views were actually inside of the TableLayout and adding the TableRows to the HorizontalScrollView; my hope was to be able to then add the header row outside of the scroll views.

The only other thing I can think of is having a second table layout just for the header row, but getting the columns to line up seems like it would be difficult. Any ideas?

Was it helpful?

Solution

One approach is by embedding a TableLayout within another TableLayout's row and putting the header in the preceding row as seen below. Aligning the data and the header requires the layout_width property of the header View objects and the data's View objects to be set to the same dip values. Also, the layout_weight property of the inner TableLayout's View objects must match its corresponding header. Now, in the XML below, I have placed 3 TextViews in the inner TableLayout in a single row to match with the column headers. This is just to show how the alignment can be done. You can populate that data programmatically by inflating a layout and adding it at runtime.

<?xml version="1.0" encoding="utf-8"?>
<TableLayout
  xmlns:android="http://schemas.android.com/apk/res/android"
  android:layout_width="fill_parent"
  android:layout_height="fill_parent">


  <TableRow>
    <TextView android:text="Name"
        android:layout_width="100dp"        
        android:layout_column="0"
        android:layout_weight="1"/>
    <TextView android:text="Score"
        android:layout_width="30dp"
        android:layout_column="1"
        android:layout_weight="1">
    </TextView>
    <TextView android:text="Level"
        android:layout_width="30dp"
        android:layout_column="2"
        android:layout_weight="1">
    </TextView>
  </TableRow>

    <ScrollView android:layout_height="120dp">      
    <TableLayout android:id="@+id/score_table"
      android:layout_width="fill_parent"
      android:layout_height="fill_parent">          
    <TableRow>
        <TextView android:text="Al"
        android:layout_width="100dp"        
        android:layout_column="0"
        android:layout_weight="1">
        </TextView>
        <TextView android:text="1000"
        android:layout_width="30dp"
        android:layout_column="1"
        android:layout_weight="1">
        </TextView>
        <TextView android:text="2"
        android:layout_width="30dp"
        android:layout_column="2"
        android:layout_weight="1">
        </TextView>
    </TableRow>
  </TableLayout>
  </ScrollView>     
</TableLayout>

OTHER TIPS

I actually came up with another decent way of doing this.

Simply build the table normally with the header row as the first row, inside of a vertical orientation LinearLayout. Next, programmatically remove the first row then add it as the first child to the LinearLayout. This worked like a charm.

Edit: This also works without having to specify static column widths.

I know that the question is old, but it was the first one, that Google gave me as I've had the same problem. And since I think I've found a better solution, I would like to share it.

Idea: put the TableLayout (inside the ScrollView) into RelativeLayout and create an overlay, that would draw the first (header) row over everything else.

Here is layout.xml:

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"

    android:id="@+id/table_wrapper"

    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
>
    <ScrollView

        android:layout_width="wrap_content"
        android:layout_height="wrap_content"

        tools:ignore="UselessParent"
    >
        <TableLayout

            android:id="@+id/table"

            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
        />
    </ScrollView>
</RelativeLayout>

And here is the code:

TableLayout table = (TableLayout)view.findViewById(R.id.table);

final TableRow headerRow = new TableRow(context);
table.addView(headerRow);

table.addView(new TableRow(context));
table.addView(new TableRow(context));
table.addView(new TableRow(context));


RelativeLayout tableWrapper = (RelativeLayout)view.findViewById(R.id.table_wrapper);

View fakeHeaderView = new View(context) {
    @Override
    public void draw(Canvas canvas) {
        headerRow.draw(canvas);
    }
    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {

        int width = headerRow.getMeasuredWidth();
        int height = headerRow.getMeasuredHeight();

        widthMeasureSpec = MeasureSpec.makeMeasureSpec(width, MeasureSpec.EXACTLY);
        heightMeasureSpec = MeasureSpec.makeMeasureSpec(height, MeasureSpec.EXACTLY);

        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
    }
};

tableWrapper.addView(fakeHeaderView);

For those not happy with having to pre-define your sizes, I found a bit of a hack that's working for me.

Basically, make a separate table for the title and put it over your main table, but with the same Top alignment, then create two copies of the title row and after adding one to the main table, add the other to the title table and set the child view's layoutParams to the row form the main table.

Here's my basic example.

in your layout:

<HorizontalScrollView
    android:id="@+id/table_horizontal_scroll_view"
    android:layout_alignParentTop="true"
    android:layout_width="wrap_content"
    android:layout_height="match_parent"
    android:clickable="false">

    <RelativeLayout
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        >

        <ScrollView
            android:layout_alignParentTop="true"
            android:layout_marginTop="0dp"
            android:id="@+id/table_vertical_scroll_view"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content">

            <TableLayout
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:id="@+id/grid_table_layout"
                />

        </ScrollView>

        <TableLayout
            android:layout_alignLeft="@+id/table_vertical_scroll_view"
            android:layout_alignRight="@+id/table_vertical_scroll_view"
            android:layout_alignStart="@+id/table_vertical_scroll_view"
            android:layout_alignEnd="@+id/table_vertical_scroll_view"
            android:layout_alignParentTop="true"
            android:background="@color/grid_view_background"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:id="@+id/grid_floating_row_layout"
            />

    </RelativeLayout>


</HorizontalScrollView>

Then when you add your rows:

    //clear out any views
    tableLayout.removeAllViews();
    floatingRowLayout.removeAllViews();

    TableRow[] rows = getTableContentRows() // content of your table
    TableRow[] titleRows = {getTitleRow(), getTitleRow()}; //two copies of your title row
    tableLayout.addView(titleRows[0]); // first add the first title to the main table
    addRows(rows) // add any other rows

    floatingRowLayout.addView(titleRows[1]); // floatingRowLayout is connected to id/grid_floating_row_layout

    titleRows[0].setVisibility(View.INVISIBLE); // make the title row added to the main table invisible

    // Set the layoutParams of the two title rows equal to each other. 
    // Since this is done after the first is added to the main table, they should be the correct sizes.
    for(int i = 0; i < titleRows[0].getChildCount(); i++) {
      titleRows[1].getChildAt(i).setLayoutParams(titleRows[0].getChildAt(i).getLayoutParams());
    }

Use Two tableLayout One in ScrollView like give android:stretchColumns="*"

   <RelativeLayout
            android:layout_width="match_parent"
            android:orientation="vertical"
            android:paddingTop="5dp"
            android:layout_height="match_parent"
            android:layout_below="@+id/llSpinner">
            <TableLayout
                android:layout_width="match_parent"
                android:id="@+id/tableHead"
android:stretchColumns="*" 
                android:layout_height="wrap_content">
            </TableLayout>

        <ScrollView
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_above="@+id/tableTotal"
            android:layout_below="@+id/tableHead"
            android:id="@+id/scrolltable">


        </ScrollView>
    <TableLayout
                android:layout_width="match_parent"
                android:id="@+id/tableTotal"
android:stretchColumns="*" 
                android:layout_alignParentBottom="true"
                android:layout_height="wrap_content">
            </TableLayout>
        </RelativeLayout>

then create a common view for ROWs and most important mention android:layout_width="0dp"

<TableRow
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="fill_parent"
    android:layout_height="?android:attr/listPreferredItemHeight"
    android:focusable="true"
    android:focusableInTouchMode="false"
    android:clickable="true"
    android:background="@android:drawable/list_selector_background">

    <TextView
        android:text="S.No"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:id="@+id/tbsNo"
        android:layout_weight="1"
        android:gravity="center"
        android:layout_column="1" />

    <TextView
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:text="Date"
        android:layout_weight="1"
        android:gravity="center"
        android:id="@+id/tbDate"
        android:layout_column="2" />


    <TextView
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:text="Count"
        android:layout_weight="1"
        android:gravity="center"
        android:id="@+id/tbMrCount"
        android:layout_column="3" />
</TableRow>

Now in Activity

 Tablelayout tableHeading =(TableLayout)findViewById(R.id.tableHead);


               Tablelayout    table =(TableLayout) findViewById(R.id.table_repots);
                   trHeading = (TableRow) getLayoutInflater().inflate(R.layout.table_row_item, null);
                trHeading.setBackgroundColor(Color.parseColor("#6688AC"));
                trHeading.setPadding(0,10,0,10);

                TextView tv;
                tv = (TextView) trHeading.findViewById(R.id.tbsNo);
                tv.setText("S.No");
            tv = (TextView) trHeading.findViewById(R.id.tbDate);
           tv.setText("Date");
          table.addView(tv);
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top