开源项目MultiChoiceAdapter详解(五)——可扩展的MultiChoiceBaseAdapter
上次写到了开源项目MultiChoiceAdapter详解(四)——MultiChoiceBaseAdapter的使用,其实我们仍旧可以不使用ActionMode的,所以这里就写一个自己扩展的方法。
一、布局文件
listview_normal_layout.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/normal_listView" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_weight="1" > </ListView> <LinearLayout android:id="@+id/setting_linearLayout" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_gravity="bottom"> <Button android:id="@+id/selectAll_button" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="全选" android:layout_weight="1" android:onClick="buttonListener"/> <Button android:id="@+id/cancle_button" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="取消" android:layout_weight="1" android:onClick="buttonListener"/> <Button android:id="@+id/delete_button" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_weight="1" android:text="删除" android:onClick="buttonListener"/> <Button android:id="@+id/share_button" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="分享" android:layout_weight="1" android:onClick="buttonListener"/> </LinearLayout> </LinearLayout>
item.xml
<?xml version="1.0" encoding="utf-8"?> <com.manuelpeinado.multichoiceadapter.view.CheckableLinearLayout 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:background="@drawable/custom_list_item_background" android:orientation="horizontal"> <!-- 上面必须要用自定义的layout,否则不会有选中的效果!!! --> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" android:padding="16dp" android:orientation="horizontal" > <TextView android:id="@+id/item_textView" android:layout_width="200dp" android:layout_height="wrap_content" android:layout_marginLeft="30dp" android:layout_gravity="center_vertical" android:textColor="#000000" android:layout_weight="1" android:textAppearance="?android:attr/textAppearanceLarge" /> <!-- CheckBox中一定要写上focusable="false"否则无法相应点击事件 @android:id/checkbox这个也一定要写,如果不写的话点击checkbox就不会触发多选状态 如果你不想要选中checkbox就触发多选状态的话,这里可以用自己定义的id就行 --> <CheckBox android:id="@android:id/checkbox" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="center_vertical|right" android:layout_weight="1" android:layout_marginLeft="40dp" android:textColor="#000000" android:focusable="false" android:visibility="gone" android:text="" /> </LinearLayout> </com.manuelpeinado.multichoiceadapter.view.CheckableLinearLayout>
view_header.xml
这个是用于给listview添加一个头部视图的,顺带学习下listview添加顶部视图的方法呗~
<?xml version="1.0" encoding="utf-8"?> <TextView xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="wrap_content" android:paddingBottom="16dp" android:paddingTop="16dp" android:text="这是给listview添加的顶部视图" android:gravity="center_horizontal" android:textStyle="bold" />
二、继承类然后实现
可以看见这里关于ActionMode有关的回调方法我都是空实现
private class MultiBaseAdapter extends MultiChoiceBaseAdapter{ private String[] mData; /** * 构造函数 * @param savedInstanceState */ public MultiBaseAdapter(Bundle savedInstanceState,String[] data) { super(savedInstanceState); // TODO 自动生成的构造函数存根 mData = data; } @Override public boolean onCreateActionMode(ActionMode mode, Menu menu) { return true; } @Override public boolean onActionItemClicked(ActionMode mode, MenuItem item) { return false; } @Override public boolean onPrepareActionMode(ActionMode arg0, Menu arg1) { // TODO 自动生成的方法存根 return false; } /** * 看适配器中有多少元素需要加载 */ @Override public int getCount() { // TODO 自动生成的方法存根 return mData.length; } /** * 通过position来得到相应的item,这里返回object对象 */ @Override public Object getItem(int position) { // TODO 自动生成的方法存根 return mData[position]; } /** * 通过position得到id */ @Override public long getItemId(int position) { // TODO 自动生成的方法存根 return position; } /** * 返回item的view对象 */ @Override protected View getViewImpl(int position, View convertView, ViewGroup parent) { if (convertView == null) { int layout = R.layout.item; LayoutInflater inflater = LayoutInflater.from(getContext()); convertView = inflater.inflate(layout, parent, false); } ViewGroup group = (ViewGroup)convertView; ((TextView)group.findViewById(R.id.item_textView)).setText(mData[position]); ((CheckBox)group.findViewById(android.R.id.checkbox)).setVisibility(View.VISIBLE); return group; } }
三、配置适配器和相应的监听器
listView.addHeaderView(createHeaderView(), null, false);是给listview添加头视图的方法,传入false表示头图不能点击
private MultiBaseAdapter adapter; @Override protected void onCreate(Bundle savedInstanceState) { // TODO 自动生成的方法存根 super.onCreate(savedInstanceState); setContentView(R.layout.listview_normal_layout); String[] data = {"android","ios","wp","c++", "java","c#","javascript","vb", "delphi","PB","ASP","SQL"}; final LinearLayout settingLL = (LinearLayout)findViewById(R.id.setting_linearLayout); settingLL.setVisibility(View.GONE); ListView listView = (ListView)findViewById(R.id.normal_listView); /** * 给listview顶部添加2个额外视图,设置顶部视图不可点击 */ listView.addHeaderView(createHeaderView(), null, false); listView.addHeaderView(createHeaderView(), null, false); //实例化适配器 adapter = new MultiBaseAdapter(savedInstanceState, data); //添加视图 adapter.setAdapterView(listView); //设置不显示actionMode adapter.showActionMode(false); //点击事件 adapter.setOnItemClickListener(new MyItemClick(adapter)); //监听选中的状态 adapter.setOnSelectedStateChangeListener(new OnSelectedStateChangeListener() { /** * checkedItemCount = 已经选中的item数目 */ @Override public void onSelectedStateChanged(int checkedItemCount) { if (checkedItemCount != 0) { settingLL.setVisibility(View.VISIBLE); } else { settingLL.setVisibility(View.GONE); } } }); }
private View createHeaderView() { return LayoutInflater.from(this).inflate(R.layout.view_header, null); }
点击事件的监听器:
/** * @author:Jack Tony * @tips :点击事件的监听器 * @date :2014-10-20 */ private class MyItemClick implements OnItemClickListener{ private MultiChoiceBaseAdapter mAdapter; public MyItemClick(MultiChoiceBaseAdapter adapter) { mAdapter = adapter; } @Override public void onItemClick(AdapterView<?> arg0, View arg1, int position, long arg3) { //因为在顶部添加了2个视图,所以这里的位置要下移两位 Toast.makeText(getApplicationContext(), "点击了: " + mAdapter.getItem(position - 2), Toast.LENGTH_SHORT).show(); } }
四、用回调方法来优化
@Override protected void onSaveInstanceState(Bundle outState) { adapter.save(outState); } @Override public boolean onKeyDown(int keyCode, KeyEvent event) { if (keyCode == KeyEvent.KEYCODE_BACK ) { if (adapter.getCheckedItemCount() > 0) { cancleAll(adapter); return true; } } return super.onKeyDown(keyCode, event); }
public void buttonListener(View v) { switch (v.getId()) { case R.id.selectAll_button: selectAll(adapter); break; case R.id.cancle_button: cancleAll(adapter); break; case R.id.delete_button: delectItems(adapter); break; case R.id.share_button: Toast.makeText(getApplicationContext(), "分享"+Arrays.toString(getSelectedItems(adapter)), 1).show(); cancleAll(adapter); break; default: break; } } /** * 全选 * @param adapter */ private void selectAll(MultiChoiceBaseAdapter adapter) { for (int i = 0; i < adapter.getCount(); ++i) { adapter.setItemChecked(i, true); } } /** * 取消所有选择效果 * @param adapter */ private void cancleAll(MultiChoiceBaseAdapter adapter) { for (int i = 0; i < adapter.getCount(); ++i) { adapter.setItemChecked(i, false); } } /** * 得到已经选中的items * @param adapter * @return */ private String[] getSelectedItems(MultiChoiceBaseAdapter adapter) { //得到选中的items Set<Long> selection = adapter.getCheckedItems(); String[] items = new String[selection.size()]; int i = 0; for (long position : selection) { items[i++] = (String)adapter.getItem((int)position); } return items; } /** * 删除已经选中的items * @param adapter */ private void delectItems(MultiChoiceBaseAdapter adapter) { //通过判断名字来remove掉这些items // TODO:删除某些元素,因为这里的数据源是String[]所以没有链表那样好删除,就没去实现。 //实际中:推荐用链表来动态删除元素,在删除时需要注意的是最好以唯一的id,如position来进行删除 cancleAll(adapter); }
搞定了!!!
全部代码:
package com.kale.multichoiceadaptertest; import java.util.Arrays; import java.util.Set; import android.app.Activity; import android.os.Bundle; import android.support.v7.view.ActionMode; import android.view.KeyEvent; import android.view.LayoutInflater; import android.view.Menu; import android.view.MenuItem; import android.view.View; import android.view.ViewGroup; import android.widget.AdapterView; import android.widget.AdapterView.OnItemClickListener; import android.widget.CheckBox; import android.widget.LinearLayout; import android.widget.ListView; import android.widget.TextView; import android.widget.Toast; import com.manuelpeinado.multichoiceadapter.base.OnSelectedStateChangeListener; import com.manuelpeinado.multichoiceadapter.compat.MultiChoiceBaseAdapter; public class BaseAdapterNormalTestActivity extends Activity{ private MultiBaseAdapter adapter; @Override protected void onCreate(Bundle savedInstanceState) { // TODO 自动生成的方法存根 super.onCreate(savedInstanceState); setContentView(R.layout.listview_normal_layout); String[] data = {"android","ios","wp","c++", "java","c#","javascript","vb", "delphi","PB","ASP","SQL"}; final LinearLayout settingLL = (LinearLayout)findViewById(R.id.setting_linearLayout); settingLL.setVisibility(View.GONE); ListView listView = (ListView)findViewById(R.id.normal_listView); /** * 给listview顶部添加2个额外视图,设置顶部视图不可点击 */ listView.addHeaderView(createHeaderView(), null, false); listView.addHeaderView(createHeaderView(), null, false); //实例化适配器 adapter = new MultiBaseAdapter(savedInstanceState, data); //添加视图 adapter.setAdapterView(listView); //设置不显示actionMode adapter.showActionMode(false); //点击事件 adapter.setOnItemClickListener(new MyItemClick(adapter)); //监听选中的状态 adapter.setOnSelectedStateChangeListener(new OnSelectedStateChangeListener() { /** * checkedItemCount = 已经选中的item数目 */ @Override public void onSelectedStateChanged(int checkedItemCount) { if (checkedItemCount != 0) { settingLL.setVisibility(View.VISIBLE); } else { settingLL.setVisibility(View.GONE); } } }); } @Override protected void onSaveInstanceState(Bundle outState) { adapter.save(outState); } @Override public boolean onKeyDown(int keyCode, KeyEvent event) { if (keyCode == KeyEvent.KEYCODE_BACK ) { if (adapter.getCheckedItemCount() > 0) { cancleAll(adapter); return true; } } return super.onKeyDown(keyCode, event); } private View createHeaderView() { return LayoutInflater.from(this).inflate(R.layout.view_header, null); } private class MultiBaseAdapter extends MultiChoiceBaseAdapter{ private String[] mData; /** * 构造函数 * @param savedInstanceState */ public MultiBaseAdapter(Bundle savedInstanceState,String[] data) { super(savedInstanceState); // TODO 自动生成的构造函数存根 mData = data; } @Override public boolean onCreateActionMode(ActionMode mode, Menu menu) { return true; } @Override public boolean onActionItemClicked(ActionMode mode, MenuItem item) { return false; } @Override public boolean onPrepareActionMode(ActionMode arg0, Menu arg1) { // TODO 自动生成的方法存根 return false; } /** * 看适配器中有多少元素需要加载 */ @Override public int getCount() { // TODO 自动生成的方法存根 return mData.length; } /** * 通过position来得到相应的item,这里返回object对象 */ @Override public Object getItem(int position) { // TODO 自动生成的方法存根 return mData[position]; } /** * 通过position得到id */ @Override public long getItemId(int position) { // TODO 自动生成的方法存根 return position; } /** * 返回item的view对象 */ @Override protected View getViewImpl(int position, View convertView, ViewGroup parent) { if (convertView == null) { int layout = R.layout.item; LayoutInflater inflater = LayoutInflater.from(getContext()); convertView = inflater.inflate(layout, parent, false); } ViewGroup group = (ViewGroup)convertView; ((TextView)group.findViewById(R.id.item_textView)).setText(mData[position]); ((CheckBox)group.findViewById(android.R.id.checkbox)).setVisibility(View.VISIBLE); return group; } } public void buttonListener(View v) { switch (v.getId()) { case R.id.selectAll_button: selectAll(adapter); break; case R.id.cancle_button: cancleAll(adapter); break; case R.id.delete_button: delectItems(adapter); break; case R.id.share_button: Toast.makeText(getApplicationContext(), "分享"+Arrays.toString(getSelectedItems(adapter)), 1).show(); cancleAll(adapter); break; default: break; } } /** * 全选 * @param adapter */ private void selectAll(MultiChoiceBaseAdapter adapter) { for (int i = 0; i < adapter.getCount(); ++i) { adapter.setItemChecked(i, true); } } /** * 取消所有选择效果 * @param adapter */ private void cancleAll(MultiChoiceBaseAdapter adapter) { for (int i = 0; i < adapter.getCount(); ++i) { adapter.setItemChecked(i, false); } } /** * 得到已经选中的items * @param adapter * @return */ private String[] getSelectedItems(MultiChoiceBaseAdapter adapter) { //得到选中的items Set<Long> selection = adapter.getCheckedItems(); String[] items = new String[selection.size()]; int i = 0; for (long position : selection) { items[i++] = (String)adapter.getItem((int)position); } return items; } /** * 删除已经选中的items * @param adapter */ private void delectItems(MultiChoiceBaseAdapter adapter) { //通过判断名字来remove掉这些items // TODO:删除某些元素,因为这里的数据源是String[]所以没有链表那样好删除,就没去实现。 //实际中:推荐用链表来动态删除元素,在删除时需要注意的是最好以唯一的id,如position来进行删除 cancleAll(adapter); } /** * @author:Jack Tony * @tips :点击事件的监听器 * @date :2014-10-20 */ private class MyItemClick implements OnItemClickListener{ private MultiChoiceBaseAdapter mAdapter; public MyItemClick(MultiChoiceBaseAdapter adapter) { mAdapter = adapter; } @Override public void onItemClick(AdapterView<?> arg0, View arg1, int position, long arg3) { //因为在顶部添加了2个视图,所以这里的位置要下移两位 Toast.makeText(getApplicationContext(), "点击了: " + mAdapter.getItem(position - 2), Toast.LENGTH_SHORT).show(); } } }
开源项目MultiChoiceAdapter详解(一)——概要介绍
开源项目MultiChoiceAdapter详解(二)——MultiChoiceArrayAdapter的使用
开源项目MultiChoiceAdapter详解(三)——MulitChoiceNormalArrayAdapter的使用
开源项目MultiChoiceAdapter详解(四)——MultiChoiceBaseAdapter的使用
开源项目MultiChoiceAdapter详解(五)——可扩展的MultiChoiceBaseAdapter
开源项目MultiChoiceAdapter详解(六)——GridView和MultiChoiceBaseAdapter配合使用