意外と面倒だったのでメモしておく。
■実装
res/layout-v11/cell.xml
API level 11以降の場合は以下のように記述すれば終わる。
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="fill_parent" android:layout_height="wrap_content" android:background="?android:attr/activatedBackgroundIndicator" android:orientation="vertical"> <TextView android:id="@+id/name" android:layout_width="fill_parent" android:layout_height="wrap_content"/> <TextView android:id="@+id/text" android:layout_width="fill_parent" android:layout_height="wrap_content"/> </LinearLayout>
res/layout/cell.xml
上述のlayoutファイルしかないとAPI level 10以下で実行できなくなるので以下のレイアウトファイルを追加する。
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="fill_parent" android:layout_height="wrap_content" android:orientation="vertical"> <TextView android:id="@+id/name" android:layout_width="fill_parent" android:layout_height="wrap_content"/> <TextView android:id="@+id/text" android:layout_width="fill_parent" android:layout_height="wrap_content"/> </LinearLayout>
DataListCursorAdapter.java
bindViewでonDataAssignedを実行するようにする。
class DataListCursorAdapter extends CursorAdapter { private Listener mListener; public static class ViewHolder { public TextView name; public TextView text; } @SuppressWarnings("deprecation") public DataListCursorAdapter(Context context, Cursor c, Listener listener) { super(context, c); mListener = listener; } public DataListCursorAdapter(Context context, Cursor c, Listener listener, boolean autoRequery) { super(context, c, false); mListener = listener; } public DataListCursorAdapter(Context context, Cursor c, Listener listener, int flags) { super(context, c, FLAG_REGISTER_CONTENT_OBSERVER); mListener = listener; } @Override public void bindView(View view, Context context, Cursor cursor) { try { ViewHolder holder = (ViewHolder) view.getTag(); JSONObject json = new JSONObject(cursor.getString(cursor.getColumnIndex(Table.DATA))); final Data data = new Data(json); mListener.onDataAssigned(data, view); holder.name.setText(data.name); holder.text.setText(data.text); } catch (JSONException e) { } } @Override public View newView(Context context, Cursor cursor, ViewGroup parent) { LayoutInflater inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE); View view = inflater.inflate(R.layout.cell, null); ViewHolder holder = new ViewHolder(); holder.name = (TextView) view.findViewById(R.id.name); holder.text = (TextView) view.findViewById(R.id.text); view.setTag(holder); return view; } public interface Listener { public void onDataAssigned(Data data, View view); } }
DataListFragment.java
ListViewは画面サイズを敷き詰めるのに十分な数のViewを生成し、スクロールして表示される項目についてはViewの中身を入れ替えるだけで実現しているので省メモリで高速である。一方で選択項目のViewの背景色を変えるとそのViewを再利用した項目の背景色も変わってしまう。従って、以下のようにinterfaceを実装してHoney Comb未満ではデータがbindされた時にリストの背景色を確認・変更するようにする。
@Override public void onDataAssigned(Data data, View view) { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) { return; } if (TextUtils.equals(mLastSelectedDataId, data.id)) { view.setBackgroundColor(0xfff7aecb); } else { view.setBackgroundColor(0x00000000); } }
最後にタップしたリストのデータをフィールドに保持するようにする。
@Override public void onItemClick(AdapterView<?> listView, View view, int position, long id) { Cursor cursor = mArrayCursorAdapter.getCursor(); JSONObject json = new JSONObject(cursor.getString(cursor.getColumnIndex(Table.DATA))); final Data data = new Data(json); if (data != null && TextUtils.equals(mLastSelectedDataId, data.id)) { getListView().setItemChecked(position, false); mLastSelectedDataId = null; } else if (data != null) { getListView().setItemChecked(position, true); mLastSelectedDataId = data.id; } }