現在、自作地図アプリでは、バス時刻表および歩数計の結果を GridLayout を使って、表形式でポップアップ表示している。 それなりの行数がかかっているので、もう少し、スリム化したいと思っている。
GridView、ListView でも表形式の表示が可能である。ここでは、ListView による方法を述べる。
総行数としては、Gridlayoutと大差ないが、ListViewの方が構造化されるので、分かりやすい。
プログラム完成後の地図アプリ画面を下に示す。PopupWindow を使っている。
現在は、日々の歩数グラフ、月平均歩数グラフ、SQLiteテーブルを切り替えて表示する。

表示するものにより、行フォーマットは異なる。月平均グラフの場合を以下に示す。 android:maxLines="1" は無くてもいいはず。
[listview_monthly.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">
<TextView
android:id="@+id/date"
android:layout_width="100dp"
android:layout_height="26dp"
android:textColor="#000"
android:background="#eee"
android:padding="2dp"
android:gravity="center"
android:maxLines="1"/>
<TextView
android:id="@+id/steps"
android:layout_width="60dp"
android:layout_height="26dp"
android:textColor="#000"
android:padding="2dp"
android:gravity="end"
android:maxLines="1"/>
<ImageView
android:id="@+id/bar_chart"
android:layout_width="match_parent"
android:layout_height="26dp"
android:gravity="start"
android:padding="2dp" />
</LinearLayout>
1行分のデータ管理クラスは共通である。名称は任意である。ここでは ListItem とした。
Bitmap bar_chart は日々の歩数と月平均歩数で使う。
地図アプリのデバッグは Androidタブレットで行っている。 スマホ(Map.fSP が true)とはサイズが異なる。
public class ListItem {
private final String date;
private final int isteps;
private final String steps;
private String shutdown_steps;
private Bitmap bar_chart;
public ListItem(int idate, int isteps) {
this.date = String.valueOf(idate);
this.isteps = isteps;
this.steps = String.valueOf(isteps);
}
public ListItem(int idate, int isteps, int shutdown_steps) {
this(idate, isteps);
this.shutdown_steps = String.valueOf(shutdown_steps);
this.bar_chart = null;
}
String getDate() {
return date;
}
String getSteps() {
return steps;
}
String getShutdownSteps() {
return shutdown_steps;
}
Bitmap getBarChart() {
if (bar_chart != null) {
return bar_chart;
}
int w = Map.fSP ? 780 : 600;
int h = Map.fSP ? 70 : 34;
bar_chart = Bitmap.createBitmap(w, h, Bitmap.Config.ARGB_8888);
Canvas canvas = new Canvas(bar_chart);
Paint paint = new Paint();
paint.setColor(Color.BLACK);
float top = Map.fSP ? 18 : 10;
float right = isteps*0.08f * (Map.fSP ? 0.7f : 0.6f);
canvas.drawRect(0, top, right, h-top, paint);
return bar_chart;
}
}
他の方法もあるが、今回は ArrayAdapter を使った。
リストビューに表示する行要素を取得する。
public class ListAdapter extends ArrayAdapter<ListItem> {
private final int mResource;
private final List<ListItem> mItems;
private final LayoutInflater mInflater;
public ListAdapter(Context context, int resource, List<ListItem> items) {
super(context, resource, items);
mResource = resource;
mItems = items;
mInflater = (LayoutInflater)context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
View view = convertView != null ? convertView : mInflater.inflate(mResource, null);
// リストビューに表示する要素を取得
ListItem item = mItems.get(position);
TextView date = (TextView) view.findViewById(R.id.date);
date.setText(item.getDate()); // 日付
TextView steps = (TextView) view.findViewById(R.id.steps);
steps.setText(item.getSteps()); // 歩数
if (item.getShutdownSteps() == null) {
ImageView barChart = (ImageView) view.findViewById(R.id.bar_chart);
barChart.setImageBitmap(item.getBarChart()); // 棒グラフ
} else { // 歩数計テーブル
TextView shutdown_steps = (TextView) view.findViewById(R.id.shutdown_steps);
shutdown_steps.setText(item.getShutdownSteps()); // shutdown時の累積歩数
}
return view;
}
}
PopupWindowでの XMLスタイルファイルの使用経験がないため、コードを使った。
SQLiteを使う class Pedometer および月平均算出プログラムを含めると 全体のプログラム行数は相当な行数となる。しかし、構造化されているので、 メンテナンスはしやすい。
public class PopupListView extends PopupWindow {
final int LMP = LinearLayout.LayoutParams.MATCH_PARENT;
final int LWC = LinearLayout.LayoutParams.WRAP_CONTENT;
Context context;
Button[] btns;
static int lastSelected = 0;
ListView listView = null;
public PopupListView(Context context) {
this(context, new String[]{"日々の歩数", "月平均歩数", "DBテーブル"});
}
public PopupListView(Context context, String[] str_btns) {
super(Map.fSP ? 1100 : 700, Map.fSP ? 935 : 500);
this.context = context;
// 全体のレイアウト
LinearLayout layout = new LinearLayout(context);
layout.setOrientation(LinearLayout.VERTICAL);
layout.setLayoutParams(new LinearLayout.LayoutParams(LMP, LMP));
layout.setBackgroundColor(Color.WHITE);
setContentView(layout);
// ボタン列のレイアウト
LinearLayout button_layout = new LinearLayout(context);
button_layout.setOrientation(LinearLayout.HORIZONTAL);
button_layout.setLayoutParams(new LinearLayout.LayoutParams(LWC, Map.fSP ? 80 : 40));
layout.addView(button_layout);
btns = new Button[str_btns.length];
for (int n = 0; n < btns.length; n++) {
btns[n] = new Button(context);
btns[n].setWidth((Map.fSP ? 1100 : 600)/4);
btns[n].setId(n);
btns[n].setText(str_btns[n]);
btns[n].setPadding(0,0,0,0);
btns[n].setOnClickListener(v -> select(v.getId(), layout));
btns[n].setBackgroundColor(n==lastSelected ? 0xff33ffff : 0xffdddddd);
button_layout.addView(btns[n]);
}
select(lastSelected, layout);
}
void select(int id, LinearLayout layout) {
for (int n = 0; n < btns.length; n++) {
btns[n].setBackgroundColor(n==id ? 0xff33ffff : 0xffdddddd);
}
lastSelected = id;
if (listView != null) {
layout.removeView(listView); // 旧ListViewを削除
}
listView = new ListView(context);
layout.addView(listView);
ArrayList<ListItem> listItems = new ArrayList<>();
int listitemLayout;
if (id == 0) { // 日々の歩数
int[][] data = new Pedometer(context).getRecordDesc(32);
for (int i = 0; i < data.length - 1; i++) {
int steps = data[i][1] - data[i + 1][1] + data[i][2];
ListItem item = new ListItem(data[i][0], steps);
listItems.add(item);
}
listitemLayout = R.layout.listview_daily;
} else if (id == 1) { // 月平均
MonthlyAverage[] ma = monthlyAverage();
for (int i = ma.length-1; i >= 0; i--) {
ListItem item = new ListItem(ma[i].yyyymm, ma[i].steps);
listItems.add(item);
}
listitemLayout = R.layout.listview_monthly;
} else { // id == 2, データベース・テーブル
int[][] data = new Pedometer(context).getRecordDesc(-1);
for (int[] datum : data) {
ListItem item = new ListItem(datum[0], datum[1], datum[2]);
listItems.add(item);
}
listitemLayout = R.layout.listview_pedometer;
}
// 出力結果をリストビューに表示
ListAdapter adapter = new ListAdapter(context, listitemLayout, listItems);
listView.setAdapter(adapter);
}