如何在Android中创建带有边框的表格?

199

我使用表格布局将数据显示为表格,但我想要一个具有用户定义列和行以及边框的表格。有什么建议?

18个回答

204

我对这个问题的解决方案是在每个单元格的背景字段上放置一个xml可绘制资源。通过这种方式,您可以为所有单元格定义具有所需边框的形状。唯一的不便之处在于极端单元格的边框宽度是其他单元格的一半,但如果您的表填满整个屏幕,这不是问题。

一个例子:

drawable/cell_shape.xml

<?xml version="1.0" encoding="utf-8"?>
<shape
  xmlns:android="http://schemas.android.com/apk/res/android"
    android:shape= "rectangle"  >
        <solid android:color="#000"/>
        <stroke android:width="1dp"  android:color="#ff9"/>
</shape>

布局/my_table.xml

<?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="match_parent"
    android:orientation="vertical">

    <TableRow
        android:id="@+id/tabla_cabecera"
        android:layout_width="match_parent"
        android:layout_height="match_parent"></TableRow>

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

        <TableRow
            android:id="@+id/tableRow1"
            android:layout_width="match_parent"
            android:layout_height="wrap_content">

            <TextView
                android:id="@+id/textView1"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:background="@drawable/cell_shape"
                android:padding="5dp"
                android:text="TextView"
                android:textAppearance="?android:attr/textAppearanceMedium"></TextView>

            <TextView
                android:id="@+id/textView1"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:background="@drawable/cell_shape"
                android:padding="5dp"
                android:text="TextView"
                android:textAppearance="?android:attr/textAppearanceMedium"></TextView>

            <TextView
                android:id="@+id/textView1"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:background="@drawable/cell_shape"
                android:padding="5dp"
                android:text="TextView"
                android:textAppearance="?android:attr/textAppearanceMedium"></TextView>

        </TableRow>

        <TableRow
            android:id="@+id/tableRow2"
            android:layout_width="match_parent"
            android:layout_height="wrap_content">

            <TextView
                android:id="@+id/textView1"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:background="@drawable/cell_shape"
                android:padding="5dp"
                android:text="TextView"
                android:textAppearance="?android:attr/textAppearanceMedium"></TextView>

            <TextView
                android:id="@+id/textView1"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:background="@drawable/cell_shape"
                android:padding="5dp"
                android:text="TextView"
                android:textAppearance="?android:attr/textAppearanceMedium"></TextView>

            <TextView
                android:id="@+id/textView1"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:background="@drawable/cell_shape"
                android:padding="5dp"
                android:text="TextView"
                android:textAppearance="?android:attr/textAppearanceMedium"></TextView>
        </TableRow>

        <TableRow
            android:id="@+id/tableRow3"
            android:layout_width="match_parent"
            android:layout_height="wrap_content">

            <TextView
                android:id="@+id/textView1"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:background="@drawable/cell_shape"
                android:padding="5dp"
                android:text="TextView"
                android:textAppearance="?android:attr/textAppearanceMedium"></TextView>

            <TextView
                android:id="@+id/textView1"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:background="@drawable/cell_shape"
                android:padding="5dp"
                android:text="TextView"
                android:textAppearance="?android:attr/textAppearanceMedium"></TextView>

            <TextView
                android:id="@+id/textView1"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:background="@drawable/cell_shape"
                android:padding="5dp"
                android:text="TextView"
                android:textAppearance="?android:attr/textAppearanceMedium"></TextView>

        </TableRow>

        <TableRow
            android:id="@+id/tableRow4"
            android:layout_width="match_parent"
            android:layout_height="wrap_content">

            <TextView
                android:id="@+id/textView1"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:background="@drawable/cell_shape"
                android:padding="5dp"
                android:text="TextView"
                android:textAppearance="?android:attr/textAppearanceMedium"></TextView>

            <TextView
                android:id="@+id/textView1"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:background="@drawable/cell_shape"
                android:padding="5dp"
                android:text="TextView"
                android:textAppearance="?android:attr/textAppearanceMedium"></TextView>

            <TextView
                android:id="@+id/textView1"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:background="@drawable/cell_shape"
                android:padding="5dp"
                android:text="TextView"
                android:textAppearance="?android:attr/textAppearanceMedium"></TextView>

        </TableRow>
    </TableLayout>


</LinearLayout>

编辑:一个例子

输入图片描述

编辑2:另一个例子(具有更多元素:圆角、渐变等) 输入图片描述

我在http://blog.intelligenia.com/2012/02/programacion-movil-en-android.html#more中更详细地解释了这个问题。虽然是用西班牙语写的,但其中包含一些更复杂表格的代码和图像。


6
我无法查看内容。 - Krishna
1
我该如何通过编程方式设置视图的背景? view.setBackground(?) - rasen58
1
为了查看这个内容,只需删除名为 "tabla_cabecera" 的第一行。 - ymerdrengene
1
这将使边框至少显示为2像素厚,这不如1像素宽的边框好看。 - Johann
1
是的,正如我所解释的,这是唯一的不便之处,但如果您的表填满整个屏幕,您可以将底部和左侧边框设置为1像素(例如),那么您将得到一个带有1像素边框的表格。 - David Jesse
1
这里唯一的问题是多行之间的边框线会变粗(由于边框重叠而发生)。为了解决这个问题,在TableLayout和TableRows中添加android:background="@drawable/border",但是要交替添加(即在第2、4、6行... TableRow中添加背景)。 - Akshay Ashok

56
我同意Brad的看法。那是一个可怕的答案。Android文档说明TableLayout容器不显示边框线,因此将它们发送到Android网站对他们没有任何帮助。我在droidnova上找到了一个“肮脏”的解决方案,其中涉及为TableLayout设置背景颜色,然后为TableRow设置不同的背景颜色并添加layout_margin到行中。我不喜欢这个解决方案,但它确实适用于行边框。我猜你也可以对构成每个“单元格”项的项目执行相同的操作,但我还没有验证。
与DroidNova上的示例类似的示例:
<TableLayout android:background="#000000"
android:layout_width="fill_parent"
android:layout_height="wrap_content">
  <TableRow android:background="#FFFFFF"
  android:layout_width="fill_parent"
  android:layout_height="wrap_content"
  android:layout_margin="1dp">
     ...
  </TableRow>
</TableLayout>

1
注意这里故意超度绘制的问题,如果表格很大,可能会导致UI卡顿/受阻。 - Vicky Chijwani
如何在编程中为TableRow对象设置layout_margin - James Wierzba
它只是在表格和行周围添加了轮廓,但不在列之间添加。 - user924

41

如果您只是想在行之间插入一条线(例如,在“总计”行的上方),那么有一个简单的解决方案-只需添加具有背景颜色和特定layout_height的TableRow,如下所示:

<TableRow
   android:layout_width="match_parent"
   android:layout_height="1dp"
   android:background="#000000">
</TableRow>

<TableRow android:layout_height="1px" android:background="#BDBDBD">
   <TextView android:layout_span="2" android:layout_height="1px" 
             android:layout_width="fill_parent" android:text="">
   </TextView>
</TableRow>

设置android:layout_height="1px" 或者你需要的边框厚度。在空的TextView列中填充尽可能多的,以匹配表格的其余部分,或者只使用一个并像我演示的那样用android:layout_span

输出将类似于这样:

Table Border demonstrated

如果您试图添加更复杂的边框,则其他已发布的答案更合适。


为什么要使用TextView,而不是使用View呢?此外,指定精确像素并不是一个好的做法。应该使用dp/sp代替。参见这个帖子:https://dev59.com/A3I-5IYBdhLWcg3wEELu#2025541。 - Stephan
感谢反馈...我想没有必要使用TextView - 它只是一个例子。其次,除非我误解了dp/sp(实际上很可能,因为我只在Android上开发了一周),否则我使用px,因为我只想在我的行之间保证1像素的线条,无论我使用什么分辨率或屏幕尺寸。我喜欢非常细的线条。其他用户可能有不同的口味和使用其他单位。 - Michael Bray
是的,但你喜欢非常细的线条吗!- 话说好的简单解决方案得到我的支持。 - gheese

26

我想要的是这样的一张表格:

带有垂直分隔线的表格图片

我在我的 styles.xml 文件中添加了以下内容:

      <style name="Divider">
        <item name="android:layout_width">1dip</item>
        <item name="android:layout_height">match_parent</item>
        <item name="android:background">@color/divider_color</item>
    </style>

    <style name="Divider_invisible">
        <item name="android:layout_width">1dip</item>
        <item name="android:layout_height">match_parent</item>
    </style>

然后在我的表格布局中:

 <TableLayout
            android:id="@+id/table"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:orientation="horizontal"
            android:stretchColumns="*" >

            <TableRow
                android:id="@+id/tableRow1"
                android:layout_width="fill_parent"
                android:layout_height="match_parent"
                android:background="#92C94A" >

                <TextView
                    android:id="@+id/textView11"
                    android:paddingBottom="10dp"
                    android:paddingLeft="5dp"
                    android:paddingRight="5dp"
                    android:paddingTop="10dp" />

                <LinearLayout
                    android:layout_width="1dp"
                    android:layout_height="match_parent" >

                    <View style="@style/Divider_invisible" />
                </LinearLayout>

                <TextView
                    android:id="@+id/textView12"
                    android:paddingBottom="10dp"
                    android:paddingLeft="5dp"
                    android:paddingRight="5dp"
                    android:paddingTop="10dp"
                    android:text="@string/main_wo_colon"
                    android:textColor="@color/white"
                    android:textSize="16sp" />

                <LinearLayout
                    android:layout_width="1dp"
                    android:layout_height="match_parent" >

                    <View style="@style/Divider" />
                </LinearLayout>

                <TextView
                    android:id="@+id/textView13"
                    android:paddingBottom="10dp"
                    android:paddingLeft="5dp"
                    android:paddingRight="5dp"
                    android:paddingTop="10dp"
                    android:text="@string/side_wo_colon"
                    android:textColor="@color/white"
                    android:textSize="16sp" />

                <LinearLayout
                    android:layout_width="1dp"
                    android:layout_height="match_parent" >

                    <View style="@style/Divider" />
                </LinearLayout>

                <TextView
                    android:id="@+id/textView14"
                    android:paddingBottom="10dp"
                    android:paddingLeft="5dp"
                    android:paddingRight="5dp"
                    android:paddingTop="10dp"
                    android:text="@string/total"
                    android:textColor="@color/white"
                    android:textSize="16sp" />
            </TableRow>

            <!-- display this button in 3rd column via layout_column(zero based) -->

            <TableRow
                android:id="@+id/tableRow2"
                android:layout_width="match_parent"
                android:layout_height="match_parent"
                android:background="#6F9C33" >

                <TextView
                    android:id="@+id/textView21"
                    android:padding="5dp"
                    android:text="@string/servings"
                    android:textColor="@color/white"
                    android:textSize="16sp" />

                <LinearLayout
                    android:layout_width="1dp"
                    android:layout_height="match_parent" >

                    <View style="@style/Divider" />
                </LinearLayout>

..........
.......
......

25

您也可以通过编程的方式实现这一点,而不是通过xml,但这样有点“hackish”(意即:使用不正当手段)。但是如果给一个人没有选择的机会,那么他就没有选择了:p.. 以下是代码:

TableLayout table = new TableLayout(this);
TableRow tr = new TableRow(this);
tr.setBackgroundColor(Color.BLACK);
tr.setPadding(0, 0, 0, 2); //Border between rows

TableRow.LayoutParams llp = new TableRow.LayoutParams(LayoutParams.WRAP_CONTENT,LayoutParams.WRAP_CONTENT);
llp.setMargins(0, 0, 2, 0);//2px right-margin

//New Cell
LinearLayout cell = new LinearLayout(this);
cell.setBackgroundColor(Color.WHITE);
cell.setLayoutParams(llp);//2px border on the right for the cell


TextView tv = new TextView(this);
tv.setText("Some Text");
tv.setPadding(0, 0, 4, 3);

cell.addView(tv);
tr.addView(cell);
//add as many cells you want to a row, using the same approach

table.addView(tr);

16
为了在每个单元格周围创建1dp的折叠边框,而不编写Java代码并且不创建带有标签的xml布局,请尝试以下解决方案:
在中添加android:background ="#CCC"、android:paddingTop="1dp"和android:stretchColumns="0"
在中添加android:background ="#CCC"、android:paddingBottom="1dp"和android:paddingRight="1dp"
在TableRow中的每个单元格/子项中,即,添加android:background="#FFF"和android:layout_marginLeft ="1dp"
非常重要的是按照所述填充和边距进行操作。此解决方案将绘制1dp边框,即border-collapse属性在(X)HTML/CSS中。 和中的背景颜色表示边框线颜色,而中的背景则填充表格单元格。必要时可以为单元格添加一些填充。
这里有一个示例:
<TableLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="fill_parent"
    android:layout_height="wrap_content"
    android:background="#CCC"
    android:paddingTop="1dp"
    android:stretchColumns="0"
    android:id="@+id/tlTable01">

    <TableRow
        android:background="#CCC"
        android:paddingBottom="1dp"
        android:paddingRight="1dp">
        <TextView 
            android:layout_marginLeft="1dp"
            android:padding="5dp"
            android:background="#FFF"
            android:text="Item1"/>
        <TextView 
            android:layout_marginLeft="1dp"
            android:padding="5dp"
            android:background="#FFF"
            android:gravity="right"
            android:text="123456"/>
    </TableRow>
    <TableRow
        android:background="#CCC"
        android:paddingBottom="1dp"
        android:paddingRight="1dp">
        <TextView 
            android:layout_marginLeft="1dp"
            android:padding="5dp"
            android:background="#FFF"
            android:text="Item2"/>
        <TextView 
            android:layout_marginLeft="1dp"
            android:padding="5dp"
            android:background="#FFF"
            android:gravity="right"
            android:text="456789"/>
    </TableRow>
</TableLayout>

太棒了!谢谢! - superodde
这很好,但是当您想使用暗模式时会出现问题。因为您必须将 TableRow 背景设置为白色以获得白色边框。现在,当您的第二个 TextView 高度比第一个 TextView 更高时,第一个 TextView 后面会有白色背景。将第一个 TextView 的背景设置为黑色无济于事,因为它无法覆盖整个视图。 - Wiktor Kalinowski
1
这正是我在寻找的...谢谢。同时,@WiktorKalinowski所说的对于暗模式也是正确的,我们必须手动调整。 - Hi Ten

13

这里输入图片描述

我根据以下设计图设计了列表。我的listitem文件名为Propertylistitem.xml,并且在单元格边框输出中使用了可绘制形状的cellborder.xml,如此图所示。我已在此处添加了必要的代码。

文件名:propertylistitem.xml

<TableLayout... >
            <TableRow... >
                 <TextView ...
                    android:background="@drawable/cellborder"
                    android:text="Amount"/>
            </TableRow>

            <TableRow... >
                <TextView...
                    android:background="@drawable/cellborder"
                    android:text="5000"/>
            </TableRow>
        </TableLayout>

文件名: cellborder.xml 这里我只想在我的设计中使用边框,所以我注释掉了实色标签。

<?xml version="1.0" encoding="utf-8"?>
    <shape xmlns:android="http://schemas.android.com/apk/res/android" android:shape="rectangle" >
    <!--     <solid android:color="#dc6888"/>     -->
        <stroke android:width="0.1dp" android:color="#ffffff"
            />
        <padding android:left="0dp" android:top="0dp"
                android:right="0dp" android:bottom="0dp" />
    </shape>

10

嗯,这可能会激发您的灵感。这些步骤展示了动态创建带边框表格的方法。

以下是表格视图:

<android.support.v4.widget.NestedScrollView xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/nested_scroll_view"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:scrollbars="none"
    android:scrollingCache="true">
    <TableLayout xmlns:android="http://schemas.android.com/apk/res/android"
        android:id="@+id/simpleTableLayout"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_marginLeft="45dp"
        android:layout_marginRight="45dp"
        android:stretchColumns="*"
        >
    </TableLayout>
</android.support.v4.widget.NestedScrollView>

这里使用的是"attrib_row.xml"文件中的行。

<?xml version="1.0" encoding="utf-8"?>
<TableRow xmlns:android="http://schemas.android.com/apk/res/android"
    android:background="@drawable/border"
    >
    <TextView
        android:id="@+id/attrib_name"
        android:textStyle="bold"
        android:height="30dp"
        android:background="@drawable/border"
        android:gravity="center"
        />
    <TextView
        android:id="@+id/attrib_value"
        android:gravity="center"
        android:height="30dp"
        android:textStyle="bold"
        android:background="@drawable/border"
        />
</TableRow>

我们可以将这个xml文件添加到drawable中,以添加边框到我们的表格"border.xml"

<?xml version="1.0" encoding="utf-8"?>
<shape
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:shape= "rectangle">
    <solid android:color="@color/colorAccent"/>
    <stroke android:width="1dp" android:color="#000000"/>
</shape>

最后这是用Kotlin编写的紧凑代码,但如果需要,它很容易转换为Java。

好的,“temps”是一个包含数据的数组列表:ArrayList<Double>()

fun CreateTable()
{
    val temps=controller?.getTemps()
    val rowHead = LayoutInflater.from(context).inflate(R.layout.attrib_row, null) as TableRow
    (rowHead.findViewById<View>(R.id.attrib_name) as TextView).text=("time")
    (rowHead.findViewById<View>(R.id.attrib_value) as TextView).text=("Value")
    table!!.addView(rowHead)
    for (i in 0 until temps!!.size) {

        val row = LayoutInflater.from(context).inflate(R.layout.attrib_row, null) as TableRow
        (row.findViewById<View>(R.id.attrib_name) as TextView).text=((i+1).toString())
        (row.findViewById<View>(R.id.attrib_value) as TextView).text=(temps[i].toString())
        table!!.addView(row)
    }
    table!!.requestLayout()
}

你可以在你的片段中使用它,例如像这样:

   override fun onViewCreated(view: View?, savedInstanceState: Bundle?) {
        super.onViewCreated(view, savedInstanceState)
        table = view?.findViewById<View>(R.id.simpleTableLayout) as TableLayout
        CreateTable()
    }

最终结果看起来像这样 在此输入图片描述


10

经过长时间的搜索和尝试,这是我能做出来的最简单的代码:

ShapeDrawable border = new ShapeDrawable(new RectShape());
border.getPaint().setStyle(Style.STROKE);
border.getPaint().setColor(Color.BLACK);
tv.setBackground(border);
content.addView(tv);

tv是一个带有简单文本的TextView,content是我的容器(在这种情况下是LinearLayout)。 这样会稍微容易一些。


需要API级别16 :( - AndacAydin
可以使用setBackgroundDrawable()代替。 - Corey Wu

5
如何覆盖onDraw方法并在画布上绘制线条?
for(int i = 0; i < rows; i++)
    {
        canvas.drawLine(0, i * m_cellHeight, m_totalWidth, i * m_cellHeight, paint);
    }
    for(int i = 0; i < m_columns; i++){
        canvas.drawLine(i* m_cellWidth, 0, i * m_cellWidth, m_cellHeight * rows, paint);
    }

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