【凯子哥带你夯实应用层】使用ActionMode实现有删除动画的多选删除功能

转载请注明出处:http://blog.csdn.net/zhaokaiqiang1992

ActionMode是3.0之后,官方推荐的一种上下文菜单的实现方式,在之前一直用的是Context Menu,今天这篇文章简单介绍一下ActionMode,并实现多选删除功能。

如果要在ListView这类控件中实现多选,我们可以通过设置setChoiceMode(ListView.CHOICE_MODE_MULTIPLE_MODAL)来实现,然后通过设置setMultiChoiceModeListener之后,就可以开启ActionMode。ActionMode并不是一个View,只是一个操作模式,所以我们用的时候不能按照View的用法来使用。

下面是实现的效果图

这个和GMail的删除是不是很像?

因为ActionMode没有多少知识点要说,咱们就简单介绍下,然后上代码,这个功能主要其实主要是逻辑麻烦点,也很简单。

设置完多选模式监听器之后,我们需要实现下面的方法

mListView.setMultiChoiceModeListener(new MultiChoiceModeListener(){

			@Override
			public boolean onCreateActionMode(ActionMode mode, Menu menu) {
				// TODO Auto-generated method stub
				return false;
			}

			@Override
			public boolean onPrepareActionMode(ActionMode mode, Menu menu) {
				// TODO Auto-generated method stub
				return false;
			}

			@Override
			public boolean onActionItemClicked(ActionMode mode, MenuItem item) {
				// TODO Auto-generated method stub
				return false;
			}

			@Override
			public void onDestroyActionMode(ActionMode mode) {
				// TODO Auto-generated method stub

			}

			@Override
			public void onItemCheckedStateChanged(ActionMode mode,
					int position, long id, boolean checked) {
				// TODO Auto-generated method stub

			}

		});

就5个方法,看名字也很好理解。

在onCreateActionMode()中,一般实现ActionMode下右侧的MenuItem配置,和标题设置,比如像下面这样

@Override
			public boolean onCreateActionMode(ActionMode mode, Menu menu) {
				// 在进入ActionMode的时候调用
				MenuInflater inflater = mode.getMenuInflater();
				inflater.inflate(R.menu.menu_delete, menu);
				mode.setTitle("Delete");
				isInActionMode = true;
				isInDeleteMode = false;

				return true;
			}

onActionItemClicked则是在我们设置的MenuItem点击之后调用,和ActionBar里面的MenuItem一样,所以我们可以像下面这样

@Override
			public boolean onActionItemClicked(ActionMode mode, MenuItem item) {

				// 当listview中的item被点击的时候调用
				if (item.getItemId() == R.id.action_delete) {
					mAnimateDismissAdapter.animateDismiss(mCheckedPositions);
					isInDeleteMode = true;
					mode.finish();
					return true;
				}

				return false;
			}

onItemCheckedStateChanged则是我们的listview的item点击的时候调用,我们可以根据position和checked进行逻辑操作。

基本这几个方法就基本满足我们的功能了,下面是完整的示例代码

package com.imooc.multychoice;

import java.util.ArrayList;
import java.util.Iterator;

import android.app.Activity;
import android.os.Bundle;
import android.view.ActionMode;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup;
import android.widget.AbsListView;
import android.widget.AbsListView.MultiChoiceModeListener;
import android.widget.BaseAdapter;
import android.widget.CheckBox;
import android.widget.ListView;
import android.widget.TextView;

import com.haarman.listviewanimations.itemmanipulation.AnimateDismissAdapter;
import com.haarman.listviewanimations.itemmanipulation.OnDismissCallback;
import com.imooc.multychoice.R;

public class MainActivity extends Activity {

	protected static final String TAG = "TAG";
	private ListView mListView;
	private MultyAdapter mAdapter;
	// 是否处于ActionMode模式
	private boolean isInActionMode;
	private boolean isInDeleteMode = false;
	private AnimateDismissAdapter<Model> mAnimateDismissAdapter;
	private ArrayList<Integer> mCheckedPositions;

	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_main);

		mListView = (ListView) findViewById(R.id.lv);
		mAdapter = new MultyAdapter();
		mCheckedPositions = new ArrayList<Integer>();

		mAnimateDismissAdapter = new AnimateDismissAdapter<MainActivity.Model>(
				mAdapter, new MyDismissCallBack());
		mAnimateDismissAdapter.setAbsListView(mListView);
		mListView.setAdapter(mAnimateDismissAdapter);

		mListView.setChoiceMode(ListView.CHOICE_MODE_MULTIPLE_MODAL);

		mListView.setMultiChoiceModeListener(new MultiChoiceModeListener() {

			@Override
			public boolean onPrepareActionMode(ActionMode mode, Menu menu) {
				return false;
			}

			@Override
			public void onDestroyActionMode(ActionMode mode) {

				// 在退出ActionMode的时候调用,如果处于删除状态,就删除选中的数据,
				// 否则,重置所有选中的状态
				if (!isInDeleteMode) {
					for (Model model : mAdapter.models) {
						model.setChecked(false);
					}
					mCheckedPositions.clear();
				}

				isInActionMode = false;

			}

			@Override
			public boolean onCreateActionMode(ActionMode mode, Menu menu) {
				// 在进入ActionMode的时候调用
				MenuInflater inflater = mode.getMenuInflater();
				inflater.inflate(R.menu.menu_delete, menu);
				mode.setTitle("Delete");
				isInActionMode = true;
				isInDeleteMode = false;

				return true;
			}

			@Override
			public boolean onActionItemClicked(ActionMode mode, MenuItem item) {

				// 当listview中的item被点击的时候调用
				if (item.getItemId() == R.id.action_delete) {
					mAnimateDismissAdapter.animateDismiss(mCheckedPositions);
					isInDeleteMode = true;
					mode.finish();
					return true;
				}

				return false;
			}

			@Override
			public void onItemCheckedStateChanged(ActionMode mode,
					int position, long id, boolean checked) {

				// 当item的选中状态被选中的时候调用
				mAdapter.models.get(position).setChecked(checked);
				mAdapter.notifyDataSetChanged();
				mode.setSubtitle(mListView.getCheckedItemCount()
						+ " item selected");

				if (mCheckedPositions.contains(position) && !checked) {
					mCheckedPositions.remove(Integer.valueOf(position));
				} else {
					mCheckedPositions.add(position);
				}

			}
		});

	}

	private class MultyAdapter extends BaseAdapter {

		private ArrayList<Model> models;

		public MultyAdapter() {

			models = new ArrayList<Model>();
			for (int i = 0; i < 20; i++) {
				models.add(new Model("I‘m " + i));
			}

		}

		@Override
		public int getCount() {
			return models.size();
		}

		@Override
		public Model getItem(int position) {
			return models.get(position);
		}

		@Override
		public long getItemId(int position) {
			return 0;
		}

		@Override
		public View getView(int position, View convertView, ViewGroup parent) {

			ViewHolder viewHolder;

			Model model = mAdapter.models.get(position);

			if (convertView == null) {

				convertView = getLayoutInflater().inflate(
						R.layout.item_multy_choice, parent, false);

				viewHolder = new ViewHolder();

				viewHolder.tv = (TextView) convertView.findViewById(R.id.tv);
				viewHolder.chb = (CheckBox) convertView.findViewById(R.id.chb);
				convertView.setTag(viewHolder);
			} else {
				viewHolder = (ViewHolder) convertView.getTag();
			}

			viewHolder.tv.setText(model.getTitle());
			viewHolder.chb.setChecked(model.isChecked());
			viewHolder.chb.setVisibility(isInActionMode ? View.VISIBLE
					: View.GONE);

			return convertView;
		}
	}

	private static class ViewHolder {
		TextView tv;
		CheckBox chb;
	}

	/**
	 * 测试Model
	 *
	 * @author zhaokaiqiang
	 *
	 */
	private class Model {

		private String title;

		private boolean isChecked;

		public Model(String title) {
			this.title = title;
			isChecked = false;
		}

		public String getTitle() {
			return title;
		}

		public boolean isChecked() {
			return isChecked;
		}

		public void setChecked(boolean isChecked) {
			this.isChecked = isChecked;
		}

	}

	private class MyDismissCallBack implements OnDismissCallback {

		@Override
		public void onDismiss(AbsListView arg0, int[] arg1) {

			mCheckedPositions.clear();

			Iterator<Model> iterator = mAdapter.models.iterator();
			while (iterator.hasNext()) {
				if (iterator.next().isChecked()) {
					// 删除选中的元素
					iterator.remove();
				}
			}
			mAdapter.notifyDataSetChanged();
		}
	}

}

在上面的代码中,为了实现动画效果,我使用了开源项目ListViewAnimation中的AnimationDismissAdapter,具体用法很简单,直接看代码就可以啦~

下载地址:https://github.com/ZhaoKaiQiang/MultyChoiceDemo

时间: 2024-10-15 11:04:26

【凯子哥带你夯实应用层】使用ActionMode实现有删除动画的多选删除功能的相关文章

【凯子哥带你夯实应用层】滚来滚去,滚来滚去...Scroller相关类使用大揭秘!!!

转载请注明出处:http://blog.csdn.net/zhaokaiqiang1992 话接上文,在前一篇文章里面,咱们一起分析了"知乎"的回答详情页的需求,然后顺便用代码实现了下,忘了的可以再去看看[凯子哥带你夯实应用层]都说"知乎"逼格高,我们来实现"知乎"回答详情页动画效果 .其实在很多的界面效果中,这种"滚动"的效果能带来很多的惊喜,各种效果也很有搞头,说不定什么时候,Boss看着哪个界面好看,就让你去仿个过来,你

【凯子哥带你夯实应用层】都说“知乎”逼格高,我们来实现“知乎”回答详情页动画效果

转载请注明出处:http://blog.csdn.net/zhaokaiqiang1992 2014已经远去,2015年的目标很简单,就是继续熟悉Android的上层API,虽然偶尔会为了某个问题去研究下FrameWork的代码,但是对于我们这种新手来说,只有对上层的API用的熟练了,才能更好的往下研究原理.所以,今年的任务就是继续学习和研究Android的上层API的使用,顺便写一篇毕业论文,然后毕个业. OK,从这篇开始,咱们就开始[凯子哥带你夯实应用层]系列,如果你有想要实现的界面效果,或

【凯子哥带你夯实应用层】还在用XListView?试试更漂亮的AutoLoadListView吧!

转载请注明出处:http://blog.csdn.net/zhaokaiqiang1992 关于上拉刷新和下拉加载,已经有不少的解决方案了,XListView和PullToRefresh应该是被广为熟知的开源项目,项目很棒,可以解决我们的需求.但是,今天咱们用一种更简单的方式,来实现上拉刷新和下拉加载功能,我叫它AutoLoadListView~ 先来一张效果图. 刷新效果使用19版本之后的v4兼容包的SwipeRefreshLayout实现,效果很漂亮,而自动加载下一页的跳动效果,则是使用了另

【凯子哥带你夯实应用层】使用ActionProvider实现子菜单时遇到的一个坑

转载请注明出处:http://blog.csdn.net/zhaokaiqiang1992 最近在重温Android基础,在看到ActionProvider的时候遇到一个坑,分享到大家,避免入坑. 首先简单介绍下ActionProvider. ShareActionProvider你应该用过吧?就是使用系统自带的分享功能,其实ShareActionProvider就是ActionProvider的一个子类,可以在ActionBar上面显示为一个MenuItem,但是我们可以自定义事件行为,所以我

【凯子哥带你夯实应用层】Android的Google官方设计指南(上)

Android 设计规范 时间 2015.3.2 版本 V1.0 翻译 杨鹏 整理 赵凯强 本文章是我公司一个大牛之前的公司同事翻译的Android的Google官方设计指导,经过我整理而成,分享给大家,欢迎转载,但是请保留出处和翻译作者.本指导内容详实.规范,无论是初级开发者还是高级开发者,甚至是公司产品设计和美工,都应该研读学习,特此推荐!由于文章内容较颇多,所以我分为几篇发布,方便大家阅读学习.如果对你有帮助,请评论或者顶一下代表支持,谢谢! 还是人多力量大啊,有同学告诉我已经有这样的资料

【凯子哥带你夯实应用层】新手必备的常用代码片段整理(一)

转载请注明出处:http://blog.csdn.net/zhaokaiqiang1992 以下内容来自多个开源项目的整理和自己的项目积累 拨打电话 跳转至拨号界面 发送短信 唤醒屏幕并解锁 判断当前App处于前台还是后台状态 判断当前手机是否处于锁屏睡眠状态 判断当前是否有网络连接 判断当前是否是WIFI连接状态 安装APK 判断当前设备是否为手机 获取当前设备宽高单位px 获取当前设备的IMEI需要与上面的isPhone一起使用 获取当前设备的MAC地址 获取当前程序的版本号 拨打电话 pu

【凯子哥带你夯实应用层】读 Develop API Guides 有感(一)

转载请注明出处:http://blog.csdn.net/zhaokaiqiang1992 动态检测设备属性 关于targetSdkVersion的含义 关于onSaveInstanceState的高级知识 关于startActivity和Intent 动态检测设备属性 我们可以使用下面的代码动态检测当前设备是否具备某一个特性,如是否有方向传感器 PackageManager pm = getPackageManager(); if(!pm.hasSystemFeature(PackageMan

【凯子哥带你学Android】Andriod性能优化之列表卡顿——以“简书”APP为例

这几天闲得无聊,就打开手机上的开发者模式里面的"GPU过度绘制"功能,看看别家的App做的咋样,然后很偶然的打开了"简书",然后就被它的过度绘制惊呆了,于是写了这篇性能分析的文章,从一个只有APK文件的角度,说下如何寻找布局中可能存在的性能问题,以及解决方案.本文章以简书Android最新版本1.9.1进行分析. GPU过度绘制 Hierarchy View SysTrace TraceView 总结 分析资源下载 GPU过度绘制 首先打开下面两个功能开关 开发者模

【转载】【凯子哥带你学Framework】Activity启动过程全解析

It's right time to learn Android's Framework ! 前言 一个App是怎么启动起来的? App的程序入口到底是哪里? Launcher到底是什么神奇的东西? 听说还有个AMS的东西,它是做什么的? Binder是什么?他是如何进行IPC通信的? Activity生命周期到底是什么时候调用的?被谁调用的? 等等... 你是不是还有很多类似的疑问一直没有解决?没关系,这篇文章将结合源码以及大量的优秀文章,站在巨人的肩膀上,更加通俗的来试着解释一些问题.但是毕