Android-long press ListView uses context menu (ActionMode) for batch event processing, androidactionmode

Source: Internet
Author: User

Android-long press ListView uses context menu (ActionMode) for batch event processing, androidactionmode

I haven't written a blog for a long time '''''''

I finally got a little idle recently '''''''

Boring to clean up text messages with mobile phones, and found that batch event processing is still quite useful ''''''

Let's take a look at the effect by yourself '''''


Let's talk less about it. First, let's take a look at the effects of batch deletion in the text message function provided by the mobile phone:



Then there is the effect of our own simple shanzhai:


The simulated operation process is very simple, but also representative.

Let's assume that we are in the scenario of entering a page for storing the contact list.


Therefore, we first define a progress box to simulate a prompt that the data is being downloaded from the network.

Then, after the network data is successfully downloaded to the mobile device, the data is bound to the corresponding ListView.

Next, we mentioned in this blog: The ListView trigger event of Long-pressing the contact list,

The Context Menu Using ActionMode is displayed, and the list items in the ListView can be reproduced for batch operations.

Finally, after you select a certain number of options, click items in the menu to perform a batch operation, execute the corresponding operation, and refresh the ListView.


Clarified the general effects we want to achieve, and then what we want to do

It is to sort out the ideas, and then gradually write the code to complete the implementation work. Let's do it!


First, we know that we want to use a contact list as a scenario.

Naturally, we need a ListView to bind and store the contact data.

Therefore, we will first create the layout files that store the ListView and the details of the items that define the ListView, respectively:


Context_menu_action_mode.xml

<?xml version="1.0" encoding="utf-8"?><LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"    android:layout_width="match_parent"    android:layout_height="match_parent"    android:orientation="vertical" >    <ListView        android:id="@+id/context_menu_listView"        android:layout_width="match_parent"        android:layout_height="match_parent" /></LinearLayout>

Context_menu_action_mode_item.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="match_parent"    android:paddingBottom="@dimen/activity_vertical_margin"    android:paddingLeft="@dimen/activity_horizontal_margin"    android:paddingRight="@dimen/activity_horizontal_margin"    android:paddingTop="@dimen/activity_vertical_margin" >    <ImageView        android:id="@+id/user_head"        android:layout_width="55dp"        android:layout_height="55dp"        android:contentDescription="@string/user_head_description"        android:src="@drawable/headimage_default" />    <TextView        android:id="@+id/user_name"        android:layout_width="wrap_content"        android:layout_height="wrap_content"        android:layout_marginLeft="20dp"        android:layout_marginStart="20dp"        android:layout_toEndOf="@id/user_head"        android:layout_toRightOf="@id/user_head"        android:textSize="25sp" />    <TextView        android:id="@+id/phone_number"        android:layout_width="wrap_content"        android:layout_height="wrap_content"        android:layout_alignBottom="@id/user_head"        android:layout_marginLeft="20dp"        android:layout_marginStart="20dp"        android:layout_toEndOf="@id/user_head"        android:layout_toRightOf="@id/user_head" />    <CheckBox        android:id="@+id/contact_selected_checkbox"        android:layout_width="wrap_content"        android:layout_height="wrap_content"        android:layout_alignParentEnd="true"        android:layout_alignParentRight="true"        android:layout_centerVertical="true"        android:clickable="false"        android:focusable="false" /></RelativeLayout>

There is no difficulty in defining the layout.

The only thing we need to note is that for a more friendly interactive experience, after the user presses the ListView to enter the checkable mode,

A CheckBox is added to the rightmost of each list to indicate whether the list item you want to operate is successfully selected.

The CheckBox is displayed only after the user enters the check mode. Therefore, we need to pay attention to the dynamic control of the display in the code.

And! Remember to set the value of the clickable and focusable attributes of CheckBox to false!

The reason for this is that CheckBox (defined in the Item file of ListView) has a higher priority than ListView in response focus and click events.

Therefore, if you forget to set it, the focus and response events will be blocked in the CheckBox and cannot reach the ListView.


Step 2, after we have defined the relevant procedures of ListView, we will naturally not forget its good friend: Adapter

MyContactAdapter. java:

Package com. example. android_menu_test_demo.adapter; import java. util. arrayList; import com. example. android_menu_test_demo.R; import com. example. android_menu_test_demo.domain.Contact; import android. content. context; import android. view. layoutInflater; import android. view. view; import android. view. viewGroup; import android. widget. baseAdapter; import android. widget. checkBox; import android. widget. imageView; import android. widget. textView; public class MyContactAdapter extends BaseAdapter {private Context mContext; private ArrayList <Contact> contacts; private ViewHolder mViewHolder; private ArrayList <Contact> selected_contacts = new ArrayList <Contact> (); private boolean itemMultiCheckable; public MyContactAdapter (Context mContext, ArrayList <Contact> contacts) {this. mContext = mContext; this. contacts = contacts;} @ Overridepublic int getCount () {return contacts. size () ;}@ Overridepublic Object getItem (int position) {return contacts. get (position) ;}@ Overridepublic long getItemId (int position) {return position ;}@ Overridepublic View getView (int position, View convertView, ViewGroup parent) {if (convertView = null) {convertView = LayoutInflater. from (mContext ). inflate (R. layout. contact_listview_item, null); mViewHolder = new ViewHolder (); mViewHolder. user_head = (ImageView) convertView. findViewById (R. id. user_head); mViewHolder. user_name_text = (TextView) convertView. findViewById (R. id. user_name); mViewHolder. phone_number_text = (TextView) convertView. findViewById (R. id. phone_number); mViewHolder. item_seleted = (CheckBox) convertView. findViewById (R. id. contact_selected_checkbox); convertView. setTag (mViewHolder);} else {mViewHolder = (ViewHolder) convertView. getTag ();} // ***************************** // set whether the checkbox is visible if (itemMultiCheckable) {mViewHolder. item_seleted.setVisibility (View. VISIBLE); // if the checkbox is VISIBLE, it indicates that the checkbox is currently in a multi-choice operation, you can set the checkbox selected status if (selected_contacts.contains (contacts. get (position) {mViewHolder. item_seleted.setChecked (true);} else {mViewHolder. item_seleted.setChecked (false) ;}} else {mViewHolder. item_seleted.setVisibility (View. GONE);} // control value: Contact contact = contacts. get (position); mViewHolder. user_name_text.setText (contact. getUserName (); mViewHolder. phone_number_text.setText (contact. getPhoneNumber (); return convertView;} public void setItemMultiCheckable (boolean flag) {itemMultiCheckable = flag;} public void addSelectedContact (int position) {selected_contacts.add (contacts. get (position);} public void cancelSeletedContact (int position) {selected_contacts.remove (contacts. get (position);} public void clearSeletedContacts () {selected_contacts = new ArrayList <Contact> ();} public void deleteSeletedContacts () {for (Contact contact: selected_contacts) {contacts. remove (contact) ;}} static class ViewHolder {ImageView user_head; TextView user_name_text, phone_number_text; CheckBox item_seleted ;}}

The definition of the adapter class is not much different from the most common definition in our development.

The Code worth noting is nothing more than what we mentioned earlier. Do a good job of dynamically controlling the CheckBox display status.

In addition, in the adapter definition, in order to make the data to be displayed by listview easier to load and transmit,

The entity class that encapsulates data is usually defined, just like the Contact class above. However, this is too simple and there is no need to post code.


Next, we will focus on the functions we want to implement,

We want to trigger a context menu through the long-Click Event of ListView for event processing.

Compared with the normal context menu, the ActionMode added after Android 3.0,

Obviously, it is more suitable for batch event processing and has a better interactive experience.


Therefore, since the context menu will be used, it is not necessary to talk about it.

First define a simple menu file we need:

Multi_acitonmode_menu.xml:

<?xml version="1.0" encoding="utf-8"?><menu xmlns:android="http://schemas.android.com/apk/res/android" >    <item        android:id="@+id/menu_cancle"        android:showAsAction="always"        android:title="@string/item_cancle"/>            <item        android:id="@+id/menu_delete"        android:showAsAction="always"        android:title="@string/item_delete"/></menu>

Next, we are all ready for all preparations,

The next step is to write the Activity code.

ContextMenuActionModeActivity. java

Package com. example. android_menu_test_demo; import android. view. actionMode; import android. view. layoutInflater; import android. view. menu; import android. view. menuItem; import android. view. view; import android. widget. listView; import android. widget. textView; import android. widget. absListView. multiChoiceModeListener; import java. util. arrayList; import com. example. android_menu_test_demo.adapter.MyContactAdapter; import com. example. android_menu_test_demo.domain.Contact; import android. annotation. targetApi; import android. app. activity; import android. app. progressDialog; import android. OS. asyncTask; import android. OS. build; import android. OS. bundle; @ TargetApi (Build. public class ContextMenuActionModeActivity extends Activity {private ListView contact_list_view; private ProgressDialog mDialog; private MyContactAdapter mAdpater; private MultiModeCallback mCallback; // simulate private ArrayList <Contact> contacts; private String [] userNames = new String [] {"Jack", "Rose", "Matt", "Adam", "Xtina", "Blake", "Tupac ", "Biggie", "T. I "," Eminem "}; private String [] phoneNumbers = new String [] {" 138-0000-0001 "," 138-0000-0002 ", "138-0000-0003", "138-0000-0004", "138-0000-0005", "138-0000-0006", "138-0000-0007 ", "138-0000-0008", "138-0000-0009", "138-0000-0010"}; @ Overrideprotected void onCreate (Bundle savedInstanceState) {super. onCreate (savedInstanceState); setContentView (R. layout. context_menu_action_mode); initView (); new contactsdownloadtask(.exe cute ();} private void initView () {contact_list_view = (ListView) this. findViewById (R. id. context_menu_listView); mDialog = new ProgressDialog (this); mDialog. setTitle ("prompt message"); mDialog. setMessage ("Download contact list... "); mDialog. setProgressStyle (ProgressDialog. STYLE_HORIZONTAL); mCallback = new MultiModeCallback (); contact_list_view.setChoiceMode (ListView. CHOICE_MODE_MULTIPLE_MODAL); callback (mCallback);} private void downloadContactsFromServer () {if (contacts = null) {contacts = new ArrayList <Contact> ();} for (int I = 0; I <userNames. length; I ++) {contacts. add (new Contact (userNames [I], phoneNumbers [I]) ;}} private class ContactsDownloadTask extends AsyncTask <Void, Integer, Void> {private int currentlyProgressValue; @ Overrideprotected void onPreExecute () {mDialog. show (); super. onPreExecute () ;}@ Overrideprotected Void doInBackground (Void... params) {while (currentlyProgressValue <100) {publishProgress (++ currentlyProgressValue); try {Thread. sleep (20);} catch (InterruptedException e) {e. printStackTrace () ;}// download data from serverdownloadContactsFromServer (); return null ;}@ Overrideprotected void onProgressUpdate (Integer... values) {super. onProgressUpdate (values); mDialog. setProgress (values [0]);} @ Overrideprotected void onPostExecute (Void result) {super. onPostExecute (result); mAdpater = new MyContactAdapter (ContextMenuActionModeActivity. this, contacts); contact_list_view.setAdapter (mAdpater); mDialog. dismiss () ;}} private class MultiModeCallback implements MultiChoiceModeListener {private View mMultiSelectActionBarView; private TextView mSelectedCount; @ Overridepublic boolean onCreateActionMode (ActionMode mode, Menu menu) {mode. getMenuInflater (). inflate (R. menu. multi_acitonmode_menu, menu); mAdpater. setItemMultiCheckable (true); mAdpater. notifyDataSetChanged (); if (mMultiSelectActionBarView = null) {mMultiSelectActionBarView = LayoutInflater. from (ContextMenuActionModeActivity. this ). inflate (R. layout. list_multi_select_actionbar, null); mSelectedCount = (TextView) mMultiSelectActionBarView. findViewById (R. id. selected_conv_count);} mode. setCustomView (mMultiSelectActionBarView); (TextView) mMultiSelectActionBarView. findViewById (R. id. title )). setText (R. string. select_item); return true ;}@ Overridepublic boolean onPrepareActionMode (ActionMode mode, Menu menu) {// TODO Auto-generated method stubreturn false;} @ Overridepublic boolean onActionItemClicked (ActionMode mode, menuItem item) {switch (item. getItemId () {case R. id. menu_cancle: mAdpater. setItemMultiCheckable (false); mAdpater. clearSeletedContacts (); mAdpater. notifyDataSetChanged (); mode. finish (); break; case R. id. menu_delete: mAdpater. deleteSeletedContacts (); mAdpater. notifyDataSetChanged (); mode. invalidate (); mode. finish (); break; default: break;} return false;} @ Overridepublic void onDestroyActionMode (ActionMode mode) {mAdpater. setItemMultiCheckable (false); mAdpater. clearSeletedContacts (); mAdpater. policydatasetchanged () ;}@ Overridepublic void onItemCheckedStateChanged (ActionMode mode, int position, long id, boolean checked) {if (checked) {mAdpater. addSelectedContact (position);} else {mAdpater. cancelSeletedContact (position);} mAdpater. notifyDataSetChanged (); updateSeletedCount (); mode. invalidate ();} public void updateSeletedCount () {mSelectedCount. setText (Integer. toString (contact_list_view.getCheckedItemCount () + "bar ");}}}

For cainiao like ours, the above activity code may be worth noting:

1. Basically, we will first define an asynchronous task class to simulate the process of downloading data from the network. This helps you understand the use of Adapter APIs.

2. We defined the internal class that implements the MultiChoiceModeListener interface in the above Code. MultiModeCallback is the key to helping us implement the long-pressed ListView (also used in the GridView) and listen to the key to handling MultiChoice events.

-In simple terms, we can see that in the internal class callback method onCreateActionMode, we can process the creation work related to the ActionMode menu after long-pressed ListView. In addition, the CheckBox display in ListView is controlled to inform users that we have entered the batch operation mode.

-The onActionItemClicked method is used to listen to and respond to the click events of corresponding options on the menu. You can compile the response code for corresponding menu options based on your needs.

-The onDestroyActionMode method is used to process the action to be executed when the menu is destroyed.

-The onItemCheckedStateChanged method is used to listen for the callback when the selected status of each list item in the ListView changes. We will complete the corresponding Encoding As needed here.

3. Here, we can say that the implementation of the functions we want is basically done. However, you may have noticed the following points in some code of the above MultiModeCallback class:

To make interactions more friendly, we can also add a piece of content on the menu bar in the form of ActionBar, as in the text message function, it is used to prompt the user for information similar to "XX items have been selected currently. Therefore, we will also define a layout file similar to ActionBar, as shown below:

List_multi_select_actionbar.xml:

<LinearLayout    xmlns:android="http://schemas.android.com/apk/res/android"    android:id="@+id/custom_title_root"    android:layout_width="match_parent"    android:layout_height="match_parent"    android:orientation="horizontal">    <TextView        android:id="@+id/title"        android:layout_gravity="center_vertical"        android:layout_height="wrap_content"        android:layout_width="wrap_content"        android:textColor="#ffffff" />    <TextView        android:id="@+id/selected_conv_count"        android:layout_gravity="center_vertical"        android:layout_width="wrap_content"        android:layout_height="wrap_content"         android:textColor="#ffffff"/></LinearLayout>

In the above code, you can see that we load the ActionMode context menu in the onCreateActionMode method, at the same time, it also loads and controls the View used as the ActionBar.

After loading and displaying the View, we need to listen in onItemCheckedStateChanged. When you select a list item, update the display content of the TextView used to display the prompt information.


In this step, we can say that it has been completed. The next step is to compile the Demo to the simulator or mobile phone to see the effect ~


Copyright Disclaimer: This article is an original article by the blogger and cannot be reproduced without the permission of the blogger.

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.