新しいGmailのように、コンテキストアクションバーを使用してリストビューを作成する





何を手に入れたいですか



行アイコンをクリックするか、長押しすることにより、行を選択する機能を備えたスムーズに機能するリストを作成します。 また、選択が無駄にならないように、選択したオブジェクトでユーザーが特定のアクションを実行できるようにする必要があります。







リストのマークアップを作成する



そのため、まず、リストを配置するレイアウトを作成する必要があります。次のようになります。



<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" android:paddingLeft="@dimen/activity_horizontal_margin" android:paddingRight="@dimen/activity_horizontal_margin" android:paddingTop="@dimen/activity_vertical_margin" android:paddingBottom="@dimen/activity_vertical_margin" tools:context=".MainActivity"> <ListView android:id="@android:id/list" android:layout_width="fill_parent" android:layout_height="fill_parent"/> </RelativeLayout>
      
      





アンドロイド開発者スタジオによって私のために親切に作成された多くのパッドは別として、ここには何も面白いものはありません。 念のために: android:id / listは、ListActivityとListFragmentが知っている特別に割り当てられたIDです。



次に、ListViewの各行になるレイアウトを作成します。

 <?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="match_parent" android:orientation="vertical" android:background="?android:attr/activatedBackgroundIndicator"> <View android:id="@+id/item_image" android:layout_width="45dp" android:layout_height="45dp" android:layout_margin="5dp" android:padding="10dp"/> <TextView android:id="@+id/item_text" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_toRightOf="@id/item_image" android:layout_marginTop="10dp" android:layout_marginLeft="10dp" android:text="TextView" android:layout_gravity="center_vertical|left" android:textAppearance="?android:textAppearanceListItem"> </TextView> </RelativeLayout>
      
      





ここでは、ビューの右側にTextViewがあります。 ビューの代わりに、通常は画像がありますが、この例では、ランダムに生成された色を単純に表示します。

また、レイアウトプロパティのandroid:background = "?Android:attr / activatedBackgroundIndicator"にも注意してください。 この属性がないと、選択の視覚効果は表示されません。



ListViewを作成してデータを入力します



すぐにアクティビティコードを提供し、説明します。

 public class MainActivity extends ListActivity { public static final String TAG = "FOR_HABR"; private Random randomGenerator = new Random(); @Override protected void onCreate(Bundle savedInstanceState) { Log.d(TAG, "onCreate"); super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); //    int size = getRandomNumber(200); ListView listView = getListView(); //     Integer[] colors = generateListOfColors(size).toArray(new Integer[0]); ArrayAdapter<Integer> customAdapter = new CustomAdapter(this, R.layout.list_view_row, colors, listView); listView.setAdapter(customAdapter); } @Override public boolean onCreateOptionsMenu(Menu menu) { Log.d(TAG, "onCreateOptionsMenu"); getMenuInflater().inflate(R.menu.main, menu); return true; } //     private List<Integer> generateListOfColors(int size) { List<Integer> result = new ArrayList<Integer>(); for (int i = 0; i < size; i++) { result.add(generateRandomColor()); } return result; } //   private int generateRandomColor() { return Color.rgb(getRandomNumber(256), getRandomNumber(256), getRandomNumber(256)); } private int getRandomNumber(int maxValue) { return randomGenerator.nextInt(maxValue); } }
      
      





ここでは、最初にシートが配置されるIDレイアウトを見つけ、このアクティビティのコンテンツを割り当てます。 ListViewに情報を入力するために、最初に数字のリストを生成し、それをカスタムアダプターのコンストラクターに渡します。

アダプターは、データと表示の間のブリッジです。アダプターは、リストの各行のどこでどのコンポーネントを見たいかをシステムに伝えます。 アダプタのコードは次のとおりです。

 public class CustomAdapter extends ArrayAdapter<Integer> { private ListView listView; public CustomAdapter(Context context, int textViewResourceId, Integer[] objects, ListView listView) { super(context, textViewResourceId, objects); this.listView = listView; } static class ViewHolder { TextView text; View indicator; } @Override public View getView(final int position, View convertView, ViewGroup parent) { Integer color = getItem(position); View rowView = convertView; // ,      if (rowView == null) { LayoutInflater inflater = ((Activity) getContext()).getLayoutInflater(); rowView = inflater.inflate(R.layout.list_view_row, parent, false); ViewHolder h = new ViewHolder(); h.text = (TextView) rowView.findViewById(R.id.item_text); h.indicator = rowView.findViewById(R.id.item_image); rowView.setTag(h); } ViewHolder h = (ViewHolder) rowView.getTag(); h.text.setText("#" + Integer.toHexString(color).replaceFirst("ff", "")); h.indicator.setBackgroundColor(color); return rowView; } }
      
      





親クラスの1つのメソッド、getViewメソッドのみを書き換えています。 このメソッドは、ユーザーの視界に新しいリスト行が表示されるたびに呼び出されます。 したがって、Viewオブジェクトを、ユーザーに表示するフォームでそこから返さなければなりません。

ここでは、オブジェクトを再利用することでListViewのパフォーマンスをわずかに(最大15%)向上させることができる人気のあるテンプレートを使用しています。 このテンプレートの詳細については、 こちらをご覧ください



この段階で、アプリケーションを起動できます。色付きのリストが表示されますが、もちろん、インタラクティブ機能はありません。



シリーズを選択する機能を追加します



これを行うには、次を実行します。

 // ListView,       listView.setChoiceMode(ListView.CHOICE_MODE_MULTIPLE_MODAL); //    listView.setMultiChoiceModeListener(new MultiChoiceImpl(listView));
      
      







ハンドラーは次のようになります。

 public class MultiChoiceImpl implements AbsListView.MultiChoiceModeListener { private AbsListView listView; public MultiChoiceImpl(AbsListView listView) { this.listView = listView; } @Override //        public void onItemCheckedStateChanged(ActionMode actionMode, int i, long l, boolean b) { Log.d(MainActivity.TAG, "onItemCheckedStateChanged"); int selectedCount = listView.getCheckedItemCount(); //     Context Action Bar setSubtitle(actionMode, selectedCount); } @Override //  CAB  xml public boolean onCreateActionMode(ActionMode actionMode, Menu menu) { Log.d(MainActivity.TAG, "onCreateActionMode"); MenuInflater inflater = actionMode.getMenuInflater(); inflater.inflate(R.menu.context_menu, menu); return true; } @Override public boolean onPrepareActionMode(ActionMode actionMode, Menu menu) { Log.d(MainActivity.TAG, "onPrepareActionMode"); return false; } @Override //     Item  AB public boolean onActionItemClicked(ActionMode actionMode, MenuItem menuItem) { String text = "Action - " + menuItem.getTitle() + " ; Selected items: " + getSelectedFiles(); Toast.makeText(listView.getContext(), text , Toast.LENGTH_LONG).show(); return false; } @Override public void onDestroyActionMode(ActionMode actionMode) { Log.d(MainActivity.TAG, "onDestroyActionMode"); } private void setSubtitle(ActionMode mode, int selectedCount) { switch (selectedCount) { case 0: mode.setSubtitle(null); break; default: mode.setTitle(String.valueOf(selectedCount)); break; } } private List<String> getSelectedFiles() { List<String> selectedFiles = new ArrayList<String>(); SparseBooleanArray sparseBooleanArray = listView.getCheckedItemPositions(); for (int i = 0; i < sparseBooleanArray.size(); i++) { if (sparseBooleanArray.valueAt(i)) { Integer selectedItem = (Integer) listView.getItemAtPosition(sparseBooleanArray.keyAt(i)); selectedFiles.add("#" + Integer.toHexString(selectedItem).replaceFirst("ff", "")); } } return selectedFiles; } }
      
      





おそらく、ここで新しいアクションバー(context_menu)が膨らんでいることに気づいたでしょう。 次のようになります。

 <menu xmlns:android="http://schemas.android.com/apk/res/android"> <item android:id="@+id/cab_add" android:icon="@android:drawable/ic_menu_add" android:orderInCategory="1" android:showAsAction="ifRoom" android:title="add"/> <item android:id="@+id/cab_share" android:icon="@android:drawable/ic_menu_share" android:orderInCategory="1" android:showAsAction="ifRoom" android:title="share"/> </menu>
      
      





だから、今順番に。 ListViewで、特別な選択モードCHOICE_MODE_MULTIPLE_MODALを設定します。これは、 AbsListView.MultiChoiceModeListenerインターフェイスを実装するListViewクラスをスリップすることを意味します。 このクラスでは、選択イベントで受け取るものを指定するメソッドを実装し、CABのアイテムをクリックするか、CABを破棄します。



ここで、アイコンをクリックして行を選択する機能を追加します。 これを行うには、getViewメソッドのOnClickListenerで停止します。

 h.indicator.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { selectRow(v); } private void selectRow(View v) { listView.setItemChecked(position, !isItemChecked(position)); } private boolean isItemChecked(int pos) { SparseBooleanArray sparseBooleanArray = listView.getCheckedItemPositions(); return sparseBooleanArray.get(pos); } });
      
      





ここで、行がすでに選択されている場合は選択を解除し、そうでない場合は選択します。



以上です。 完全なサンプルコードは、私のBitBucketにあります。



UPD。 この記事で使用されたほとんどすべてがAPI 11に追加され、14にも追加されました。したがって、API <11との互換性が必要な場合は、 こちらをご覧ください

素晴らしい開発仲間もいます-HoloEverywhere



All Articles