LoginSignup
5
9

More than 5 years have passed since last update.

Android開発のリストビューについてまとめて見た

Posted at

はじめに

こんにちは。某学校でプログラミング等の勉強中のサーバーサイドのプログラマーのワタタクです。:relaxed:
今回もAndroid開発していきましょう。
Androidには様々なリストビューの出し方があるので、筆者自身も混乱してきたので魔と寝ていきたいと思います。

対象者

  • Javaがなんとなく書ける人。
  • Android開発が曖昧だけど多少できる人。 

リストビューの基本

リストタップのリスナ

○リストビューをタップした時のリスナクラス : onItemClickListenerインタフェースを実装する。
*このインタフェースはAdapterViewクラスのメンバインタフェース
○リスト設定メソッド

setOnItemClickListener(onItemClickListenerを実装したメンバインタフェースを実装したものを入れる)

タップ要素の取得

1)イベントハンドラ : onItemClick()
引数は4つ

1.AdapterView<?> parent 
->タップされたListView全体

2.View view
->タップされた1行分の画面部品

3.int position
->タップされた行番号 
*0から始まる

4.long id
->DBのデータをもとにListViewを生成した際の主キーの値
*DBを使わない場合は上のpositionと同じ値

2)データ取得
○タップした行のデータはparentとpositionを使って取得できる

(String)parent.getItemAtPosition(position)

サンプルコード


private class ListItemClickListener implements AdapterView.OnItemClickListener {
    public void onItemClick(AdapterView<?> parent, View view, int position, long l) {
        String item = (String)parent.getItemAtPosition(position);
        Toast.makeText(ListClickSampleActivity.this, show, Toast.LENGTH_SHORT).show();
    }
}

静的のリストビュー

1) xmlで作る

activity_list_click_sample.xml
<?xml version="1.0" encoding="utf-8"?>
<ListView
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/lvMenu"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:entries="@array/lv_menu"/>
string.xml
<?xml version="1.0" encoding="UTF-8" ?>
<resources>
    <string name="app_name">リスト選択サンプル</string>
    <string-array name="lv_menu">
        <item>唐揚げ</item>
        <item>ハンバーグ定食</item>
        <item>生姜焼き定食</item>
        <item>ステーキ定食</item>
        <item>野菜炒め定食</item>
        <item>回鍋肉定食</item>
        <item>麻婆豆腐定食</item>
        <item>とんかつ定食</item>
        <item>ミンチカツ定食</item>
        <item>チキンかつ定食</item>
        <item>コロッケ定食</item>
        <item>焼き魚定食</item>
        <item>焼肉定食</item>
        <item>弱肉強食</item>
    </string-array>
</resources>
ListClickSampleActivity.java
public class ListClickSampleActivity extends AppCompatActivity {

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

        ListView lvMenu = findViewById(R.id.lvMenu);
        lvMenu.setOnItemClickListener(ListItemClickListener);

    }

    AdapterView.OnItemClickListener ListItemClickListener = new AdapterView.OnItemClickListener() {
        @Override
        public void onItemClick(AdapterView<?> parent, View view, int position, long l) {
            String item = (String)parent.getItemAtPosition(position);
            String show = "あなたが選んだ定食:" + item;
            Toast.makeText(ListClickSampleActivity.this, show, Toast.LENGTH_SHORT).show();
        }
    };
}

2)Javaコードで作る

<?xml version="1.0" encoding="utf-8"?>
<ListView
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/lvPref"
    android:layout_width="match_parent"
    android:layout_height="match_parent">
</ListView>
PrefListActivity.java
public class PrefListActivity extends AppCompatActivity {
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_pref_list);

        ListView lvPref = findViewById(R.id.lvPref);

        List<String> prefList = createPrefectureList();
        ArrayAdapter<String> adapter = new ArrayAdapter<>(PrefListActivity.this, android.R.layout.simple_list_item_1, prefList);
        lvPref.setAdapter(adapter);

        lvPref.setOnItemClickListener(new ListItemClickListener());
    }

    /**
     * 都道府県リストを生成するメソッド。
     * @return 都道府県リストオブジェクト。
     */
    private List<String> createPrefectureList() {
        List<String> prefList = new ArrayList<>();
        prefList.add("北海道");
        prefList.add("青森県");
        prefList.add("岩手県");
        prefList.add("宮城県");
        prefList.add("秋田県");
        prefList.add("山形県");
        prefList.add("福島県");
        prefList.add("茨城県");
        prefList.add("栃木県");
        prefList.add("群馬県");
        prefList.add("埼玉県");
        prefList.add("千葉県");
        prefList.add("東京都");
        prefList.add("神奈川県");
        prefList.add("新潟県");
        prefList.add("富山県");
        prefList.add("石川県");
        prefList.add("福井県");
        prefList.add("山梨県");
        prefList.add("長野県");
        prefList.add("岐阜県");
        prefList.add("静岡県");
        prefList.add("愛知県");
        prefList.add("三重県");
        prefList.add("滋賀県");
        prefList.add("京都府");
        prefList.add("大阪府");
        prefList.add("兵庫県");
        prefList.add("奈良県");
        prefList.add("和歌山県");
        prefList.add("鳥取県");
        prefList.add("島根県");
        prefList.add("岡山県");
        prefList.add("広島県");
        prefList.add("山口県");
        prefList.add("徳島県");
        prefList.add("香川県");
        prefList.add("愛媛県");
        prefList.add("高知県");
        prefList.add("福岡県");
        prefList.add("佐賀県");
        prefList.add("長崎県");
        prefList.add("熊本県");
        prefList.add("大分県");
        prefList.add("宮崎県");
        prefList.add("鹿児島県");
        prefList.add("沖縄県");
        return prefList;
    }

    /**
     * リストが選択されたときの処理が記述されたメンバクラス。
     * 第2画面へ処理を移管する。
     */
    private class ListItemClickListener implements AdapterView.OnItemClickListener {
        @Override
        public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
            String prefName = (String) parent.getItemAtPosition(position);

            Intent intent = new Intent(PrefListActivity.this, PrefEditActivity.class);
            intent.putExtra("selectedPrefNo", position);
            intent.putExtra("selectedPrefName", prefName);
            startActivity(intent);
        }
    }
}

動的のリストビュー

SimpleCursorAdapterクラスを使う。
→DB内のデータをもとにリストビューを作りたいときに使う。
引数は6つ

1.コンテキスト

2.リストビューの各行のレイアウトを表すR値
*simple_list_view_item_1で通常いい。

3.Cursorオブジェクト

4.String[] : カラム名の配列

5.int[] : 画面部品のR値の配列

6.0でいい

これをリストビューに表示(登録)する方法
->ListViewクラスのsetAdapterメソッドを使う

サンプルコード

MemoListActivity.java
public class MemoListActivity extends AppCompatActivity {
    private ListView _lvMemoList;

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

        _lvMemoList = findViewById(R.id.lvMemoList);
        _lvMemoList.setOnItemClickListener(new ListItemClickListener());
    }

    @Override
    protected void onResume() {
        super.onResume();
        DatabaseHelper helper = new DatabaseHelper(MemoListActivity.this);
        SQLiteDatabase db = helper.getWritableDatabase();
        Cursor cursor = DataAccess.findAll(db);
        String[] from = {"title"};
        int[] to = {android.R.id.text1};
        SimpleCursorAdapter adapter = new SimpleCursorAdapter(MemoListActivity.this, android.R.layout.simple_list_item_1, cursor, from, to, 0);
        _lvMemoList.setAdapter(adapter);
    }
}

onResume : 画面を更新するメソッド

カスタマイズリスト

SimpleAdapterを使う。

row

リストビューの各行をカスタマイズするには以下の手順をとる。
1) 1行分のレイアウト.xmlファイルを用意する
-> xmlファイルの書き方は通常のレイアウトファイルと同じ

res/layout/row.xml
<LinearLayout ... >
    <ImageView ... />
    <TextView ... /> 
    <TextView ... /> 
    <TextView ... />
</LinearLayout>

*ファイル名はなんでも良い

2) アダプタをnewする時にレイアウトを指定する引数に 1) のファイルのR値を指定する。

(ex.)
new.SimpleAdapter( ..., _list, R.layout.row, ... );

3) アダプタクラスをnewする時の引数toのint配列では 1) のファイル中に記述したidのR値を指定する。

(ex.)
int[] to = {R.id.tvMenuName, R.id.tvMenuPrice}

ViewBinder

(1)ViewBinderとは
row.xmlを使うと、リストビュー先行のレイアウトがカスタマイズできる。

では、データに合わせて、各行の表示内容まで変更するには?

from - toの組み合わせでfromのデータをtoの画面部品に割り当てる処理を自作する (ViewBinderの作成)、手順は以下の通り。

1) SimpleAdapter.ViewBinderインタフェースを実装したクラスを作成する。 -> privateなメンバクラスで良い

2) このクラスのsetViewValue()メソッドに画面部品へのデータの割り当て処理を記述する。(後述)

3) アダプタクラスのsetViewBinder()メソッドにこのクラスをnewしたものを渡す

(ex.) 
private class CustomViewBinder implement SimpleAdapter.ViewBinder {
    @Override
    public boolean setViewValue() { 

         ここに各行内画面部品のデータ割り当てを記述
    }  
}

adapter.setViewBinder(new CustomViewBinder());

(2) setViewValue() の引数
setViewValue()のメソッドの引数は以下の3コ。

1. View view : 1 行分の中の画面部品。
2. Object data : 上記で第 1 引数に割り当てるデータ。
3. String textReprosentation : 第 2 引数の内容を文字列化したもの。第二引数が null の場合は、
空白文字列。

(3)setViewValue()内の処理パターン
setViewValue()内は引数 viewのidを使って分岐し、引数 data を使って処理を記述していく。
→ switch 文が便利。

public booelan setViewValue ( .... ) {
  int viewId = view.getId(); ← id を取得
  switch( viewId ) { ← id に応じて処理を分岐 (switch)
    case R . id . imPhoneType : ← id 同士の比較なので R 値
      ImageView imPhoneType = ( ImageView ) view;
      int phoneType = ( Integer ) data;

      あとはお好きに。

      return true;     
    case .....
  }
  return false
}

setViewValue() メソッド内では、ビューにデータを埋め込む独自処理を記述した場合、つまり、各 case の末尾に return true を記述する。さらに、メソッド末尾に return false を記述する。
→ この戻り値の値によって、os 側でデータの埋め込み処理を行うかどうかの判定を行なっている。

(4) SimpleCursorAdapter の場合
SimpleCursorAdapter の場合でも、ViewBinder の setViewValue() の処理は SimpleAdapter と同じ。

view . getId() の値を switch で分岐させる。ただし、引数は以下の 3 コ。
1. View view : リスト 1 行中の画面部品。
2. Cursor cursor : 対象となっているリスト 1 行分のデータが格納されたカーソルオブジェクト。
3. int columnIndex : 上記第 1 引数に割り当てるデータのカラムインデックス。

DBデータのリロード

リストビューの元データとなる DB 内のデータが更新された場合、DB からデータを取り直して再表示させる必要がある。

○以下のソースコードとなる。
SimpleCursorAdapter adapter = ( SimpleCursorAdapter ) _lvPhones . getAdapter();

adapter . changeCursor( cursor ); ← カーソルの入れ替え。 新しいカーソル

(注)
onCreate() でアダプタの設定を行い、onResume() でカーソルの設定 ( 入れ替え ) を行うよう な場合、 onCreate() 内で SimpleCursorAdapter を new する際の引数 cursor には null を渡せば良い。

サンプルコード1

public class CustomizedListView2Activity extends AppCompatActivity {
    /**
     * リストビューに表示させるリストデータ。
     */
    private List<Map<String, Object>> _list;

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

        _list = createList();

        String[] from = {"phoneType", "phoneNo", "phoneSex"};
        int[] to = {R.id.imPhoneType, R.id.tvPhoneNo, R.id.tvSex};
        SimpleAdapter adapter = new SimpleAdapter(CustomizedListView2Activity.this, _list, R.layout.row, from, to);
        adapter.setViewBinder(new CustomViewBinder());
        ListView lvPhones = findViewById(R.id.lvPhones);
        lvPhones.setAdapter(adapter);
    }

    /**
     * リストビューに表示されるリストデータを生成するメソッド。
     *
     * @return 生成されたリストデータ。
     */
    private List<Map<String, Object>> createList() {
        List<Map<String, Object>> list = new ArrayList<>();

        for (int i = 1; i <= 30; i++) {
            int phoneType = (int) (3 * Math.random()) + 1;
            int phoneNoInt = (int) (99999999 * Math.random());
            int phoneSexInt = (int) (10*Math.random() + 1);

            String phoneNo = "090" + String.format("%08d", phoneNoInt);

            int phoneSex = 1;
            if(phoneSexInt <= 5) {
                phoneSex = 0;
            }

            Map<String, Object> map = new HashMap<>();
            map.put("phoneType", phoneType);
            map.put("phoneNo", phoneNo);
            map.put("phoneSex", phoneSex);
            list.add(map);
        }

        return list;
    }

    /**
     * リストビューのカスタムビューバインダークラス。
     */
    private class CustomViewBinder implements SimpleAdapter.ViewBinder {

        @Override
        public boolean setViewValue(View view, Object data, String textRepresentation) {
            int viewId = view.getId();
            switch(viewId) {
                case R.id.imPhoneType:
                    ImageView imPhoneType = (ImageView) view;
                    int phoneType = (Integer) data;
                    switch(phoneType) {
                        case 2:
                            imPhoneType.setImageResource(android.R.drawable.ic_menu_crop);
                            break;
                        case 3:
                            imPhoneType.setImageResource(android.R.drawable.ic_menu_myplaces);
                            break;
                        default:
                            imPhoneType.setImageResource(android.R.drawable.ic_menu_call);
                            break;
                    }
                    return true;
                case R.id.tvPhoneNo:
                    TextView tvPhoneNo = (TextView) view;
                    String phoneNo = (String) data;
                    tvPhoneNo.setText(phoneNo);
                    return true;
                case R.id.tvSex:
                    TextView tvSex = (TextView) view;
                    int phoneSex = (Integer) data;
                    String sex = "♂";
                    if(phoneSex == 0) {
                        sex = "♀";
                    }
                    tvSex.setText(sex);
                    return true;
            }
            return false;
        }
    }
}

サンプルコード2

public class CustomizedListView3Activity extends AppCompatActivity {

    private ListView _lvPhones;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_customized_list_view3);
        _lvPhones = findViewById(R.id.lvPhones);

        String[] from = {"phone_type", "phone_no", "phone_sex"};
        int[] to = {R.id.imPhoneType, R.id.tvPhoneNo, R.id.tvSex};
        SimpleCursorAdapter adapter = new SimpleCursorAdapter(CustomizedListView3Activity.this, R.layout.row, null, from, to, 0);
        adapter.setViewBinder(new CustomViewBinder());
        _lvPhones.setAdapter(adapter);
    }

    @Override
    public void onResume() {
        super.onResume();
        setNewCursor();
    }

    /**
     * カーソルアダプタ内のカーソルを更新するメソッド。
     */
    private void setNewCursor() {
        DatabaseHelper helper = new DatabaseHelper(CustomizedListView3Activity.this);
        SQLiteDatabase db = helper.getWritableDatabase();
        Cursor cursor = DataAccess.findAll(db);
        SimpleCursorAdapter adapter = (SimpleCursorAdapter) _lvPhones.getAdapter();
        adapter.changeCursor(cursor);
    }

    /**
     * リストビューのカスタムビューバインダークラス。
     *
     * @author Shinzo SAITO
     */
    private class CustomViewBinder implements SimpleCursorAdapter.ViewBinder {

        @Override
        public boolean setViewValue(View view, Cursor cursor, int columnIndex) {
            int viewId = view.getId();
            switch(viewId) {
                case R.id.imPhoneType:
                    ImageView imPhoneType = (ImageView) view;
                    int phoneType = cursor.getInt(columnIndex);
                    switch(phoneType) {
                        case 2:
                            imPhoneType.setImageResource(android.R.drawable.ic_menu_crop);
                            break;
                        case 3:
                            imPhoneType.setImageResource(android.R.drawable.ic_menu_myplaces);
                            break;
                        default:
                            imPhoneType.setImageResource(android.R.drawable.ic_menu_call);
                            break;
                    }
                    return true;
                case R.id.tvPhoneNo:
                    TextView tvPhoneNo = (TextView) view;
                    String phoneNo = cursor.getString(columnIndex);
                    tvPhoneNo.setText(phoneNo);
                    return true;
                case R.id.tvSex:
                    TextView tvSex = (TextView) view;
                    int phoneSex = cursor.getInt(columnIndex);
                    String sex = "♂";
                    if(phoneSex == 0) {
                        sex = "♀";
                    }
                    tvSex.setText(sex);
                    return true;
            }
            return false;
        }
    }
}

以上。Androidでのリストビューについてまとめて見ました。
もし何か間違っている等のご指摘があればご連絡ください。
最後まで読んで頂きありがとうございました。

5
9
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
5
9