現在、自作地図アプリでは、バス時刻表および歩数計の結果を 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); }