Android ListView longClickable =" true"禁用onItemClickListener

时间:2014-07-17 21:08:13

标签: android listview android-listview onclicklistener onlongclicklistener

我的ListView有问题。我想在正常点击时显示一个Contextual ActionBar onItemLongClick和列表项的详细信息片段。 但是,如果我设置longClickable =" true"在我的列表项的xml布局中,onItemClickListener不会触发,如果我删除该行,我可以单击该项但现在长按不会使用NullPointerException。 我现在花费数小时来解决问题,例如android:descendantFocusability =" blocksDescendants"在布局或焦点="假"列表项中的元素。什么都行不通。这是一些代码

mItemAdapter = new CustomItemAdapter(getActivity(), this, mItemList);
mListView.setAdapter(mItemAdapter);
mListView.setChoiceMode(ListView.CHOICE_MODE_MULTIPLE_MODAL);
mListView.setOnItemClickListener(this);
mListView.setOnItemLongClickListener(this);

我使用自定义适配器类和自定义对象来填充我的列表。

public class CustomItemAdapter extends ArrayAdapter<Item>

我应该避免在那里设置任何听众吗?

这是我布局的根元素:

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="?android:attr/listPreferredItemHeight"
    android:background="@drawable/list_item_shape"
    android:descendantFocusability="blocksDescendants"
    android:longClickable="true"
    android:clickable="true"
    android:orientation="vertical" >

感谢您的帮助。

1 个答案:

答案 0 :(得分:0)

当我想要实现您描述的完全相同的东西时,我使用以下代码:

/*
 * Copyright 2012 Google Inc.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.maddogs.mymoney.utils;

import java.util.HashSet;

import android.annotation.SuppressLint;
import android.annotation.TargetApi;
import android.os.Build;
import android.os.Bundle;
import android.os.Handler;
import android.support.v7.app.ActionBarActivity;
import android.support.v7.view.ActionMode;
import android.util.Pair;
import android.util.SparseBooleanArray;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.widget.AbsListView;
import android.widget.Adapter;
import android.widget.AdapterView;
import android.widget.ListView;

/**
 * Utilities for handling multiple selection in list views. Contains
 * functionality similar to {@link AbsListView#CHOICE_MODE_MULTIPLE_MODAL} but
 * that works with {@link ActionBarActivity} and backward-compatible action
 * bars.
 */
@TargetApi(Build.VERSION_CODES.HONEYCOMB)
public class MultiSelectionUtil {
    public static Controller attachMultiSelectionController(
            final ListView listView, final ActionBarActivity activity,
            final MultiChoiceModeListener listener) {
        return Controller.attach(listView, activity, listener);
    }

    @SuppressLint("NewApi")
    public static class Controller implements ActionMode.Callback,
            AdapterView.OnItemClickListener,
            AdapterView.OnItemLongClickListener {
        private Handler mHandler = new Handler();
        private ActionMode mActionMode;
        private ListView mListView = null;
        private ActionBarActivity mActivity = null;
        private MultiChoiceModeListener mListener = null;
        private HashSet<Long> mTempIdsToCheckOnRestore;
        private HashSet<Pair<Integer, Long>> mItemsToCheck;
        private AdapterView.OnItemClickListener mOldItemClickListener;

        private Controller() {
        }

        public static Controller attach(ListView listView,
                                        ActionBarActivity activity, MultiChoiceModeListener listener) {
            Controller controller = new Controller();
            controller.mListView = listView;
            controller.mActivity = activity;
            controller.mListener = listener;
            listView.setOnItemLongClickListener(controller);
            return controller;
        }

        private void readInstanceState(Bundle savedInstanceState) {
            mTempIdsToCheckOnRestore = null;
            if (savedInstanceState != null) {
                long[] checkedIds = savedInstanceState
                        .getLongArray(getStateKey());
                if (checkedIds != null && checkedIds.length > 0) {
                    mTempIdsToCheckOnRestore = new HashSet<Long>();
                    for (long id : checkedIds) {
                        mTempIdsToCheckOnRestore.add(id);
                    }
                }
            }
        }

        public void tryRestoreInstanceState(Bundle savedInstanceState) {
            readInstanceState(savedInstanceState);
            tryRestoreInstanceState();
        }

        public void finish() {
            if (mActionMode != null) {
                mActionMode.finish();
            }
        }

        public void tryRestoreInstanceState() {
            if (mTempIdsToCheckOnRestore == null
                    || mListView.getAdapter() == null) {
                return;
            }

            boolean idsFound = false;
            Adapter adapter = mListView.getAdapter();
            for (int pos = adapter.getCount() - 1; pos >= 0; pos--) {
                if (mTempIdsToCheckOnRestore.contains(adapter.getItemId(pos))) {
                    idsFound = true;
                    if (mItemsToCheck == null) {
                        mItemsToCheck = new HashSet<Pair<Integer, Long>>();
                    }
                    mItemsToCheck.add(new Pair<Integer, Long>(pos, adapter
                            .getItemId(pos)));
                }
            }

            if (idsFound) {
                // We found some IDs that were checked. Let's now restore the
                // multi-selection
                // state.
                mTempIdsToCheckOnRestore = null; // clear out this temp field
                mActionMode = mActivity.startSupportActionMode(Controller.this);
            }
        }

        public boolean saveInstanceState(Bundle outBundle) {
            // TODO: support non-stable IDs by persisting positions instead of
            // IDs
            if (mActionMode != null && mListView.getAdapter().hasStableIds()) {
                long[] checkedIds = mListView.getCheckedItemIds();
                outBundle.putLongArray(getStateKey(), checkedIds);
                return true;
            }

            return false;
        }

        private String getStateKey() {
            return MultiSelectionUtil.class.getSimpleName() + "_"
                    + mListView.getId();
        }

        @Override
        public boolean onCreateActionMode(ActionMode actionMode, Menu menu) {
            if (mListener.onCreateActionMode(actionMode, menu)) {
                mActionMode = actionMode;
                mOldItemClickListener = mListView.getOnItemClickListener();
                mListView.setOnItemClickListener(Controller.this);
                mListView.setChoiceMode(AbsListView.CHOICE_MODE_MULTIPLE);
                mHandler.removeCallbacks(mSetChoiceModeNoneRunnable);

                if (mItemsToCheck != null) {
                    for (Pair<Integer, Long> posAndId : mItemsToCheck) {
                        mListView.setItemChecked(posAndId.first, true);
                        mListener.onItemCheckedStateChanged(mActionMode,
                                posAndId.first, posAndId.second, true);
                    }
                }
                return true;
            }
            return false;
        }

        @Override
        public boolean onPrepareActionMode(ActionMode actionMode, Menu menu) {
            if (mListener.onPrepareActionMode(actionMode, menu)) {
                mActionMode = actionMode;
                return true;
            }
            return false;
        }

        @Override
        public boolean onActionItemClicked(ActionMode actionMode,
                                           MenuItem menuItem) {
            return mListener.onActionItemClicked(actionMode, menuItem);
        }

        @Override
        public void onDestroyActionMode(ActionMode actionMode) {
            mListener.onDestroyActionMode(actionMode);
            SparseBooleanArray checkedPositions = mListView
                    .getCheckedItemPositions();
            if (checkedPositions != null) {
                for (int i = 0; i < checkedPositions.size(); i++) {
                    mListView.setItemChecked(checkedPositions.keyAt(i), false);
                }
            }
            mListView.setOnItemClickListener(mOldItemClickListener);
            mActionMode = null;
            mHandler.post(mSetChoiceModeNoneRunnable);
        }

        private Runnable mSetChoiceModeNoneRunnable = new Runnable() {
            @Override
            public void run() {
                mListView.setChoiceMode(AbsListView.CHOICE_MODE_NONE);
            }
        };

        @Override
        public void onItemClick(AdapterView<?> adapterView, View view,
                                int position, long id) {
            boolean checked = mListView.isItemChecked(position);
            mListener.onItemCheckedStateChanged(mActionMode, position, id,
                    checked);

            int numChecked = 0;
            SparseBooleanArray checkedItemPositions = mListView
                    .getCheckedItemPositions();
            if (checkedItemPositions != null) {
                for (int i = 0; i < checkedItemPositions.size(); i++) {
                    numChecked += checkedItemPositions.valueAt(i) ? 1 : 0;
                }
            }

            if (numChecked <= 0) {
                mActionMode.finish();
            }
        }

        @Override
        public boolean onItemLongClick(AdapterView<?> adapterView, View view,
                                       int position, long id) {
            if (mActionMode != null) {
                return false;
            }

            mItemsToCheck = new HashSet<Pair<Integer, Long>>();
            mItemsToCheck.add(new Pair<Integer, Long>(position, id));
            mActionMode = mActivity.startSupportActionMode(Controller.this);
            return true;
        }
    }

    /**
     * @see android.widget.AbsListView.MultiChoiceModeListener
     */
    public static interface MultiChoiceModeListener extends ActionMode.Callback {
        /**
         * @see android.widget.AbsListView.MultiChoiceModeListener#onItemCheckedStateChanged(android.view.ActionMode,
         * int, long, boolean)
         */
        public void onItemCheckedStateChanged(ActionMode mode, int position,
                                              long id, boolean checked);
    }
}

您只需将此附加到活动和列表视图,实现界面,您就可以使用操作栏进行多选!