こんにちは、せのり(@senoriblog)です!
今回はAndroidでテーブルに動的に行を追加する方法を紹介します。
テーブル(TableLayout)の行数を動的に変更したい、という場面がちょくちょくあると思います。
例えば、以下のようなデータベースの検索結果を、、
No | Name | Position | Birth |
11 | 小笠原 慎之介 | 投手 | 1997/10/8 |
12 | 田島 慎二 | 投手 | 1989/12/21 |
13 | 橋本 侑樹 | 投手 | 1998/1/8 |
14 | 谷元 圭介 | 投手 | 1985/1/28 |
こんな感じに表示したいときなど。
予めデータ件数が分かっていなくても、
件数に合わせて自動的に行を追加するプログラムを紹介します。
この記事ではコピペで使えるようにコードをまとめました。
上記の内容で解説します。 それでは、順番にみていきましょう。
TableLayoutとは
マス目、格子状に区切って表形式でデータや画像等を表示したいときに使用します。
HTML の table タグのようなイメージです。
表の行数、列数が固定の場合は、レイアウトファイル(XML)にそのまま表示したい内容を記載すれば良いですが、
データベースからデータを検索して取得結果を画面に表示したいときなど、
表示する件数が事前に分からないケースは XML には固定で書けないので、
Java で動的に行を追加する必要があります。
【コード】重複データを削除する方法
ということで、その記述は以下の通り。
まずは、MainActivity.java のコードから。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 |
public void loadData() { int leftRowMargin=0; int topRowMargin=0; int rightRowMargin=0; int bottomRowMargin = 0; int textSize = 0, smallTextSize =0, mediumTextSize = 0; textSize = (int) getResources().getDimension(R.dimen.font_size_verysmall); smallTextSize = (int) getResources().getDimension(R.dimen.font_size_small); mediumTextSize = (int) getResources().getDimension(R.dimen.font_size_medium); Player players = new Player(); PlayerData[] data = players.getPlayers(); int rows = data.length; getSupportActionBar().setTitle("Players (" + String.valueOf(rows) + ")"); TextView textSpacer = null; mTableLayout.removeAllViews(); // -1 はヘッダー行 for(int i = -1; i < rows; i ++) { PlayerData row = null; if (i > -1) row = data[i]; else { textSpacer = new TextView(this); textSpacer.setText(""); } // 1列目(No) final TextView tv = new TextView(this); tv.setLayoutParams(new TableRow.LayoutParams(TableRow.LayoutParams.WRAP_CONTENT, TableRow.LayoutParams.WRAP_CONTENT)); tv.setGravity(Gravity.LEFT); tv.setPadding(5, 15, 0, 15); if (i == -1) { tv.setText("No"); tv.setBackgroundColor(Color.parseColor("#f0f0f0")); tv.setTextSize(TypedValue.COMPLEX_UNIT_PX, smallTextSize); } else { tv.setText(String.valueOf(row.getNo())); tv.setTextSize(TypedValue.COMPLEX_UNIT_PX, textSize); } // 2列目(Name) final TextView tv2 = new TextView(this); tv2.setLayoutParams(new TableRow.LayoutParams(TableRow.LayoutParams.WRAP_CONTENT, TableRow.LayoutParams.WRAP_CONTENT)); tv2.setGravity(Gravity.LEFT); tv2.setPadding(5, 15, 0, 15); if (i == -1) { tv2.setText("Name"); tv2.setBackgroundColor(Color.parseColor("#f0f0f0")); tv2.setTextSize(TypedValue.COMPLEX_UNIT_PX, smallTextSize); } else { tv2.setText(row.getName()); } // 3列目(Position) final TextView tv3 = new TextView(this); tv3.setLayoutParams(new TableRow.LayoutParams(TableRow.LayoutParams.WRAP_CONTENT, TableRow.LayoutParams.WRAP_CONTENT)); tv3.setGravity(Gravity.LEFT); tv3.setPadding(5, 15, 0, 15); if (i == -1) { tv3.setText("Position"); tv3.setBackgroundColor(Color.parseColor("#f0f0f0")); tv3.setTextSize(TypedValue.COMPLEX_UNIT_PX, smallTextSize); } else { tv3.setTextSize(TypedValue.COMPLEX_UNIT_PX, textSize); tv3.setText(row.getPosition()); } // 4列目(Birth) final TextView tv4 = new TextView(this); tv4.setLayoutParams(new TableRow.LayoutParams(TableRow.LayoutParams.WRAP_CONTENT, TableRow.LayoutParams.WRAP_CONTENT)); tv4.setGravity(Gravity.LEFT); tv4.setPadding(5, 15, 0, 15); if (i == -1) { tv4.setText("Birth"); tv4.setBackgroundColor(Color.parseColor("#f0f0f0")); tv4.setTextSize(TypedValue.COMPLEX_UNIT_PX, smallTextSize); } else { tv4.setText(new SimpleDateFormat("yyyy/MM/dd", Locale.JAPAN).format(row.getBirth())); tv4.setTextSize(TypedValue.COMPLEX_UNIT_PX, textSize); } // テーブルに行を追加 final TableRow tr = new TableRow(this); tr.setId(i + 1); TableLayout.LayoutParams trParams = new TableLayout.LayoutParams(TableLayout.LayoutParams.MATCH_PARENT, TableLayout.LayoutParams.WRAP_CONTENT); trParams.setMargins(leftRowMargin, topRowMargin, rightRowMargin, bottomRowMargin); tr.setPadding(0,0,0,0); tr.setLayoutParams(trParams); tr.addView(tv); tr.addView(tv2); tr.addView(tv3); tr.addView(tv4); mTableLayout.addView(tr, trParams); // 罫線を追加 if (i > -1) { final TableRow trSep = new TableRow(this); TableLayout.LayoutParams trParamsSep = new TableLayout.LayoutParams(TableLayout.LayoutParams.MATCH_PARENT, TableLayout.LayoutParams.WRAP_CONTENT); trParamsSep.setMargins(leftRowMargin, topRowMargin, rightRowMargin, bottomRowMargin); trSep.setLayoutParams(trParamsSep); TextView tvSep = new TextView(this); TableRow.LayoutParams tvSepLay = new TableRow.LayoutParams(TableRow.LayoutParams.MATCH_PARENT, TableRow.LayoutParams.WRAP_CONTENT); tvSepLay.span = 4; tvSep.setLayoutParams(tvSepLay); tvSep.setBackgroundColor(Color.parseColor("#d9d9d9")); tvSep.setHeight(1); trSep.addView(tvSep); mTableLayout.addView(trSep, trParamsSep); } } } |
17行目のfor
が行(データ数)のループで、
25~87行目で列ごとにセルの値や文字サイズ等を設定しています。
今回は4列あるので、変数tv1
tv2
tv3
tv4
を宣言しています。
97~100行目で変数tr
に1行分のデータを入れて、
101行目で変数mTableLayout
にtr
を入れています。
次は、activity_main.xml のコードです。
25行目のTableLayout
が行を動的に追加しているテーブルです。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 |
xml version="1.0" encoding="utf-8"?> <androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" tools:context=".MainActivity"> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" xmlns:app="http://schemas.android.com/apk/res-auto" android:layout_width="match_parent" android:layout_height="match_parent" android:paddingBottom="@dimen/activity_vertical_margin" android:paddingLeft="@dimen/activity_horizontal_margin" android:paddingRight="@dimen/activity_horizontal_margin" android:paddingTop="@dimen/activity_vertical_margin" android:orientation="vertical" android:id="@+id/players_layout" tools:context=".MainActivity"> <ScrollView android:layout_width="match_parent" android:layout_height="match_parent" > <TableLayout android:id="@+id/tablePlayers" android:layout_width="match_parent" android:layout_height="match_parent" android:padding="0dp" android:stretchColumns="*"> </TableLayout> </ScrollView> </LinearLayout> </androidx.constraintlayout.widget.ConstraintLayout> |
次は、テーブルにセットするデータを保持する Model クラスです。
今回の主旨とはあまり関係ないですが参考までに掲載します。
今回は Player.java に固定値でデータを記載していますが、
本来はデータベースから取得したデータを保持するプログラムとなります。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 |
package com.example.tablelayoutsample; import java.util.Date; public class PlayerData { private int _no; private String _name; private String _position; private Date _birth; public PlayerData( int no, String name, String position, Date birth) { _no = no; _name = name; _position = position; _birth = birth; } public int getNo() { return _no; } public String getName() { return _name; } public String getPosition() { return _position; } public Date getBirth() { return _birth; } } |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 |
package com.example.tablelayoutsample; import java.util.Date; public class Player { public PlayerData[] getPlayers() { PlayerData[] data = new PlayerData[30]; data[0] = new PlayerData(11,"小笠原 慎之介","投手",new Date(97,10,8)); data[1] = new PlayerData(12,"田島 慎二","投手",new Date(89,12,21)); data[2] = new PlayerData(13,"橋本 侑樹","投手",new Date(98,1,8)); data[3] = new PlayerData(14,"谷元 圭介","投手",new Date(85,1,28)); data[4] = new PlayerData(16,"又吉 克樹","投手",new Date(90,11,4)); data[5] = new PlayerData(17,"柳 裕也","投手",new Date(94,4,22)); data[6] = new PlayerData(18,"梅津 晃大","投手",new Date(96,10,24)); data[7] = new PlayerData(19,"髙橋 宏斗","投手",new Date(102,8,9)); data[8] = new PlayerData(21,"岡田 俊哉","投手",new Date(91,12,5)); data[9] = new PlayerData(22,"大野 雄大","投手",new Date(88,9,26)); data[10] = new PlayerData(24,"福谷 浩司","投手",new Date(91,1,9)); data[11] = new PlayerData(25,"佐藤 優","投手",new Date(93,6,29)); data[12] = new PlayerData(28,"森 博人","投手",new Date(98,5,25)); data[13] = new PlayerData(29,"山井 大介","投手",new Date(78,5,10)); data[14] = new PlayerData(33,"祖父江 大輔","投手",new Date(87,8,11)); data[15] = new PlayerData(34,"福 敬登","投手",new Date(92,6,16)); data[16] = new PlayerData(36,"岡野 祐一郎","投手",new Date(94,4,16)); data[17] = new PlayerData(38,"松葉 貴大","投手",new Date(90,8,14)); data[18] = new PlayerData(40,"石川 翔","投手",new Date(99,12,14)); data[19] = new PlayerData(41,"勝野 昌慶","投手",new Date(97,6,12)); data[20] = new PlayerData(42,"ロサリオ","投手",new Date(94,5,18)); data[21] = new PlayerData(43,"三ツ間 卓也","投手",new Date(92,7,22)); data[22] = new PlayerData(46,"鈴木 博志","投手",new Date(97,3,22)); data[23] = new PlayerData(47,"笠原 祥太郎","投手",new Date(95,3,17)); data[24] = new PlayerData(50,"清水 達也","投手",new Date(99,11,3)); data[25] = new PlayerData(53,"マルク","投手",new Date(95,7,18)); data[26] = new PlayerData(54,"藤嶋 健人","投手",new Date(98,5,8)); data[27] = new PlayerData(59,"山本 拓実","投手",new Date(100,1,31)); data[28] = new PlayerData(64,"福島 章太","投手",new Date(102,10,24)); data[29] = new PlayerData(65,"加藤 翼","投手",new Date(102,12,14)); return data; } } |
【解説】どういう処理をしているのか
処理の全体の流れとしては、
- セル(TextView)にデータを格納
- 1を列の数だけ繰り返す
- 行(TableRow)にセル(TextView)を追加
- テーブル(TableLayout)に行(TableRow)を追加
- 1~4を行の数だけ繰り返す
となります。
1.セル(TextView)にデータを格納
MainActivity.java の以下のコードでセルにデータを格納しています。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
// 1列目(No) final TextView tv = new TextView(this); tv.setLayoutParams(new TableRow.LayoutParams(TableRow.LayoutParams.WRAP_CONTENT, TableRow.LayoutParams.WRAP_CONTENT)); tv.setGravity(Gravity.LEFT); tv.setPadding(5, 15, 0, 15); if (i == -1) { tv.setText("No"); tv.setBackgroundColor(Color.parseColor("#f0f0f0")); tv.setTextSize(TypedValue.COMPLEX_UNIT_PX, smallTextSize); } else { tv.setText(String.valueOf(row.getNo())); tv.setTextSize(TypedValue.COMPLEX_UNIT_PX, textSize); } |
2行目で1列目のセルの変数を宣言しています。
final TextView tv = new TextView(this);
14行目のsetText()
でセルに表示する値を設定しています。
今回は4列のテーブルなので、「セル(TextView)にデータを格納」を4回繰り返しました。
列を増やしたい場合は上記プログラムを追加してください。
また、i == -1
の場合はテーブルのヘッダー行を作成しています。
行(TableRow)にセル(TextView)を追加
テーブル(TableLayout)に行(TableRow)を追加
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
// テーブルに行を追加 final TableRow tr = new TableRow(this); tr.setId(i + 1); TableLayout.LayoutParams trParams = new TableLayout.LayoutParams(TableLayout.LayoutParams.MATCH_PARENT, TableLayout.LayoutParams.WRAP_CONTENT); trParams.setMargins(leftRowMargin, topRowMargin, rightRowMargin, bottomRowMargin); tr.setPadding(0,0,0,0); tr.setLayoutParams(trParams); tr.addView(tv); tr.addView(tv2); tr.addView(tv3); tr.addView(tv4); mTableLayout.addView(tr, trParams); |
2行目で行の変数を宣言しています。
final TableRow tr = new TableRow(this);
10~13行目のaddView(tv)
でセルを行の変数に詰めています。
14行目でテーブルに行の変数を詰めています。
mTableLayout.addView(tr, trParams);
これをデータの行数分繰り返し行います。
最終的にmTableLayout
に全ての行の変数が詰め込まれると、
テーブルへのデータ格納が完了です。
以下のレポジトリにソースコードをアップしてあります。