Android TableLayout表头行

15

好的,我有一个TableLayout,里面装满了数据——所有行都是通过编程方式添加的。我把TableLayout放在HorizontalScrollView里面,并将其放在ScrollView里面——这样我就可以水平和垂直滚动。现在我想做的是在它上面添加一个不会滚动的标题行。我尝试移动一些东西,使我的两个滚动视图实际上都在TableLayout内部,并将TableRows添加到HorizontalScrollView中;我的希望是能够在滚动视图之外添加标题行。

唯一能想到的另一件事是为标题行再创建一个TableLayout,但是让列对齐似乎会很困难。有什么想法吗?

6个回答

15

一种方法是在一个TableLayout的行中嵌入另一个TableLayout,并将标题放在前面的行中,如下所示。为了使数据和标题对齐,需要将标题View对象和数据View对象的layout_width属性设置为相同的dip值。此外,内部TableLayout的View对象的layout_weight属性必须与其对应的标题匹配。 现在,在下面的XML中,我在一个单行内的内部TableLayout中放置了3个TextView,以与列标题匹配。这只是为了展示如何进行对齐。您可以通过膨胀布局并在运行时添加它来以编程方式填充那些数据。

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

尝试这个答案:http://stackoverflow.com/questions/20241614/android-fixed-header-horizontal-and-vertical-scrolling-table/26211896#26211896 - M S Gadag
不支持水平滚动。 - Aristo Michael

13

我实际上想到了另一种不错的方法。

只需在垂直方向LinearLayout中将标题行作为第一行正常构建表格。接着,编程地删除第一行,然后将其作为LinearLayout的第一个子元素添加即可。这个方法非常有效。

编辑:这种方法也可以在不指定静态列宽的情况下使用。


我使用了 ((ViewGroup)tableRow.getParent()).removeChild(tableRow); 然后 linearLayout.addView(tableRow); 语句,但是它只删除了表头并没有显示出来,也没有保持列宽。 我是在 onCreate() 中这样做的。也许需要放到其他位置。 - James
我喜欢这个想法,但不幸的是对我来说完全没有用。标题列始终只有最小宽度,并且与数据列不对齐。本来会太好了... - mmo

4

我知道这个问题很老,但这是谷歌给我的第一个答案,因为我也遇到了同样的问题。而且我认为我找到了一个更好的解决方案,我想分享一下。

思路:将TableLayout(在ScrollView中)放入RelativeLayout中,并创建一个覆盖层,在其上绘制第一行(标题行),覆盖其他所有内容。

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

下面是代码:

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

赞!我不太明白这是如何工作的,但它确实能够运行!非常优雅,确实 :-) - mmo
这种方法的问题在于它会导致内存泄漏!每次重绘时,都会创建并添加一个新的fakeHeaderView到tableWrapper中(子列表随着调试器的验证而不断增长)。而且 - 正如我通过实验发现的那样 - 由于某种奇怪的原因,无法删除旧实例,否则最后添加的实例将无法正确绘制,整个效果也无法正常工作!有什么提示吗? - mmo

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

0

对于那些不喜欢预定义大小的人,我发现了一个有点小技巧,对我很有效。

基本上,为标题制作一个单独的表格,并将其放在主表格上方,但与相同的顶部对齐,然后创建两个标题行的副本,在将一个添加到主表格之后,将另一个添加到标题表格中,并将子视图的layoutParams设置为来自主表格的行。

这是我的基本示例。

在您的布局中:

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

然后当您添加行时:

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

0

使用两个TableLayout,一个在ScrollView中,像这样设置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>

然后为行创建一个通用视图,最重要的是提到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>

现在在活动中

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

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接