記事は著者の許可を得たこの記事の翻訳です。
例:独自のテンプレートを使用したListActivity。
リストアイテム用の独自のテンプレートを作成し、それをアダプタに適用できます。 テンプレートはリストの各要素で同じになりますが、より柔軟にする方法について説明します。 この例では、リスト内の各アイテムにアイコンを追加します。
プロジェクト「de.vogella.android.listactivity」のres / layoutフォルダーに「rowlayout.xml」テンプレートファイルを作成します。
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="wrap_content" android:layout_height="wrap_content" > <ImageView android:id="@+id/icon" android:layout_width="22px" android:layout_height="22px" android:layout_marginLeft="4px" android:layout_marginRight="10px" android:layout_marginTop="4px" android:src="@drawable/ic_launcher" > </ImageView> <TextView android:id="@+id/label" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="@+id/label" android:textSize="20px" > </TextView> </LinearLayout>
アクティビティを次のように変更します。 コードは前の例とほとんど同じですが、唯一の違いは、ArrayAdapterで独自のテンプレートを使用し、テキストに含まれるユーザーインターフェイス要素をアダプターに伝えることです。 標準テンプレートを使用したため、前の記事ではこれを行いませんでした。
package de.vogella.android.listactivity; import android.app.ListActivity; import android.os.Bundle; import android.view.View; import android.widget.ArrayAdapter; import android.widget.ListView; import android.widget.Toast; public class MyListActivity extends ListActivity { public void onCreate(Bundle icicle) { super.onCreate(icicle); String[] values = new String[] { "Android", "iPhone", "WindowsMobile", "Blackberry", "WebOS", "Ubuntu", "Windows7", "Max OS X", "Linux", "OS/2" }; // ArrayAdapter<String> adapter = new ArrayAdapter<String>(this, R.layout.rowlayout, R.id.label, values); setListAdapter(adapter); } @Override protected void onListItemClick(ListView l, View v, int position, long id) { String item = (String) getListAdapter().getItem(position); Toast.makeText(this, item + " selected", Toast.LENGTH_LONG).show(); } }
例:柔軟なテンプレートを使用したListActivity
前の例は両方とも一度にすべての行に同じパターンを使用します。 特定の行の外観を変更する場合は、アダプターを定義し、getView()メソッドを置き換える必要があります。
このメソッドは、ListViewの個々の要素を作成します。 getView()はビューを返します。 このビューは実際にはテンプレート(ViewGroup)であり、ImageViewやTextViewなどの他のビューが含まれています。 getView()を使用すると、個々のビューのパラメーターを変更することもできます。
getView()でXMLからテンプレートを読み取るには、LayoutInflatorシステムサービスを使用できます。
この例では、ArrayAdapterを拡張していますが、BaseAdapterを直接実装することもできます。
単純なアダプター定義
最適化に注意を払わずに、独自のアダプターを作成するのは非常に簡単です。 アクティビティに表示するデータを取得し、リストアイテムに保存するだけです。 getView()で、要素の定義済みテンプレートを設定し、findViewById()で必要な要素を取得します。 その後、プロパティを定義できます。
この例では、「no.png」と「ok.png」の2つの画像を使用します。 それらを「res / drawable-mdpi」フォルダーに入れます。 写真を使用します。 それらが見つからない場合は、「icon.png」をコピーして、グラフィカルエディターを使用して少し変更します。
アダプタとして機能するクラス「MySimpleArrayAdapter」を作成します。
package de.vogella.android.listactivity; import android.content.Context; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.widget.ArrayAdapter; import android.widget.ImageView; import android.widget.TextView; public class MySimpleArrayAdapter extends ArrayAdapter<String> { private final Context context; private final String[] values; public MySimpleArrayAdapter(Context context, String[] values) { super(context, R.layout.rowlayout, values); this.context = context; this.values = values; } @Override public View getView(int position, View convertView, ViewGroup parent) { LayoutInflater inflater = (LayoutInflater) context .getSystemService(Context.LAYOUT_INFLATER_SERVICE); View rowView = inflater.inflate(R.layout.rowlayout, parent, false); TextView textView = (TextView) rowView.findViewById(R.id.label); ImageView imageView = (ImageView) rowView.findViewById(R.id.icon); textView.setText(values[position]); // Windows iPhone String s = values[position]; if (s.startsWith("Windows7") || s.startsWith("iPhone") || s.startsWith("Solaris")) { imageView.setImageResource(R.drawable.no); } else { imageView.setImageResource(R.drawable.ok); } return rowView; } }
このアダプターを使用するには、MyListクラスを次のように変更します
package de.vogella.android.listactivity; import android.app.ListActivity; import android.os.Bundle; public class MyListActivity extends ListActivity { public void onCreate(Bundle icicle) { super.onCreate(icicle); String[] values = new String[] { "Android", "iPhone", "WindowsMobile", "Blackberry", "WebOS", "Ubuntu", "Windows7", "Max OS X", "Linux", "OS/2" }; MySimpleArrayAdapter adapter = new MySimpleArrayAdapter(this, values); setListAdapter(adapter); } }
このアプリケーションを起動すると、いくつかのアイコンが異なるアイコンのリストが表示されます。
独自のアダプターのパフォーマンスを最適化する
要素ごとにJavaオブジェクトを作成すると、メモリ消費と時間が消費されます。 既に述べたように、Androidは表示されなくなったリストの要素(ビュー)を消去し、convertViewパラメーターを介してgetView()メソッドに管理を委任します。
アダプタはこのビューを使用して、この要素のテンプレートを「肥大化」させることを回避できます。 これにより、メモリが節約され、プロセッサの負荷が軽減されます。
実装では、convertViewが空でない場合、コンテンツのconvertViewを確認し、既存のテンプレートに新しいデータを送信して、コンテンツを再割り当てする必要があります。
また、実装ではViewHolderモデルを使用します。 findViewById()メソッドは非常にリソースを消費するため、直接必要でない場合は避けてください。
ViewHolderは、必要なテンプレートへのリンクをリストアイテムに保存します。 このViewHolderは、setTag()メソッドを使用して要素にアタッチされます。 各ビューには、適用されたリンクが含まれる場合があります。 アイテムがクリアされると、getTag()メソッドを介してViewHolderを取得できます。 ロードされているように見えますが、実際にはfindViewById()を繰り返し呼び出すよりも速く動作します。
両方の手法(既存のビューとViewHolderモデルの再割り当て)により、特に大容量のデータでパフォーマンスが約15%向上します。
de.vogella.android.listactivityプロジェクトを引き続き使用して、MyArrayAdapter.javaクラスを作成します。
package de.vogella.android.listactivity; import android.app.Activity; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.widget.ArrayAdapter; import android.widget.ImageView; import android.widget.TextView; public class MyArrayAdapter extends ArrayAdapter<String> { private final Activity context; private final String[] names; public MyArrayAdapter(Activity context, String[] names) { super(context, R.layout.rowlayout, names); this.context = context; this.names = names; } // // static class ViewHolder { public ImageView imageView; public TextView textView; } @Override public View getView(int position, View convertView, ViewGroup parent) { // ViewHolder ViewHolder holder; // , // View rowView = convertView; if (rowView == null) { LayoutInflater inflater = context.getLayoutInflater(); rowView = inflater.inflate(R.layout.rowlayout, null, true); holder = new ViewHolder(); holder.textView = (TextView) rowView.findViewById(R.id.label); holder.imageView = (ImageView) rowView.findViewById(R.id.icon); rowView.setTag(holder); } else { holder = (ViewHolder) rowView.getTag(); } holder.textView.setText(names[position]); // Windows iPhone String s = names[position]; if (s.startsWith("Windows7") || s.startsWith("iPhone") || s.startsWith("Solaris")) { holder.imageView.setImageResource(R.drawable.no); } else { holder.imageView.setImageResource(R.drawable.ok); } return rowView; } }
package de.vogella.android.listactivity; import android.app.ListActivity; import android.os.Bundle; public class MyListActivity extends ListActivity { public void onCreate(Bundle icicle) { super.onCreate(icicle); String[] values = new String[] { "Android", "iPhone", "WindowsMobile", "Blackberry", "WebOS", "Ubuntu", "Windows7", "Max OS X", "Linux", "OS/2" }; setListAdapter(new MyArrayAdapter(this, values)); } }
高度なListActivity
アイテムのロングクリック処理
ビューにLongItemClickListenerを追加することもできます。 これを行うには、getListView()メソッドでListViewを取得し、setOnItemLongClickListener()メソッドでロングクリック処理を定義します。
package de.vogella.android.listactivity; import android.app.ListActivity; import android.os.Bundle; import android.view.View; import android.widget.AdapterView; import android.widget.AdapterView.OnItemLongClickListener; import android.widget.ArrayAdapter; import android.widget.ListView; import android.widget.Toast; public class MyList extends ListActivity { /** , . */ public void onCreate(Bundle icicle) { super.onCreate(icicle); // ListActivity String[] names = new String[] { "Linux", "Windows7", "Eclipse", "Suse", "Ubuntu", "Solaris", "Android", "iPhone", "Linux", "Windows7", "Eclipse", "Suse", "Ubuntu", "Solaris", "Android", "iPhone" }; ArrayAdapter<String> adapter = new TwoLayoutsArrayAdapter(this, names); setListAdapter(adapter); ListView list = getListView(); list.setOnItemLongClickListener(new OnItemLongClickListener() { @Override public boolean onItemLongClick(AdapterView<?> parent, View view, int position, long id) { Toast.makeText(MyList.this, "Item in position " + position + " clicked", Toast.LENGTH_LONG).show(); // "", , // onListItemClick return true; } }); } @Override protected void onListItemClick(ListView l, View v, int position, long id) { super.onListItemClick(l, v, position, id); // , Object o = this.getListAdapter().getItem(position); String keyword = o.toString(); Toast.makeText(this, "You selected: " + keyword, Toast.LENGTH_SHORT) .show(); } }
データモデルと相互作用する要素
リストアイテムテンプレートには、データモデルとやり取りするビューも含まれる場合があります。 たとえば、リストアイテムでチェックボックスを使用できます。チェックボックスが有効になっている場合、アイテムに表示されるデータを変更できます。
まだ同じプロジェクトを使用しています。 「rowbuttonlayout.xml」リストアイテムテンプレートを作成します。
<?xml version="1.0" encoding="utf-8"?> <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="wrap_content"> <TextView android:text="@+id/label" android:layout_width="wrap_content" android:layout_height="wrap_content" android:id="@+id/label" android:textSize="30px"></TextView> <CheckBox android:id="@+id/check" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginLeft="4px" android:layout_marginRight="10px" android:layout_alignParentRight="true" ></CheckBox> </RelativeLayout>
この例では、チェックされている場合、要素の名前とそのコンテンツを含むModelクラスを作成します。
package de.vogella.android.listactivity; public class Model { private String name; private boolean selected; public Model(String name) { this.name = name; selected = false; } public String getName() { return name; } public void setName(String name) { this.name = name; } public boolean isSelected() { return selected; } public void setSelected(boolean selected) { this.selected = selected; } }
次のアダプターを作成します。 このアダプターは、チェックボックス変更処理を追加します。 チェックボックスが有効になっている場合、モデルのデータも変更されます。 必須のチェックボックスは、setTag()メソッドを通じてモデルを取得します。
package de.vogella.android.listactivity; import java.util.List; import android.app.Activity; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.widget.ArrayAdapter; import android.widget.CheckBox; import android.widget.CompoundButton; import android.widget.TextView; public class InteractiveArrayAdapter extends ArrayAdapter<Model> { private final List<Model> list; private final Activity context; public InteractiveArrayAdapter(Activity context, List<Model> list) { super(context, R.layout.rowbuttonlayout, list); this.context = context; this.list = list; } static class ViewHolder { protected TextView text; protected CheckBox checkbox; } @Override public View getView(int position, View convertView, ViewGroup parent) { View view = null; if (convertView == null) { LayoutInflater inflator = context.getLayoutInflater(); view = inflator.inflate(R.layout.rowbuttonlayout, null); final ViewHolder viewHolder = new ViewHolder(); viewHolder.text = (TextView) view.findViewById(R.id.label); viewHolder.checkbox = (CheckBox) view.findViewById(R.id.check); viewHolder.checkbox .setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() { @Override public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) { Model element = (Model) viewHolder.checkbox .getTag(); element.setSelected(buttonView.isChecked()); } }); view.setTag(viewHolder); viewHolder.checkbox.setTag(list.get(position)); } else { view = convertView; ((ViewHolder) view.getTag()).checkbox.setTag(list.get(position)); } ViewHolder holder = (ViewHolder) view.getTag(); holder.text.setText(list.get(position).getName()); holder.checkbox.setChecked(list.get(position).isSelected()); return view; } }
最後に、ListViewを次のように変更します。
package de.vogella.android.listactivity; import java.util.ArrayList; import java.util.List; import android.app.ListActivity; import android.os.Bundle; import android.widget.ArrayAdapter; public class MyList extends ListActivity { /** , . */ public void onCreate(Bundle icicle) { super.onCreate(icicle); // , ListActivity ArrayAdapter<Model> adapter = new InteractiveArrayAdapter(this, getModel()); setListAdapter(adapter); } private List<Model> getModel() { List<Model> list = new ArrayList<Model>(); list.add(get("Linux")); list.add(get("Windows7")); list.add(get("Suse")); list.add(get("Eclipse")); list.add(get("Ubuntu")); list.add(get("Solaris")); list.add(get("Android")); list.add(get("iPhone")); // list.get(1).setSelected(true); return list; } private Model get(String s) { return new Model(s); } }
アプリケーションを起動すると、モデルに反映される要素マークにアクセスできます。
複数選択
単一選択と複数選択を行うこともできます。 例については、次のスニペットを参照してください。 選択したアイテムを取得するには、listView.getCheckedItemPositions()またはlistView.getCheckedItemPositions()を使用します。 listView.getCheckedItemIds()を使用して、選択したアイテムのIDを取得することもできます。
package de.vogella.android.listactivity; import android.app.ListActivity; import android.os.Bundle; import android.widget.ArrayAdapter; import android.widget.ListView; public class MyList extends ListActivity { /** , . */ public void onCreate(Bundle icicle) { super.onCreate(icicle); // , ListActivity String[] names = new String[] { "Linux", "Windows7", "Eclipse", "Suse", "Ubuntu", "Solaris", "Android", "iPhone", "Linux", "Windows7", "Eclipse", "Suse", "Ubuntu", "Solaris", "Android", "iPhone" }; setListAdapter(new ArrayAdapter<String>(this, android.R.layout.simple_list_item_multiple_choice, android.R.id.text1, names)); ListView listView = getListView(); listView.setChoiceMode(ListView.CHOICE_MODE_MULTIPLE); } }
package de.vogella.android.listactivity; import android.app.ListActivity; import android.os.Bundle; import android.widget.ArrayAdapter; import android.widget.ListView; public class MyList extends ListActivity { /** . */ public void onCreate(Bundle icicle) { super.onCreate(icicle); // , ListActivity String[] names = new String[] { "Linux", "Windows7", "Eclipse", "Suse", "Ubuntu", "Solaris", "Android", "iPhone", "Linux", "Windows7", "Eclipse", "Suse", "Ubuntu", "Solaris", "Android", "iPhone" }; setListAdapter(new ArrayAdapter<String>(this, android.R.layout.simple_list_item_single_choice, android.R.id.text1, names)); ListView listView = getListView(); listView.setChoiceMode(ListView.CHOICE_MODE_SINGLE); } } package de.vogella.android.listactivity; import android.app.ListActivity; import android.os.Bundle; import android.widget.ArrayAdapter; import android.widget.ListView; public class MyList extends ListActivity { /** . */ public void onCreate(Bundle icicle) { super.onCreate(icicle); // , ListActivity String[] names = new String[] { "Linux", "Windows7", "Eclipse", "Suse", "Ubuntu", "Solaris", "Android", "iPhone", "Linux", "Windows7", "Eclipse", "Suse", "Ubuntu", "Solaris", "Android", "iPhone" }; setListAdapter(new ArrayAdapter<String>(this, android.R.layout.simple_list_item_single_choice, android.R.id.text1, names)); ListView listView = getListView(); listView.setChoiceMode(ListView.CHOICE_MODE_SINGLE); } }
ヘッダーとフッター
リストの周りに任意の要素を配置できます。 たとえば、2つのTextViewの間にリストテンプレートを作成できます。 これを行う場合、リストビューにID「@android:id / list」を指定する必要があります。 ListActivityは、この識別子を持つビューを検索します。 この場合、1つのTextViewは常にListView(ヘッダー)の上に表示され、もう1つは下に表示されます。 リストの末尾/先頭でのみフッターとヘッダーを使用して固定しないようにするには、view.setHeaderView()またはview.setFooterView()を使用する必要があります。次に例を示します。
package de.vogella.android.listactivity; import android.app.ListActivity; import android.os.Bundle; import android.view.View; import android.widget.ArrayAdapter; import android.widget.ListView; public class MyList extends ListActivity { /** . */ public void onCreate(Bundle icicle) { super.onCreate(icicle); // , ListActivity String[] names = new String[] { "Linux", "Windows7", "Eclipse", "Suse", "Ubuntu", "Solaris", "Android", "iPhone", "Linux", "Windows7", "Eclipse", "Suse", "Ubuntu", "Solaris", "Android", "iPhone" }; View header = getLayoutInflater().inflate(R.layout.header, null); View footer = getLayoutInflater().inflate(R.layout.footer, null); ListView listView = getListView(); listView.addHeaderView(header); listView.addFooterView(footer); setListAdapter(new ArrayAdapter<String>(this, android.R.layout.simple_list_item_single_choice, android.R.id.text1, names)); } }
SimpleCursorAdapter
データベースまたはコンテンツを直接操作している場合は、SimpleCursorAdapterを使用してデータをListViewに転送できます。
アクティビティ「MyListActivity」で新しいプロジェクト「de.vogella.android.listactivity.cursor」を作成します。 そのようなアクティビティを作成します。
package de.vogella.android.listactivity.cursor; import android.app.ListActivity; import android.database.Cursor; import android.net.Uri; import android.os.Bundle; import android.provider.ContactsContract; import android.widget.ListAdapter; import android.widget.SimpleCursorAdapter; public class MyListActivity extends ListActivity { /** */ @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); Cursor mCursor = getContacts(); startManagingCursor(mCursor); // , // SimpleListAdapter . ListAdapter adapter = new SimpleCursorAdapter(this, // . android.R.layout.two_line_list_item, // mCursor, // , . // , . new String[] { ContactsContract.Contacts._ID, ContactsContract.Contacts.DISPLAY_NAME }, // , new int[] { android.R.id.text1, android.R.id.text2 }); // . setListAdapter(adapter); } private Cursor getContacts() { // Uri uri = ContactsContract.Contacts.CONTENT_URI; String[] projection = new String[] { ContactsContract.Contacts._ID, ContactsContract.Contacts.DISPLAY_NAME }; String selection = ContactsContract.Contacts.IN_VISIBLE_GROUP + " = '" + ("1") + "'"; String[] selectionArgs = null; String sortOrder = ContactsContract.Contacts.DISPLAY_NAME + " COLLATE LOCALIZED ASC"; return managedQuery(uri, projection, selection, selectionArgs, sortOrder); } }
アプリに連絡先へのアクセス権を付与してください。 (AndroidManifest.xmlで「android.permission.READ_CONTACTS」を使用します)。
ご清聴ありがとうございました。 翻訳に対するコメントと修正は大歓迎です。 ソースにもエラーとタイプミスがあります。
再投稿をおpoびします。最初は翻訳としてマークしませんでしたが、最近ここにいます。 jestonのヒントに感謝し 、注意を払い 、間違いから学びました。