Android ListView长按多选模式

来源:互联网 发布:苹果打开数据的快捷键 编辑:程序博客网 时间:2024/06/08 10:31

辛苦堆砌,转载请注明出处,谢谢!

本文示例实现ListView长按条目进入Action Mode,然后可以进行多选,并将选择的条目提前。功能和例子很简单,为的是更好的说明如何实现。


先看一下我们的Activity布局,activity_main.xml

<?xml version="1.0" encoding="utf-8"?><RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"    xmlns:tools="http://schemas.android.com/tools"    android:id="@+id/activity_main"    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"    tools:context="com.yjp.listviewmultiplechoicemodaldemo.MainActivity">    <ListView        android:id="@+id/list_view"        android:layout_width="match_parent"        android:layout_height="match_parent"        android:choiceMode="multipleChoiceModal"/></RelativeLayout>
重点在于ListView的android:choiceMode属性,置为了mutipleChoiceModal模式。


然后是item的布局item_with_check_box.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="wrap_content"    android:paddingTop="5dp"    android:paddingBottom="5dp">    <TextView        android:id="@+id/text_view"        android:layout_width="wrap_content"        android:layout_height="wrap_content"        android:textAppearance="?android:textAppearanceLarge" />    <CheckBox        android:id="@+id/selected_check_box"        android:layout_width="wrap_content"        android:layout_height="wrap_content"        android:layout_gravity="center"        android:clickable="false"        android:focusable="false"        android:visibility="invisible"/></RelativeLayout>

CheckBox默认不可见,后面我们会看到,只有进入Action Mode时才会显示,我们关注的重点在于CheckBox的clickable和focusable属性都是false,这样可以避免界面响应CheckBox的点击事件,这就避免了我们手动点击CheckBox导致的勾选,大家或许有疑问,这样不对吗?在正常情况下使用,的确是对的,但是由于ListView会重复利用ItemView,所以我们如果靠我们自己记录ItemView中的CheckBox的状态就会出现问题,我们无法知道我们自己维护的CheckBox是否已经重复使用。如果想测试,大家可以自己做个试验,做一个ListView,每个条目中有一个CheckBox,不要置clickable和focusable属性为false,条目多一些,保证一个屏幕放置不下,这时候你先滚动到最底下,然后手动点击CheckBox,然后来回滚动ListView,你会发现,之前勾选的会消失。


当然,如果你乐意,可以维护CheeckBox的勾选状态,但是这样实在是太费劲了,反正我是不乐意。


接下来,还有两个xml文件,一个是我们进入到Action Mode时的Action Bar布局action_mode_bar.xml,如下所示

<?xml version="1.0" encoding="utf-8"?><LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"    android:orientation="horizontal"    android:layout_width="match_parent"    android:layout_height="match_parent">    <TextView        android:id="@+id/title"        android:layout_width="wrap_content"        android:layout_height="wrap_content"        android:textAppearance="?android:textAppearanceMediumInverse"/></LinearLayout>
有一个TextView,用来显示我们希望显示的内容,这里显示“已选择 X 项”。最后一个xml是一个menu,check_task_priority.xml,作为Action Mode的menu使用。

<?xml version="1.0" encoding="utf-8"?><menu xmlns:android="http://schemas.android.com/apk/res/android"    xmlns:app="http://schemas.android.com/apk/res-auto">    <item        android:id="@+id/cancel"        android:title="取消"        app:showAsAction="always"/>    <item        android:id="@+id/up"        android:title="提前"        app:showAsAction="always"/></menu>

下面是我们的MainActivity

package com.yjp.listviewmultiplechoicemodaldemo;import android.annotation.SuppressLint;import android.content.Context;import android.support.annotation.LayoutRes;import android.support.annotation.NonNull;import android.support.annotation.Nullable;import android.support.v7.app.AppCompatActivity;import android.os.Bundle;import android.view.ActionMode;import android.view.LayoutInflater;import android.view.Menu;import android.view.MenuItem;import android.view.View;import android.view.ViewGroup;import android.widget.AbsListView;import android.widget.AdapterView;import android.widget.ArrayAdapter;import android.widget.CheckBox;import android.widget.ListView;import android.widget.TextView;import android.widget.Toast;import java.util.ArrayList;import java.util.Collections;import java.util.List;public class MainActivity extends AppCompatActivity {    private CheckListViewAdapter mAdapter;    private List<Integer> mItems = new ArrayList<>();    @Override    protected void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        setContentView(R.layout.activity_main);        ListView listView = (ListView) findViewById(R.id.list_view);        mAdapter = new CheckListViewAdapter(this,                R.layout.item_with_check_box,                mItems);        listView.setAdapter(mAdapter);        listView.setMultiChoiceModeListener(new MultiChoiceModeListener(listView));        listView.setOnItemClickListener(new AdapterView.OnItemClickListener() {            @Override            public void onItemClick(AdapterView<?> parent, View view, int position, long id) {                Toast.makeText(MainActivity.this, "点击条目", Toast.LENGTH_SHORT).show();            }        });    }    @Override    protected void onStart() {        super.onStart();        mItems.addAll(getItems());        mAdapter.notifyDataSetChanged();    }    @Override    protected void onStop() {        super.onStop();        mItems.clear();    }    private List<Integer> getItems() {        List<Integer> items = new ArrayList<>();        for (int i = 0; i < 20; i++) {            items.add(i);        }        return items;    }    private class MultiChoiceModeListener implements AbsListView.MultiChoiceModeListener {        private ListView mListView;        private TextView mTitleTextView;        private List<Integer> mSelectedItems = new ArrayList<>();        private MultiChoiceModeListener(ListView listView) {            mListView = listView;        }        @Override        public void onItemCheckedStateChanged(ActionMode mode, int position, long id, boolean checked) {            mSelectedItems.add(mAdapter.getItem(position));            mTitleTextView.setText("已选择 " + mListView.getCheckedItemCount() + " 项");            mAdapter.notifyDataSetChanged();        }        @Override        public boolean onCreateActionMode(ActionMode mode, Menu menu) {            mode.getMenuInflater().inflate(R.menu.check_task_priority, menu);            @SuppressLint("InflateParams")            View multiSelectActionBarView = LayoutInflater.from(MainActivity.this)                    .inflate(R.layout.action_mode_bar, null);            mode.setCustomView(multiSelectActionBarView);            mTitleTextView = (TextView)multiSelectActionBarView.findViewById(R.id.title);            mTitleTextView.setText("已选择 0 项");            mAdapter.setCheckable(true);            mAdapter.notifyDataSetChanged();            return true;        }        @Override        public boolean onPrepareActionMode(ActionMode mode, Menu menu) {            return false;        }        @Override        public boolean onActionItemClicked(ActionMode mode, MenuItem item) {            switch (item.getItemId()) {                case R.id.cancel:                    break;                case R.id.up:                    Collections.sort(mSelectedItems);                    for (Integer selectedItem : mSelectedItems) {                        mItems.remove(selectedItem);                    }                    mItems.addAll(0, mSelectedItems);                    break;                default:                    break;            }            mode.finish();            return true;        }        @Override        public void onDestroyActionMode(ActionMode mode) {            mSelectedItems.clear();            mAdapter.setCheckable(false);            mAdapter.notifyDataSetChanged();        }    }    private class CheckListViewAdapter extends ArrayAdapter<Integer> {        private boolean mCheckable;        private CheckListViewAdapter(@NonNull Context context,                                @LayoutRes int resource,                                @NonNull List<Integer> objects) {            super(context, resource, objects);        }        @NonNull        @Override        public View getView(int position, @Nullable View convertView, @NonNull ViewGroup parent) {            ViewHolder holder;            if (null == convertView) {                convertView = LayoutInflater.from(getContext())                        .inflate(R.layout.item_with_check_box, parent, false);                holder = new ViewHolder();                holder.textView = (TextView) convertView.findViewById(R.id.text_view);                holder.checkBox = (CheckBox) convertView.findViewById(R.id.selected_check_box);                convertView.setTag(holder);            } else {                holder = (ViewHolder) convertView.getTag();            }            Integer item = getItem(position);            if (item != null) {                holder.textView.setText(item.toString());            }            //可见性和选中状态            if (mCheckable) {                holder.checkBox.setVisibility(View.VISIBLE);            } else {                holder.checkBox.setVisibility(View.INVISIBLE);            }            holder.checkBox.setChecked(((ListView) parent).isItemChecked(position));            return convertView;        }        //用来设置是否CheckBox可见        private void setCheckable(boolean checkable) {            mCheckable = checkable;        }        private class ViewHolder {            private TextView textView;            private CheckBox checkBox;        }    }}
上面的代码中最关键的是要看到我们经常会调用notifyDataSetChanged(),原因在于我们在getView时会按照ListView记录的对应position的选择状态设置我们CheckBox的勾选状态,这样,我们就利用了ListView记录的选择状态,而不需要我们自己维护状态。上面的代码其他部分不难理解,可以运行之后自己试试。











0 0
原创粉丝点击