本文介绍了我们将如何取得具体ListView多选择操作。本文将正确使用ListViewCHOICE_MODE_MULTIPLE要么CHOICE_MODE_MULTIPLE_MODAL时间easy误区。以及

CHOICE_MODE_MULTIPLE与CHOICE_MODE_MULTIPLE_MODAL的差别。

最后我们将给出一个demo来演示两种多选操作的实现。

一、在不使用ListView多选模式的情况下

注:我觉得这一节能够不看,由于我觉得不使用ListView的多选模式有点愚蠢。

假设我们不知道ListView自带多选模式,那么我们通常是通过维护一个保存被选择position集合来实现多选的。通常情况下这个集合类型我们选择HashSet。

实现的大致框架例如以下:

Adapter中:

保存被选择的position

public HashSet<Long> selectedItems = new HashSet<Long>();

getView中推断当前Position是否在集合中。从而显示不同的外观

    public View getView(int position, View convertView, ViewGroup par) {
......if(selectedItems.contains((long)position)){holder.cBox.setChecked(true);}else{holder.cBox.setChecked(false);}if(selectedMode==AppContext.MULTI_SELECTED){holder.cBox.setVisibility(View.VISIBLE);holder.check_box_wraper.setVisibility(View.VISIBLE);}else{holder.cBox.setVisibility(View.GONE);holder.check_box_wraper.setVisibility(View.GONE);}
.....
}

Activity中:

主要是处理onItemClick事件,在不同模式下。做不同的处理。

@Override
public void onItemClick(AdapterView<?

> a, View v, int position, long id) { //普通模式 :直接打开一个activity if(itemClickActionMode==AppContext.VIEW_NOTE){ Long mId=Long.parseLong(idText.getText().toString()); Uri uri = ContentUris.withAppendedId(getIntent().getData(), mId); startActivity(new Intent(Intent.ACTION_VIEW, uri)); } //多选模式:更新adapter中selectedItems 集合的值,同一时候 让adapter在getView中改变item的外观。 else{ ViewHolder vHollder = (ViewHolder) v.getTag(); if(mAdapter.selectedItems.contains((long)position)){ mAdapter.selectedItems.remove((long)position); }else{ mAdapter.selectedItems.add((long)position); } mAdapter.notifyDataSetChanged(); onItemSelected(getSelectedCount()); } }

上面的做法其有用的非常普遍。可是我们不提倡。

二、使用ListViiew的CHOICE_MODE_MULTIPLE模式

ListView有四种模式:

/*** Normal list that does not indicate choices*/
public static final int CHOICE_MODE_NONE = 0;
/*** The list allows up to one choice*/
public static final int CHOICE_MODE_SINGLE = 1;
/*** The list allows multiple choices*/
public static final int CHOICE_MODE_MULTIPLE = 2;
/*** The list allows multiple choices in a modal selection mode*/
public static final int CHOICE_MODE_MULTIPLE_MODAL = 3;

当中CHOICE_MODE_NONE是普通模式,CHOICE_MODE_SINGLE是单选模式,不经常使用,CHOICE_MODE_MULTIPLECHOICE_MODE_MULTIPLE_MODAL都是多选模式,他们的差别稍后我们会讲到。

所以ListView在设计的时候事实上是考虑了多选操作的。我们没有必要自己再像第一节描写叙述的那样专门维护一个HashSet来保存被选择的position。

实现ListView的多选操作的代码在ListView直接父类AbsListView中,AbsListView已经有一个mCheckStates变量来做了保存被选择的position这个事情。

mCheckStates的定义例如以下:

1
SparseBooleanArray mCheckStates;

AbsListView还定义了例如以下公共方法:

//推断一个item是否被选中

1
public boolean isItemChecked(int position);

//获得被选中item的总数

1
public int getCheckedItemCount();

//选中一个item

1
public void setItemChecked(int position, boolean value);

//清除选中的item

1
public void clearChoices();

当点击一个item的时候absListView中会调用performItemClick,假设是CHOICE_MODE_MULTIPLE。则该item点击一次。mCheckStates中对应位置的状态变更一次。然后我们就能够通过listView的getCheckedItemCount()方法获取选择了多少个;isItemChecked(int position)方法推断一个item是不是被选中。

有了这些原生sdk的支持,难道还有什么多选操作是不能实现的吗?所以是不是应该考虑放弃第一节中描写叙述的那种方法了呢?遗憾的是非常多android开发人员即使是用了CHOICE_MODE_MULTIPLE,仍然没有去利用这些ListView自带的功能。预计是根本不知道该CHOICE_MODE_MULTIPLE的 特性吧,这事实上也是android程序猿与ios程序猿真正存在差距的地方。

CHOICE_MODE_MULTIPLE实战


先看看效果图

package com.example.listmultichoise;
import android.os.Bundle;
import android.app.ActionBar;
import android.app.Activity;
import android.util.Log;
import android.view.ActionMode;
import android.view.LayoutInflater;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup;
import android.view.Window;
import android.widget.AdapterView;
import android.widget.AdapterView.OnItemClickListener;
import android.widget.ListView;
import android.widget.TextView;
import android.widget.Toast;
public class ChoiceModeMultipleActivity extends Activity {ListView mListView = null;MyListAdapter mAdapter;private View mMultiSelectActionBarView;private TextView mSelectedCount;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);getWindow().requestFeature(Window.FEATURE_ACTION_BAR);setContentView(R.layout.activity_list);mListView = (ListView)findViewById(R.id.list);mAdapter = new MyListAdapter(this,mListView);mListView.setAdapter(mAdapter);mListView.setChoiceMode(ListView.CHOICE_MODE_MULTIPLE);mListView.setOnItemClickListener(new OnItemClickListener() {public void onItemClick(AdapterView<?> parent, View view, int position,long id) {mAdapter.notifyDataSetChanged();updateSeletedCount();}});if (mMultiSelectActionBarView == null) {mMultiSelectActionBarView = LayoutInflater.from(ChoiceModeMultipleActivity.this).inflate(R.layout.list_multi_select_actionbar, null);mSelectedCount =(TextView)mMultiSelectActionBarView.findViewById(R.id.selected_conv_count);}getActionBar().setDisplayOptions(ActionBar.DISPLAY_SHOW_CUSTOM,ActionBar.DISPLAY_SHOW_CUSTOM | ActionBar.DISPLAY_SHOW_HOME |ActionBar.DISPLAY_SHOW_TITLE);getActionBar().setCustomView(mMultiSelectActionBarView);((TextView)mMultiSelectActionBarView.findViewById(R.id.title)).setText(R.string.select_item);}@Overridepublic boolean onCreateOptionsMenu(Menu menu) {getMenuInflater().inflate(R.menu.multi_select_menu, menu);return true;}@Overridepublic boolean onPrepareOptionsMenu(Menu menu) {MenuItem mItem = menu.findItem(R.id.action_slelect);if(mListView.getCheckedItemCount() == mAdapter.getCount()){mItem.setTitle(R.string.action_deselect_all);}else{mItem.setTitle(R.string.action_select_all);} return super.onPrepareOptionsMenu(menu);}@Overridepublic boolean onOptionsItemSelected(MenuItem item) {switch (item.getItemId()) {case R.id.action_slelect:if(mListView.getCheckedItemCount() == mAdapter.getCount()){unSelectedAll();}else{selectedAll();}mAdapter.notifyDataSetChanged();break;default:break;}return super.onOptionsItemSelected(item);}public void selectedAll(){for(int i= 0; i< mAdapter.getCount(); i++){mListView.setItemChecked(i, true);}updateSeletedCount();}public void unSelectedAll(){mListView.clearChoices();updateSeletedCount();}public void updateSeletedCount(){mSelectedCount.setText(Integer.toString(mListView.getCheckedItemCount()));}
}

代码解释:


首先设置ListView模式:

mListView.setChoiceMode(ListView.CHOICE_MODE_MULTIPLE);

定义一个adapter,当ListView的某个item被选中之后,将该Item的背景设置为蓝色,以标记为选中。不然尽管ListView知道该item被选中,可是界面上没表现出来。

......public View getView(int position, View convertView, ViewGroup parent) {TextView tv;if (convertView == null) {tv = (TextView) LayoutInflater.from(mContext).inflate(android.R.layout.simple_expandable_list_item_1, parent,false);} else {tv = (TextView) convertView;}tv.setText(mStrings[position]);updateBackground(position , tv);return tv;}@SuppressLint("NewApi")public void updateBackground(int position, View view) {int backgroundId;if (mListView.isItemChecked(position)) {backgroundId = R.drawable.list_selected_holo_light;} else {backgroundId = R.drawable.conversation_item_background_read;}Drawable background = mContext.getResources().getDrawable(backgroundId);view.setBackground(background);}
......

在item每被点击一次中通知adapter,这样做的目的是为了让更新Ui以显示最新的选中状态。

mListView.setOnItemClickListener(new OnItemClickListener() {public void onItemClick(AdapterView<?

> parent, View view, int position, long id) { mAdapter.notifyDataSetChanged(); updateSeletedCount(); } });

当中mSelectedCount()作用是在actionbar中更新选中的数目。

public void updateSeletedCount(){mSelectedCount.setText(Integer.toString(mListView.getCheckedItemCount()));}

上面的代码实现了多选操作,可是在我选中一个item的时候,listView的onItemClick也同一时候触发。而一个ListView点击item的兴许操作通常是切换到另外一个界面,所以实际应用中,我们还须要设置一个标志位,用来差别当前是多选状态还是普通状态 。假设是多选状态,调用ListView.setChoiceMode(ListView.CHOICE_MODE_MULTIPLE);  假设是普通状态调用mListView.setChoiceMode(ListView.CHOICE_MODE_NONE);CHOICE_MODE_MULTIPLE模式的特点在于他本身没有排斥性,在能选择item的情况下,也能够响应普通点击事件。为了解决问题 ,在android3.0之后添加了CHOICE_MODE_MULTIPLE_MODAL模式。

二、使用ListViiew的CHOICE_MODE_MULTIPLE模式

CHOICE_MODE_MULTIPLE_MODAL和CHOICE_MODE_MULTIPLE恰恰相反。他是对普通点击操作和多选操作是排斥的,一旦有一个item被选中。即进入到多选状态,item的onclick事件被屏蔽。

这样的排斥性也是他比CHOICE_MODE_MULTIPLE多了个MODAL的原因。此外CHOICE_MODE_MULTIPLE_MODAL还结合了android3.0的actionmode,当进入多选状态,actionbar的位置会显示新的菜单。

我们来看看CHOICE_MODE_MULTIPLE_MODAL模式的实现原理:

怎样实现两种状态的相互排斥:当点击一个item的时候absListView中会调用performItemClick,假设是CHOICE_MODE_MULTIPLE。则该item点击一次,mCheckStates中对应位置的状态变更一次。可是CHOICE_MODE_MULTIPLE_MODAL模式不同,必需要mChoiceActionMode!= null

的情况下,才会去变更mCheckStates中对应位置的状态。不光如此。假设mChoiceActionMode!= null

。他还会阻挡ItemClick事件的继续传播,从而屏蔽了ListView OnItemClickListener的onItemClick方法。

怎样启用actionmode:一般我们使用actionmode都是在activity中调用startActionMode,可是假设你要使用ListView的CHOICE_MODE_MULTIPLE_MODAL,请不要这么做。 在absListView中有一个变量mChoiceActionMode。定义例如以下:

ActionMode mChoiceActionMode;

当长按item 或者是调用主动调用setItemChecked方法mChoiceActionMode将被实例化,而假设你是在activity中调用startActionMode,那么尽管actionbar上的菜单变化了,ListView 中的mChoiceActionMode却没有实例化。刚刚我们谈到mChoiceActionMode==null 表示未进入到多选状态,所以这时你点击一个item事实上还是普通的点击行为。

因此在CHOICE_MODE_MULTIPLE_MODAL模式下要启用多选操作。仅仅有两种办法:

(1)长按当长按item 。

(2)主动调用ListView的setItemChecked(int position, boolean value)方法选中一个item。

可是这两种进入多选状态的方法都有一个弊端,那就是进入多选状态之后,总是有一个item是被选中的, 方法(1)中长按item。被按的item被选中,这样的结果是合理的能够接受的,可是假设你想主动进入多选状态(比方我在点击actionbar的某个菜单的时候想进入多选状态),就必须採用方法(2):调用setItemChecked,这就出现个问题。你该让哪个item被选中呢?貌似最合理的该是一个都不选中吧,我仅仅是进入到这个状态,还没有開始选呢。幸运的是,我们能够使用一些技巧,实现能主动进入多选状态。且没有一个item被选中。

思路是我们先让第一个item被选中。这样Listview就进入多选状态。然后我们再清除被选中item的状态,代码例如以下:

if(item.getItemId() == R.id.action_choice){mListView.setItemChecked(0,true);mListView.clearChoices();
}

有些人可能会问。依照上面的思路。为什么不这样实现呢:

if(item.getItemId() == R.id.action_choice){mListView.setItemChecked(0,true);mListView.setItemChecked(0,false);
}

嘿嘿,刚刚我们提到ListView CHOICE_MODE_MULTIPLE_MODAL模式中,一旦有一个item被选中,即进入到多选状态,而他还有个相反的特性,一旦全部的Item被主动的设置为未选中,则退出多选状态,mChoiceActionMode会调用自己的finish()方法。为什么呢?在MultiChoiceModeWrapper类中:

@Override
public void onItemCheckedStateChanged(ActionMode mode,int position, long id, boolean checked) {mWrapped.onItemCheckedStateChanged(mode, position, id, checked);// If there are no items selected we no longer need the selection mode.if (getCheckedItemCount() == 0) {mode.finish();}
}

好了我们来实现一个CHOICE_MODE_MULTIPLE_MODAL模式下的多选操作:

代码:

package com.example.listmultichoise;
import android.os.Bundle;
import android.app.Activity;
import android.util.Log;
import android.view.ActionMode;
import android.view.LayoutInflater;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup;
import android.widget.AdapterView;
import android.widget.AdapterView.OnItemClickListener;
import android.widget.ListView;
import android.widget.TextView;
import android.widget.Toast;
public class ChoiceModeMultipleModalActivity extends Activity {ListView mListView = null;MyListAdapter mAdapter;ModeCallback mCallback;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_list);mListView = (ListView)findViewById(R.id.list);mAdapter = new MyListAdapter(this,mListView);mListView.setAdapter(mAdapter);mCallback = new ModeCallback();mListView.setChoiceMode(ListView.CHOICE_MODE_MULTIPLE_MODAL); mListView.setMultiChoiceModeListener(mCallback);mListView.setOnItemClickListener(new OnItemClickListener() {public void onItemClick(AdapterView<?> parent, View view, int position,long id) {Toast.makeText(ChoiceModeMultipleModalActivity.this, "选择了一个item", 300).show();}});}@Overridepublic boolean onCreateOptionsMenu(Menu menu) {// Inflate the menu; this adds items to the action bar if it is present.getMenuInflater().inflate(R.menu.main, menu);return true;}@Overridepublic boolean onOptionsItemSelected(MenuItem item) {if(item.getItemId() == R.id.action_choice){//这里使用了一点技巧来实现处于选中状态 可是0个item 被选择mListView.setItemChecked(0,true);mListView.clearChoices();mCallback.updateSeletedCount();}return super.onOptionsItemSelected(item);}private class ModeCallback implements ListView.MultiChoiceModeListener {private View mMultiSelectActionBarView;private TextView mSelectedCount;@Overridepublic boolean onCreateActionMode(ActionMode mode, Menu menu) {// actionmode的菜单处理MenuInflater inflater = getMenuInflater();inflater.inflate(R.menu.multi_select_menu, menu);if (mMultiSelectActionBarView == null) {mMultiSelectActionBarView = LayoutInflater.from(ChoiceModeMultipleModalActivity.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) {if (mMultiSelectActionBarView == null) {ViewGroup v = (ViewGroup)LayoutInflater.from(ChoiceModeMultipleModalActivity.this).inflate(R.layout.list_multi_select_actionbar, null);mode.setCustomView(v);mSelectedCount = (TextView)v.findViewById(R.id.selected_conv_count);}          //更新菜单的状态MenuItem mItem = menu.findItem(R.id.action_slelect);if(mListView.getCheckedItemCount() == mAdapter.getCount()){mItem.setTitle(R.string.action_deselect_all);}else{mItem.setTitle(R.string.action_select_all);}return true;}@Overridepublic boolean onActionItemClicked(ActionMode mode, MenuItem item) {switch (item.getItemId()) {case R.id.action_slelect:if(mListView.getCheckedItemCount() == mAdapter.getCount()){unSelectedAll();}else{selectedAll();}mAdapter.notifyDataSetChanged();break;default:break;}return true;}@Overridepublic void onDestroyActionMode(ActionMode mode) {mListView.clearChoices();}@Overridepublic void onItemCheckedStateChanged(ActionMode mode,int position, long id, boolean checked) {updateSeletedCount();mode.invalidate();mAdapter.notifyDataSetChanged();}public void updateSeletedCount(){mSelectedCount.setText(Integer.toString(mListView.getCheckedItemCount()));}}public void selectedAll(){for(int i= 0; i< mAdapter.getCount(); i++){mListView.setItemChecked(i, true);}mCallback.updateSeletedCount();}public void unSelectedAll(){mListView.clearChoices();mListView.setItemChecked(0,false);mCallback.updateSeletedCount();}
}

这里须要提醒的是尽管ListView的mActionMode我们不能直接操作,可是actionmode的回调方法是能够在activity中设置的:

mListView.setMultiChoiceModeListener(mCallback);

并且这个回调方法比一般的actionmode回调方法多了个onItemCheckedStateChanged

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

demo我已经上传到了csdn:http://download.csdn.net/detail/jianghejie123/8126071

版权声明:本文博客原创文章。博客,未经同意,不得转载。

本文转自mfrbuaa博客园博客,原文链接:http://www.cnblogs.com/mfrbuaa/p/4747628.html,如需转载请自行联系原作者

ListView的操作模式的选择的更详细的解释CHOICE_MODE_MULTIPLE与CHOICE_MODE_MULTIPLE_MODAL...相关推荐

  1. android 能自动选择的listview,Android ListView多选模式

    ListView使用多选模式好处 交互与数据分离,在多选状态下不需要修改数据源,在最后确定的时候获取选择索引来确定选择的数据. ListView模式 CHOICE_MODE_NONE:普通模式: CH ...

  2. ListView多选操作模式详解

    原文链接:点击打开链接 这篇文章我们将详细的介绍如何实现ListView的多选操作,文中将会纠正在使用ListViewCHOICE_MODE_MULTIPLE或者CHOICE_MODE_MULTIPL ...

  3. 内核:多内核操作模式

    多内核操作模式: 1.  <<QNX-–-微内核结构的实时操作系统.pdf>> 2.  对称多处理"(Symmetrical Multi-Processing) SM ...

  4. 大型数据中心维保外包模式的选择

    数据中心经过了快速发展的十年,笔者有幸见证了这十年的发展,也参与到数据中心的运维工作当中.本文通过总结这十年的经验提出一两点个人见解.跟大家探讨一下数据中心维保外包模式的选择,为各广大数据中心业主选择 ...

  5. 《缠中说禅108课》49:利润率最大的操作模式

    本周就不解<论语>了,并不是本 ID 不想写,而是 51 长假,对那些希望多学点本 ID 理论的人,是一个好的机会,本 ID 也就多写点这方面的,给有需要的多准备点,毕竟,这对于大多数人来 ...

  6. 暗渡陈仓:用低消耗设备进行破解和渗透测试1.2.3 操作模式

    1.2.3 操作模式 Deck的强项之一就是它既能作为传统的图形用户界面的桌面系统使用,又能用于渗透行动的投置机,而且还能作为破解攻击机的系统.在这几种应用模式之间切换完全无需任何软件改动.这个特性极 ...

  7. win11的文件属性默认显示全部,Windows11右键菜单修改为Win10模式的方法(手把手详细操作)

    win11的文件属性默认显示全部,Windows11右键菜单修改为Win10模式的方法(手把手详细操作) 文章目录 win11的文件属性默认显示全部,Windows11右键菜单修改为Win10模式的方 ...

  8. 英特尔Optane DC Persistent Memory操作模式说明

    前面介绍了Optane DC Persistent Memory有两种模式: Memory Mode App Direct Mode 服务器将使用DRAM和英特尔Optan DC Persistent ...

  9. eMMC的五种操作模式

    eMMC的五种操作模式:开机模式.ID辨识模式.中断模式.数据传输模式.无效模式. 开机模式 Boot mode Power ON后,卡若收到CMD0(GO_Idle_State)并带argument ...

最新文章

  1. 25个python相关的基础概念总结
  2. Linux打开txt文件乱码的解决方法
  3. hdu 6194 后缀数组
  4. Java经典算法50道题
  5. 1个已知CVE,7步,找到一个高质量RCE并获奖金
  6. 3810.最长连续休息时间-AcWing题库
  7. 一个js内存泄露的好例子
  8. chrome浏览器Flash版本过低解决方法
  9. mysql 自动生成时间戳
  10. Map中的keySet方法
  11. 云扩科技与百胜数睿签署战略合作协议,加速超自动化平台落地零售行业
  12. 网络电话服务器安全认证管理系统,CA 数字证书认证系统建设解决方案
  13. 第五讲 中断、异常和信号
  14. 数据结构学习笔记之快速排序(非递归)
  15. 利用计算机控制,计算机控制系统在机器人技术中的应用
  16. 数据挖掘项目_挖掘社区项目
  17. linux-2.6.32在mini2440开发板上移植 ---W35型LCD驱动移植
  18. Cocos Creator 初探:修改Engine来调整FPS信息显示
  19. 【AI人工智能】从技术角度看,我们离超级人工智能还有多远?
  20. 30人15个教徒跳海

热门文章

  1. ubuntu 安装php-redis
  2. Ioc 控制反转 实例
  3. Silverlight中多个Xaml之间的切换/调用/弹出/传参数(转)
  4. 十分钟轻松让你认识Entity Framework 7
  5. Java并发编程开发笔记——2线程安全性
  6. UIProgressView(进度条控件)
  7. 从零到有的突破:BCH爱好者聚集地BCH.Club公测上线
  8. 对冲基金BKCM LLC创始人看涨BCH
  9. Java服务端人脸识别实战开发优化
  10. Centos7上安装 elasticsearch-6.2.2及相关插件