好久没写博客拉```````

近期最终略微闲一点了```````

无聊拿手机清理短信。发现批量事件的处理还是挺管用的``````

那么自己也来山寨一记看看效果吧`````

闲话少说,首先,我们来看下手机自带的短信功能里运行批量删除时的效果:

然后  是我们自己简单山寨的效果:

     

模拟的操作过程非常easy,但也非常有代表性。

我们假定我们所处的场景为。进入一个存放联系人列表的界面。

于是,首先我们定义了一个进度框,模拟提示正在从网络上下载数据。

接着。当网络数据成功下载到移动设备上后,将数据绑定显示到相应的ListView之中。

然后,就是我们这篇博客提到的:长按该联系人列表的ListView触发事件。

弹出使用ActionMode的上下文菜单。并让该ListView中的列表项支持复现,实现批量操作。

最后。就是当用户选择了一定数量的选项后。点击菜单中的Item进行某项批量操作后,运行相应的操作,并刷新ListView。

理清了我们想要实现的大致效果,接着我们要做的

就是整理一下思路,然后逐步的去编写代码,完毕实现工作。let's do it !

首先,我们已经知道了自己 想要以一个联系人列表作为场景。

那么,自然我们会须要一个ListView来绑定和存放这些联系人数据。

于是,我们先将存放ListView以及定义该ListView的Item的细节的布局文件搞出来,分别为:

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" ><ListViewandroid: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>

关于布局的定义。并没有什么难点。

唯一须要注意的是,我们为了更加友好的交互体验,所以在用户长按ListView进入可复选的模式后,

在每一个列表的最右側加入显示了一个CheckBox,以提示用户是否成功选择到了想要操作的列表项。

CheckBox仅仅有在用户进入复选模式后,才显示,所以我们须要在后面注意在代码中动态的控制其显示情况。

而且!更须要注意的是,记得将CheckBox的clickable与focusable两个属性的值设置为false!

这样做的原因是由于CheckBox(定义在作为ListView的Item文件其中)自身的响应焦点及点击事件的优先级高于ListView自身。

所以。假设忘记设置的话,焦点及响应事件将被拦截在CheckBox,无法到达ListView。

第二步,当我们定义好了ListView的相关程序之后,自然忘不了它的好基友:适配器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();}// ************对于控件的详细处理****************// 设置checkbox是否可见if (itemMultiCheckable) {mViewHolder.item_seleted.setVisibility(View.VISIBLE);// 假设checkbox可见。证明当前处于可多选操作情况下,则依据用户选择情况设置checkbox被选中状态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);}// 控件赋值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;}
}

适配器类的定义与我们开发中最常见的定义并没有太多差别。

值得注意的的代码,无非就是前面谈到的,做好动态控制CheckBox显示状态的工作。

另外,我们在适配器的定义中,为了让listview要显示的数据,更便于装载和传递。

一般会定义封装数据的实体类,正如上面的Contact类。只是这个太简单,就没贴代码的必要了。

接下来。就是我们想要实现的功能的重点了,

我们说到希望通过ListView的长点击事件,来触发一个上下文菜单来进行事件处理。

在Android 3.0之后加入的ActionMode相对于之前的普通上下文菜单。

显然更适合对于批量事件的处理。有着更好的交互体验。

所以说。既然将要使用到上下文 菜单,那么。废话少说。

先定义一个我们须要的简单的菜单文件:

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>

紧接着,一切准备 工作我们都已经基本就绪,

那么接下来要做的。自然就是Activity的代码编写工作了。

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.VERSION_CODES.HONEYCOMB)
public class ContextMenuActionModeActivity extends Activity {private ListView contact_list_view;private ProgressDialog mDialog;private MyContactAdapter mAdpater;private MultiModeCallback mCallback;// 模拟数据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().execute();}private void initView() {contact_list_view = (ListView) this.findViewById(R.id.context_menu_listView);mDialog = new ProgressDialog(this);mDialog.setTitle("提示信息");mDialog.setMessage("下载联系人列表中...");mDialog.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL);mCallback = new MultiModeCallback();contact_list_view.setChoiceMode(ListView.CHOICE_MODE_MULTIPLE_MODAL);contact_list_view.setMultiChoiceModeListener(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.notifyDataSetChanged();}@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()) + "条");}}}

对于我们这种菜鸟来说,上面activity代码中值得注意的可能是:

1、基本上,我们首先会定义一个异步任务类。模拟从网络下载数据的过程。有助于Adapter的API的使用的掌握。

2、我们在上面代码中定义的实现了MultiChoiceModeListener接口的内部类,MultiModeCallback就是帮助我们实现长按ListView(也试用于GridView)。而且监听处理MultiChoice事件的关键。

—  简单来说,能够看到。我们在该内部类的回调方法onCreateActionMode中,处理长按ListView后,ActionMode菜单相关的创建工作。而且在此控制ListView中的CheckBox显示,告知用户,我们已经进入到了能够进行批量操作的模式下。

—  onActionItemClicked方法 用于监听和响应菜单上相应的选项的点击事件,你能够在此依据自己的需求,为相应的菜单选项编写响应代码。

—  onDestroyActionMode方法 用于处理菜单销毁时,所要运行的动作。

—  而onItemCheckedStateChanged方法 则就是用于监听处理ListView中每一个列表项的选中状态改变时的回调了。我们会在这里依据需求完毕相应的编码工作。

3、到了这里,我们对于我们想要的功能的实现,能够说已经是基本搞定了。可是,你可能已经在上面的MultiModeCallback类的某些代码中注意点到:

为了更加友善的交互感受,我们 还能够以ActionBar的形式。在菜单条上,加入一段内容。正如 短信功能里所使用的那样,用以提示用户类似于“您当前已经选择了XX条内容”的信息。所以我们还会定义一个类似ActionBar的布局文件。例如以下:

list_multi_select_actionbar.xml:

<LinearLayoutxmlns: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"><TextViewandroid:id="@+id/title"android:layout_gravity="center_vertical"android:layout_height="wrap_content"android:layout_width="wrap_content"android:textColor="#ffffff" /><TextViewandroid:id="@+id/selected_conv_count"android:layout_gravity="center_vertical"android:layout_width="wrap_content"android:layout_height="wrap_content" android:textColor="#ffffff"/></LinearLayout>

在上面的代码中,你能够看到,我们相同是在onCreateActionMode方法中完毕ActionMode上下文菜单的装载工作的同一时候,也会进行对于该作为ActionBar使用的View的装载与显示控制工作。

在该View装载和显示工作完毕之后,我们要做的就非常easy了,仅仅须要在onItemCheckedStateChanged中进行监听,当用户选中某个列表项时,对用于显示提示信息的TextView的显示内容进行更新,则OK了。

走到这一步,我们能够说是已经山寨完成了,下一步要做的则能够将Demo编译到模拟器或者手机上,看看效果了~

Android — 长按ListView 利用上下文菜单(ActionMode) 进行批量事件处理相关推荐

  1. android 动态contextmenu,Android成长日记-ContextMenu实现上下文菜单

    一. ContextMenu的组成 标题以及标题图标 菜单内容 菜单内容的点击事件 二. ContextMenu与OptionMenu的区别 OptionMenu对应的是activity,一个acti ...

  2. Android进阶(二十八)上下文菜单ContextMenu使用案例

    上下文菜单ContextMenu使用案例 前言 回顾之前的应用程序,发现之前创建的选项菜单无法显示了.按照正常逻辑来说,左图中在"商品信息"一栏中应该存在选项菜单,用户可进行分享等 ...

  3. android长按呼出菜单,Android系统下长按菜单的实现方式

    Android系统中的ContextMenu(上下文菜单)类似于PC中的右键弹出菜单,当一个视图注册到一个上下文菜单时,执行一个在该对象上的"长按"动作,将出现一个提供相关功能的浮 ...

  4. Android 的上下文菜单: Context Menu

    本文转载自: https://www.cnblogs.com/hibraincol/archive/2010/09/30/1839014.html 作者:hibraincol 转载请注明该声明. 概述 ...

  5. Android 上下文菜单实现

    1.覆盖Activity的onCreateContenxtMenu()方法,调用Menu的add方法添加菜单项(MenuItem). 2.覆盖Activity的onContextItemSelecte ...

  6. (4.0.15.3)Android 的上下文菜单: ContextMenu的使用方法以及与OptionMenu的区别

    ContextMenu是Android的context menu上下文菜单,选择某项VIEW后长按menu键,就会显示出来.比如EditeText就可以通过长按来弹出拥有"cut" ...

  7. Android 的上下文菜单: Context Menu,registerForContextMenu(getListView())

    概述: Android 的上下文菜单类似于 PC 上的右键菜单.当为一个视图注册了上下文菜单之后,长按(2 秒左右)这个视图对象就会弹出一个浮动菜单,即上下文菜单.任何视图都可以注册上下文菜单,不过, ...

  8. 5.4 Android 的上下文菜单: Context Menu,registerForContextMenu(getListView())

    Android 的上下文菜单: Context Menu,registerForContextMenu(getListView()) Android 的上下文菜单类似于 PC 上的右键菜单.当为一个视 ...

  9. 学习之路(一)Android 的上下文菜单: Context Menu,registerForContextMenu(getListView());

    概述: Android 的上下文菜单类似于 PC 上的右键菜单.当为一个视图注册了上下文菜单之后,长按(2 秒左右)这个视图对象就会弹出一个浮动菜单,即上下文菜单.任何视图都可以注册上下文菜单,不过, ...

最新文章

  1. ContextCompat.checkSelfPermission()方法中的第二个参数
  2. 人脸分割 人脸解析 源码推荐
  3. 深度学习(Deep Learning):循环神经网络一(RNN)
  4. Asp.Net Core 混合全球化与本地化支持
  5. java培训就是害人的_[Java教程]粗心害死人啊,我的天。
  6. 谈谈对MVC的理解(View+Model+Controller)
  7. 打包jar文件 外部调用资源 so等
  8. 怎么用c语言写贪吃蛇贴吧,刚学C语言,想写一个贪吃蛇的代码
  9. thinkphp3.1 mysql5.6_ThinkPHP3.1新特性之多数据库操作更加完善
  10. matlab热度图确定色标_MATLAB 颜色图函数(imagesc/scatter/polarPcolor/pcolor)
  11. arcgis怎么压缩tif文件_PDF文件怎么压缩?这个方法千万别错过了!
  12. 服务器cpu占用过高一般是什么原因,如何解决服务器cpu使用率过高的問題
  13. FunCoolShell
  14. 滴滴裁员 多一个月补偿反转苦情戏
  15. vue打测试包和正式包的配置
  16. 移动开发视频资源百度网盘地址分享
  17. 先序遍历、中序遍历、后序遍历
  18. java ean13 计算_实训java第三课 for 逻辑运算符 条件判断 商品条形码Ean-13验证码生成...
  19. 【无标题】2022年汽车修理工(高级)考试练习题及在线模拟考试
  20. Deqin- 升级版测手速游戏

热门文章

  1. 利用MyEclipse开发一个调用webservice接口的程序
  2. 网络故障排除连载之一:常用排除方法综述
  3. C# WINFORM 自定义窗体 皮肤[转]
  4. HTML数字比较大小游戏,Javascript 比较两个数大小并输出最大数
  5. python3的星期函数_calendar在python3时间中有哪些常用函数?怎么用?
  6. 【python教程入门学习】如何把Python学好
  7. 软件质量保证计划_软件测试计划 笔记
  8. 怎么获取请求头中的origin信息_委托单位代办汇算清缴时无法获取到我的专项附加扣除信息怎么办?...
  9. python数字类型转换函数_Python的数据类型转换函数
  10. linux 查看 内存 占用,Linux终端:用smem查看内存占用情况