Androidで、WindowsのGridVew的な表示(HTMLでいうTable)を行う方法が、他記事にあまり見られなかったのでレポートします。他に良い方法があるのかもしれません …
要点
- TableLayout、TableRow、TextView を使う。
- データ部はプログラムコードにて生成する。
- ヘッダ部とデータ部で列幅は合せてくれない。
- ヘッダ部の列幅の取得はうまくいかないため、データ部列幅は現物合せするしかない。
- スクロールするには、ヘッダ用とデータ部用で TableLayout を分け、データ部用をScrollViewに載せる。
- 格子線の描画はうまく行かなかった。res/drawable/*.xml に android:width=”1dp” を記述しても Table全体の外枠しか描画されず。
レイアウト
図にすると以下のように構成します。

xmlの記述例は、
<!-- データ部。高さはmatch_parentとする -->
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingLeft="16dp"
android:paddingRight="16dp"
android:orientation="vertical" >
<!-- 表題 -->
<TextView
android:id="@+id/editTextTextPersonName"
android:layout_width="match_parent"
android:layout_height="32dp"
android:layout_marginTop="1dp"
android:gravity="center"
android:text="CAN Frames View"
android:textSize="20sp"
android:visibility="visible"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="1.0"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<!-- ヘッダ部。高さを固定にする -->
<TableLayout
android:id="@+id/tblCANFramesHead"
android:layout_width="match_parent"
android:layout_height="35dp"
android:layout_marginStart="1dp"
android:layout_marginEnd="1dp"
android:layout_marginBottom="1dp"
android:gravity="top|left"
android:padding="5dip"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent">
<TableRow android:id="@+id/viewHeader">
<TextView
android:layout_weight="2"
android:gravity="center_horizontal|center_vertical"
android:padding="1dip"
android:text="ID" />
<TextView
android:layout_weight="4"
android:gravity="center_horizontal|center_vertical"
android:padding="1dip"
android:text="TIME" />
・・・中略・・・
</TableRow>
</TableLayout>
<!-- データ部。高さはmatch_parentとする -->
<ScrollView
android:id="@+id/srcView"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_marginStart="8dp"
android:layout_marginLeft="8dp"
android:layout_marginEnd="8dp"
android:layout_marginRight="8dp"
android:layout_marginBottom="76dp"
android:scrollbars="vertical"
app:layout_constraintBottom_toTopOf="@+id/tblCANFrames"
app:layout_constraintEnd_toEndOf="@+id/tblCANFrames"
app:layout_constraintHorizontal_bias="1.0">
<TableLayout
android:id="@+id/tblCANFrames"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_marginStart="1dp"
android:layout_marginEnd="1dp"
android:layout_marginBottom="1dp"
android:gravity="top|left"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent">
<!-- ダミーData部 無いとコケる -->
<TableRow android:id="@+id/viewData" >
<TextView
android:layout_weight="2"
android:gravity="center_horizontal|center_vertical"
android:padding="1dip" />
<TextView
android:layout_weight="4"
android:gravity="center_horizontal|center_vertical"
android:padding="1dip" />
・・・中略・・・
</TableRow>
</TableLayout>
</ScrollView>
</LinearLayout>
データ部生成
セル一つづつ生成していきます。ダミーデータ行は最後に削除します。以下コードです。
TableLayout frameTbl = this.findViewById(R.id.tblCANFrames);
for (int i = 1; i <= 64 ; i++) {
TableRow tblRow = new TableRow(this);
// CAN-ID
TextView viewId = new TextView(this);
viewId.setText("000");
tblRow.addView(viewId, 0);
・・・中略・・・
// DATA
for (int j = 0, k = 3; j < CAN_DATA_BYTE_NUM; j ++, k ++) {
TextView viewDat = new TextView(this);
viewDat.setText("00");
tblRow.addView(viewDat, k);
}
frameTbl.addView(tblRow, i ); // 行追加、Heightき変更不要
}
// ダミーデータを削除。
// ※removeAllするとコケる。TableRow無しのTableLayoutをつくるとコケる。
frameTbl.removeViewAt(0);
細部の調整
列幅は setPadding で以下のように調整します。
// CAN-ID
TextView viewId = new TextView(this);
viewId.setText("000");
viewId.setPadding(5,0,5,0); // <- 列幅調整
tblRow.addView(viewId, 0);
Wordwrapが効いて複数行になってしまう列は、行数を強制します。
// 受信TIME
TextView viewTim = new TextView(this);
viewTim.setText("00000000");
viewTim.setLines(1); // <- 1行に強制する
viewTim.setBackgroundColor( bgclr[i%2] );
tblRow.addView(viewTim, 1);
格子線描画はうまく行かないため、代わりに見易くするため1行毎に色替えします。
// 一行を見やすくするため交互に色替え。
int[] bgclr = new int[2];
bgclr[0] = Color.rgb(0xFF,0xFF, 0x88);
bgclr[1] = Color.rgb(0x88,0xFF, 0xFF);
for (int i = 1; i <= CAN_FRAME_MAX_NUM ; i++) {
TableRow tblRow = new TableRow(this);
// CAN-ID
TextView viewId = new TextView(this);
viewId.setText("000");
viewId.setPadding(5,0,5,0);
viewId.setBackgroundColor( bgclr[i%2] ); // <-- 1行毎に色替え
tblRow.addView(viewId, 0);
・・・後略・・・
レイアウト実行結果
レイアウトのみの実行結果です。
