アンドロイドでリスト表示を使うケースはたくさんあります。例えば、サムネイルの風景写真と場所の名前のリスト、タップしてその詳細を説明するアプリは多いですね。これらはListViewとBaseAdapterを使うと簡単にできます。
2021.2.1
ListView
画像とテキストのListViewを作りましたが
アイテムのクリックと画面遷移の追加変更を考えてみます。
画像とテキストのListViewの作成
画像を res/drawable 以下に置きますが、ここに置ける画像には限界があり、メモリを圧迫させない工夫が必要になります。
ここでは簡単な例として 540×300 pixel 程度の画像をリストと、タップして画面遷移した先でも同じ画像を使っています。
本来ならばリスト表示ではサムネイル化してもっと小さい画像を使った方がいいでしょう。タップして画面遷移した先では別のサイズの大きな画像をassetsから呼び出した方が画像がきれいになります。
これについてはdrawable VS assetsを参照ください。
BaseAdapterで画像とテキストをリスト表示 を元に画像をdrawableから読み出してリスト表示させるところは、
MainActivity.java
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 |
... public class MainActivity extends AppCompatActivity { private static final String[] scenes = { "Ventnor", "Wroxall", "Whitewell", "Ryde", "StLawrence", "Lake", "Sandown", "Shanklin" }; // ちょっと冗長的ですが分かり易くするために private static final int[] photos = { R.drawable.ventnor, R.drawable.wroxall, R.drawable.whitewell, R.drawable.ryde, R.drawable.stlawrence, R.drawable.lake, R.drawable.sandown, R.drawable.shanklin }; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); // ListViewのインスタンスを生成 ListView listView = findViewById(R.id.list_view); // BaseAdapter を継承したadapterのインスタンスを生成 // レイアウトファイル list.xml を activity_main.xml に // inflate するためにadapterに引数として渡す BaseAdapter adapter = new ListViewAdapter(this.getApplicationContext(), R.layout.list, scenes, photos); // ListViewにadapterをセット listView.setAdapter(adapter); } } |
BaseAdapterを継承したadapter class
ListViewAdapter.java
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 |
... public class ListViewAdapter extends BaseAdapter { static class ViewHolder { TextView textView; ImageView imageView; } private LayoutInflater inflater; private int itemLayoutId; private String[] titles; private int[] ids; ListViewAdapter(Context context, int itemLayoutId, String[] scenes, int[] photos) { super(); this.inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE); this.itemLayoutId = itemLayoutId; this.titles = scenes; this.ids = photos; } @Override public View getView(int position, View convertView, ViewGroup parent) { ViewHolder holder; // 最初だけ View を inflate して、それを再利用する if (convertView == null) { // activity_main.xml に list.xml を inflate して convertView とする convertView = inflater.inflate(itemLayoutId, parent, false); // ViewHolder を生成 holder = new ViewHolder(); holder.textView = convertView.findViewById(R.id.textView); holder.imageView = convertView.findViewById(R.id.imageView); convertView.setTag(holder); } // holder を使って再利用 else { holder = (ViewHolder) convertView.getTag(); } // holder の imageView にセット holder.imageView.setImageResource(ids[position]); // 現在の position にあるファイル名リストを holder の textView にセット holder.textView.setText(titles[position]); return convertView; } @Override public int getCount() { // texts 配列の要素数 return titles.length; } @Override public Object getItem(int position) { return null; } @Override public long getItemId(int position) { return 0; } } |
アイテムをクリックした時の挙動をコーディング
各要素がタップされ、その画像が一面表示される挙動を考えてみます
- タップされた時に、その要素の position を取得
- 遷移先の SubActivity.java にタップされた情報を渡し遷移する
- SubActivity からその position にある画像とテキストを表示
タップされた事を認識するために、リスナーを設定します。
implements OnItemClickListener
の設定と onCreate() に
listView.setOnItemClickListener(this);
を設定します
MainActivity.java
1 2 3 4 5 6 7 8 |
public class MainActivity extends Activity implements OnItemClickListener{ ... protected void onCreate(Bundle savedInstanceState) { ... listView.setOnItemClickListener(this); } ... |
itemがタップされ時に onItemClick() が呼ばれ、itemの position から配列のindexを取得して putExtra() で intent にセットします。そして遷移先の Activity に渡す。
MainActivity.java
1 2 3 4 5 6 7 8 9 10 11 12 13 |
... @Override public void onItemClick(AdapterView<?> parent, View v, int position, long id) { Intent intent = new Intent(this.getApplicationContext(), SubActivity.class); // clickされたpositionのtextとphotoのID String selectedText = scenes[position]; int selectedPhoto = photos[position]; // インテントにセット intent.putExtra("Text", selectedText); intent.putExtra("Photo", selectedPhoto); // Activity をスイッチする startActivity(intent); } |
SubActivity.java にて getStringExtra() から
配列のindexを取り出し
画面に表示します
SubActivity.java
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
... public class SubActivity extends AppCompatActivity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_sub); Intent intent = getIntent(); String selectedText = intent.getStringExtra("Text"); int selectedPhoto = intent.getIntExtra("Photo", 0); TextView textView = findViewById(R.id.selected_text); textView.setText(selectedText); ImageView imageView = findViewById(R.id.selected_photo); imageView.setImageResource(selectedPhoto); } } |
サンプルコード
まとめてみましょう。
新規に作成するファイル、取り込む画像などが多いのでプロジェクトとしてはこのような配置になります。
MainActivity.java
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 |
//package com.example.testlistviewitemclick; import androidx.appcompat.app.AppCompatActivity; import android.content.Intent; import android.os.Bundle; import android.view.View; import android.widget.AdapterView; import android.widget.BaseAdapter; import android.widget.ListView; public class MainActivity extends AppCompatActivity implements AdapterView.OnItemClickListener { private static final String[] scenes = { "Ventnor", "Wroxall", "Whitewell", "Ryde", "StLawrence", "Lake", "Sandown", "Shanklin" }; // ちょっと冗長的ですが分かり易くするために private static final int[] photos = { R.drawable.ventnor, R.drawable.wroxall, R.drawable.whitewell, R.drawable.ryde, R.drawable.stlawrence, R.drawable.lake, R.drawable.sandown, R.drawable.shanklin }; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); // ListViewのインスタンスを生成 ListView listView = findViewById(R.id.list_view); // BaseAdapter を継承したadapterのインスタンスを生成 // レイアウトファイル list.xml を activity_main.xml に // inflate するためにadapterに引数として渡す BaseAdapter adapter = new ListViewAdapter(this.getApplicationContext(), R.layout.list, scenes, photos); // ListViewにadapterをセット listView.setAdapter(adapter); // クリックリスナーをセット listView.setOnItemClickListener(this); } @Override public void onItemClick(AdapterView<?> parent, View v, int position, long id) { Intent intent = new Intent( this.getApplicationContext(), SubActivity.class); // clickされたpositionのtextとphotoのID String selectedText = scenes[position]; int selectedPhoto = photos[position]; // インテントにセット intent.putExtra("Text", selectedText); intent.putExtra("Photo", selectedPhoto); // SubActivityへ遷移 startActivity(intent); } } |
ListViewAdapter.java
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 |
//package com.example.testlistviewitemclick; import android.content.Context; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.widget.BaseAdapter; import android.widget.ImageView; import android.widget.TextView; public class ListViewAdapter extends BaseAdapter { static class ViewHolder { TextView textView; ImageView imageView; } private final LayoutInflater inflater; private final int itemLayoutId; private final String[] titles; private final int[] ids; ListViewAdapter(Context context, int itemLayoutId, String[] scenes, int[] photos) { super(); this.inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE); this.itemLayoutId = itemLayoutId; this.titles = scenes; this.ids = photos; } @Override public View getView(int position, View convertView, ViewGroup parent) { ViewHolder holder; // 最初だけ View を inflate して、それを再利用する if (convertView == null) { // activity_main.xml に list.xml を inflate して convertView とする convertView = inflater.inflate(itemLayoutId, parent, false); // ViewHolder を生成 holder = new ViewHolder(); holder.textView = convertView.findViewById(R.id.textView); holder.imageView = convertView.findViewById(R.id.imageView); convertView.setTag(holder); } // holder を使って再利用 else { holder = (ViewHolder) convertView.getTag(); } // holder の imageView にセット holder.imageView.setImageResource(ids[position]); // 現在の position にあるファイル名リストを holder の textView にセット holder.textView.setText(titles[position]); return convertView; } @Override public int getCount() { // texts 配列の要素数 return titles.length; } @Override public Object getItem(int position) { return null; } @Override public long getItemId(int position) { return 0; } } |
遷移先のActivityです。
SubActivity.java
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 |
//package com.example.testlistviewitemclick; import androidx.appcompat.app.AppCompatActivity; import android.content.Intent; import android.os.Bundle; import android.widget.ImageView; import android.widget.TextView; public class SubActivity extends AppCompatActivity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_sub); Intent intent = getIntent(); // MainActivityからintentで受け取ったものを取り出す String selectedText = intent.getStringExtra("Text"); int selectedPhoto = intent.getIntExtra("Photo", 0); TextView textView = findViewById(R.id.selected_text); textView.setText(selectedText); ImageView imageView = findViewById(R.id.selected_photo); imageView.setImageResource(selectedPhoto); } } |
ManifestにSubActivityを登録します。
AndroidManifest.xml
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
<?xml version="1.0" encoding="utf-8"?> <manifest xmlns:android="http://schemas.android.com/apk/res/android" ... <application ... <activity android:name=".MainActivity"> ... </activity> <activity android:name=".SubActivity" android:label="@string/app_name" > </activity> </application> </manifest> |
MainActivityのレイアウト
activity_main.xml
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
<?xml version="1.0" encoding="utf-8"?> <androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" tools:context=".MainActivity"> <ListView android:id="@+id/list_view" android:layout_width="match_parent" android:layout_height="wrap_content" app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintLeft_toLeftOf="parent" app:layout_constraintRight_toRightOf="parent" app:layout_constraintTop_toTopOf="parent" /> </androidx.constraintlayout.widget.ConstraintLayout> |
ListViewのinflater
list.xml
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 |
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:orientation="horizontal" android:layout_width="match_parent" android:layout_height="match_parent"> <ImageView android:id="@+id/imageView" android:scaleType="centerCrop" android:contentDescription="@string/description" android:layout_margin="5dp" android:layout_width="120dp" android:layout_height="80dp" /> <TextView android:id="@+id/textView" android:layout_margin="29dp" android:layout_gravity="center_vertical" android:layout_width="wrap_content" android:layout_height="wrap_content" android:textSize="20sp" android:textColor="#000" /> </LinearLayout> |
SubActivityのレイアウト
activity_sub.xml
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 |
<?xml version="1.0" encoding="utf-8"?> <androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" tools:context=".MainActivity"> <TextView android:id="@+id/selected_text" android:textSize="20sp" android:textColor="#000" android:layout_margin="10dp" android:layout_width="match_parent" android:layout_height="wrap_content" app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintLeft_toLeftOf="parent" app:layout_constraintRight_toRightOf="parent" app:layout_constraintTop_toTopOf="parent" app:layout_constraintVertical_bias="0.15"/> <ImageView android:id="@+id/selected_photo" android:layout_margin="10dp" android:layout_width="match_parent" android:layout_height="wrap_content" android:contentDescription="@string/description" android:scaleType="fitCenter" app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintLeft_toLeftOf="parent" app:layout_constraintRight_toRightOf="parent" app:layout_constraintTop_toTopOf="parent" app:layout_constraintVertical_bias="0.5"/> </androidx.constraintlayout.widget.ConstraintLayout> |
リソース
strings.xml
1 2 3 4 |
<resources> <string name="app_name">Your App Name</string> <string name="description">picture</string> </resources> |
サンプル動画
このまま同じように GridView に変える事も可能です。
関連ページ:
- ArrayAdapter
- ListView と ArrayAdapter 簡単なテキストリストの表示
- ArrayAdapterを使ってレイアウトをアレンジ
- ListActivity と ArrayAdapterで画像とテキストをリスト表示
- Basedapter
- BaseAdapterで画像とテキストをリスト表示
- ListViewリストをタップして画面遷移
- ListViewアイテムの移動、削除
- ListView アイテム個々の背景、高さなどを変える
References:
ListView | Android Developers
リストビュー | Android Developers
BaseAdapter | Android Developers