【Android開発】【改善版】タイトル行固定で複数列のリストを表示する方法

新作アプリ「こづかい帳」の開発を進める中で以前投稿した複数列のリストについて、機能改善を行ったので本日はそちらの共有です。

本対応の目的

基本的な内容は以前の投稿を参照ください。

今回の機能改善により、主に下記2点を実現しました。

  • リストデータを押下した際に対象の背景色を変更する。
  • リストデータを押下した際にリストに表示されていない情報も扱えるようにする。

サンプルコードを画面キャプチャするとこんな感じです。

[Android]タイトル行固定で複数列のリスト1

8/17の行をクリックすると行全体の色が反転します。

[Android]タイトル行固定で複数列のリスト2

そしてリスト上に表示されていない情報をToast表示します。

[Android]タイトル行固定で複数列のリスト3

layoutの準備

<?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"
    android:orientation="vertical" >
    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="horizontal" >
        <TextView
            android:id="@+id/title1"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:textSize="@dimen/sp_m"
            android:layout_weight="3"
            android:gravity="center"
            android:layout_marginRight="@dimen/dp_s"
            android:layout_marginBottom="@dimen/dp_s"
            android:padding="@dimen/dp_m"
            android:background ="@color/title"
            android:text="@string/title1"/>
        <TextView
            android:id="@+id/title2"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:textSize="@dimen/sp_m"
            android:layout_weight="2"
            android:gravity="center"
            android:layout_marginRight="@dimen/dp_s"
            android:layout_marginBottom="@dimen/dp_s"
            android:padding="@dimen/dp_m"
            android:background ="@color/title"
            android:text="@string/title2"/>
        <TextView
            android:id="@+id/title3"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:textSize="@dimen/sp_m"
            android:layout_weight="3"
            android:gravity="center"
            android:layout_marginBottom="@dimen/dp_s"
            android:padding="@dimen/dp_m"
            android:background ="@color/title"
            android:text="@string/title3"/>
    </LinearLayout>
    <ListView
        android:id="@+id/list"
        android:layout_width="match_parent"
        android:layout_height="0dp"
        android:layout_weight="1" />
</LinearLayout>

メインのレイアウトファイルは、ListViewのidを変更したのみです。

raw.xmlは前回のまま変更なしです。

drawableの準備

<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
    <item android:drawable="@android:color/transparent"
        android:state_selected="true"
        android:state_window_focused="false"/>
    <item android:drawable="@android:color/transparent"
        android:state_selected="true"/>
    <item android:drawable="@android:color/transparent"
        android:state_pressed="true"
        android:state_selected="false"/>
    <item android:drawable="@color/data1"
        android:state_selected="false"/>
</selector>
<?xml version="1.0" encoding="utf-8"?>
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
    <item android:drawable="@android:color/transparent"
        android:state_selected="true"
        android:state_window_focused="false"/>
    <item android:drawable="@android:color/transparent"
        android:state_selected="true"/>
    <item android:drawable="@android:color/transparent"
        android:state_pressed="true"
        android:state_selected="false"/>
    <item android:drawable="@color/data2"
        android:state_selected="false"/>
</selector>

今回新たに追加したファイルです。リストの背景色を通常時、押下時等に場合分けて定義しています。

valuesの準備

colors.xml、dimens.xml、string.xmlのいずれも前回のまま変更点はありません。

Java側の記載

package jp.co.skys.android.sample;

import android.app.Activity;
import android.content.Context;
import android.content.res.Resources;
import android.graphics.Typeface;
import android.os.Bundle;
import android.support.v4.content.res.ResourcesCompat;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.AdapterView;
import android.widget.BaseAdapter;
import android.widget.ListView;
import android.widget.TextView;
import android.widget.Toast;

import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Locale;

//Ver1からの変更点:ListActivity ⇒ Activityへ戻す
public class multipleRowListSample2 extends Activity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        // サンプル用のデータを準備
        List<Data> dataList = new ArrayList<>();

        // 現在時刻取得
        Date dt = new Date();
        long timestamp = dt.getTime();

        // サンプル用のデータを詰め込む
        for (int i = 0; i <= 100; i++) {
            Data data = new Data();
            data.setLongData(timestamp - 86400000 * (long) i);
            data.setStringData(String.valueOf(i) + ":abcdefghijklmnopqrstuvwxyz");
            data.setIntData(i * i * i);
            data.setHiddenData("hiddenData:"+String.valueOf(i));
            dataList.add(data);
        }

        /*Ver1からの変更点:リストを押下された場合の処理を追加
        ・押下したデータの背景色が変わる
        ・押下時にリストに表示されていない情報をToastで表示*/
        ListView listView = (ListView) findViewById(R.id.list);
        ListAdapter adapter = new ListAdapter(this, dataList);
        listView.setAdapter(adapter);
        listView.setChoiceMode(ListView.CHOICE_MODE_SINGLE);
        listView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
            @Override
            public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
                ListView listView = (ListView) parent;
                listView.setItemChecked(position, true);
                Data item = (Data) listView.getAdapter().getItem(position);
                Toast.makeText(parent.getContext(), item.getHiddenData(), Toast.LENGTH_LONG).show();
            }
        });
    }
}

// データ格納用クラス
class Data {
    private long longData;       //日付用
    private String stringData;  //文言用
    private int intData;        //数値用
    //Ver1からの変更点:画面上のリストには表示しないデータを追加
    private String hiddenData;

    public void setLongData(long tmp) {
        this.longData = tmp;
    }

    public long getLongData() {
        return longData;
    }

    public void setStringData(String tmp) {
        this.stringData = tmp;
    }

    public String getStringData() {
        return stringData;
    }

    public void setIntData(int tmp) {
        this.intData = tmp;
    }

    public long getIntData() {
        return intData;
    }

    public void setHiddenData(String tmp) {
        this.hiddenData = tmp;
    }

    public String getHiddenData() {
        return hiddenData;
    }
}

// LIST表示制御用クラス
//Ver1からの変更点:extends ArrayAdapter<Data> を extends BaseAdapterに変更
class ListAdapter extends BaseAdapter {
    private List<Data> list;
    private LayoutInflater inflater;
    private Resources r;
    public ListAdapter(Context context, List<Data> list) {
        super();
        this.list = list;
        inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
        r = context.getResources();
    }

    @Override
    public int getCount() {
        return list.size();
    }

    @Override
    public Object getItem(int position) {
        return list.get(position);
    }

    @Override
    public long getItemId(int position) {
        return position;
    }

    @Override
    public View getView(final int position, View view, ViewGroup parent) {
        // layout/raw.xmlを紐付ける
        if (view == null) view = inflater.inflate(R.layout.raw, null);
        Data data = (Data) getItem(position);
        TextView tvData1 = (TextView) view.findViewById(R.id.raw1);
        TextView tvData2 = (TextView) view.findViewById(R.id.raw2);
        TextView tvData3 = (TextView) view.findViewById(R.id.raw3);
        if (data != null) {
            SimpleDateFormat ymd = new SimpleDateFormat("MM/dd", Locale.JAPANESE);
            tvData1.setText(ymd.format(data.getLongData()));
            tvData2.setText(data.getStringData());
            tvData3.setText(String.format("%1$,3d", data.getIntData()));
        }
        //Ver1からの変更点:固定幅のフォントに設定
        tvData2.setTypeface(Typeface.MONOSPACE);

        // 条件によってリストアイテムの背景色を変更
        if(position%2 == 0) {
        /*Ver1からの変更点:colorを指定するのではなく、drawable配下のdata1.xml、data2.xmlを指定。
        minSdkVersionを16以上とする必要あり。*/
            tvData1.setBackground(ResourcesCompat.getDrawable(r, R.drawable.data1, null));
            tvData2.setBackground(ResourcesCompat.getDrawable(r, R.drawable.data1, null));
            tvData3.setBackground(ResourcesCompat.getDrawable(r, R.drawable.data1, null));
        }else{
            tvData1.setBackground(ResourcesCompat.getDrawable(r, R.drawable.data2, null));
            tvData2.setBackground(ResourcesCompat.getDrawable(r, R.drawable.data2, null));
            tvData3.setBackground(ResourcesCompat.getDrawable(r, R.drawable.data2, null));
        }

        return view;
    }
}

主な変更点は、ソース内のコメントにてご確認ください。

最後に

上記一式含まれるファイルを下記よりダウンロードできます。

multipleRowListSample2.zip

良かったらご参考まで

サブコンテンツ

このページの先頭へ