トップAndroid Java > ListViewの使い方

ListViewの使い方

はじめに

現在、自作地図アプリでは、バス時刻表および歩数計の結果を GridLayout を使って、表形式でポップアップ表示している。 それなりの行数がかかっているので、もう少し、スリム化したいと思っている。

GridView、ListView でも表形式の表示が可能である。ここでは、ListView による方法を述べる。

総行数としては、Gridlayoutと大差ないが、ListViewの方が構造化されるので、分かりやすい。

歩数計グラフ

プログラム完成後の地図アプリ画面を下に示す。PopupWindow を使っている。

現在は、日々の歩数グラフ、月平均歩数グラフ、SQLiteテーブルを切り替えて表示する。

1行分のレイアウト

表示するものにより、行フォーマットは異なる。月平均グラフの場合を以下に示す。 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行分のデータ管理クラス

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

他の方法もあるが、今回は 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

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);
    }

リファレンス

[1] Androidでリストビュー(ListView)をカスタムして表示する