Android ListView longClickable=";“真的”;禁用McClick侦听器
我的ListView有问题。我想在正常单击时显示一个上下文操作栏和列表项的详细信息片段。 但是如果我在列表项的xml布局中设置longClickable=“true”,则不会触发onItemClickListener;如果我删除该行,则可以单击该项,但现在longclick无法处理NullPointerException。 我现在花了几个小时来解决这个问题,例如在布局中使用安卓:genderantfocusability=“blocksDescendants”,或者在列表项中的元素上使用focusability=“false”。什么都不管用。这里有一些代码Android ListView longClickable=";“真的”;禁用McClick侦听器,android,listview,android-listview,onclicklistener,onlongclicklistener,Android,Listview,Android Listview,Onclicklistener,Onlongclicklistener,我的ListView有问题。我想在正常单击时显示一个上下文操作栏和列表项的详细信息片段。 但是如果我在列表项的xml布局中设置longClickable=“true”,则不会触发onItemClickListener;如果我删除该行,则可以单击该项,但现在longclick无法处理NullPointerException。 我现在花了几个小时来解决这个问题,例如在布局中使用安卓:genderantfocusability=“blocksDescendants”,或者在列表项中的元素上使用focu
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>
公共类CustomItemAdapter扩展了ArrayAdapter
我应该避免在那里设置任何侦听器吗
这是我的布局的根元素:
<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" >
感谢您的帮助。当我想要实现与您描述的完全相同的目标时,我使用以下代码:
/*
* 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);
}
}
/*
*版权所有2012谷歌公司。
*
*根据Apache许可证2.0版(以下简称“许可证”)获得许可;
*除非遵守许可证,否则不得使用此文件。
*您可以通过以下方式获得许可证副本:
*
* http://www.apache.org/licenses/LICENSE-2.0
*
*除非适用法律要求或书面同意,软件
*根据许可证进行的分发是按“原样”进行分发的,
*无任何明示或暗示的保证或条件。
*请参阅许可证以了解管理权限和权限的特定语言
*许可证下的限制。
*/
包com.maddogs.mymoney.utils;
导入java.util.HashSet;
导入android.annotation.SuppressLint;
导入android.annotation.TargetApi;
导入android.os.Build;
导入android.os.Bundle;
导入android.os.Handler;
导入android.support.v7.app.ActionBarActivity;
导入android.support.v7.view.ActionMode;
导入android.util.Pair;
导入android.util.SparseBooleanArray;
导入android.view.Menu;
导入android.view.MenuItem;
导入android.view.view;
导入android.widget.AbsListView;
导入android.widget.Adapter;
导入android.widget.AdapterView;
导入android.widget.ListView;
/**
*用于在列表视图中处理多个选择的实用程序。包含
*类似于{@link AbsListView#CHOICE_MODE_MULTIPLE_model}的功能,但
*它与{@link ActionBarActivity}和向后兼容的操作一起工作
*酒吧。
*/
@TargetApi(构建版本代码蜂窝)
公共类MultiSelectionUtil{
公共静态控制器附件MultiSelectionController(
最终列表视图列表视图,最终操作活动活动,
最终多选模式(侦听器){
返回Controller.attach(listView、activity、listener);
}
@SuppressLint(“新API”)
公共静态类控制器实现ActionMode.Callback,
AdapterView.OnItemClickListener,
AdapterView.OnItemLongClickListener{
私有处理程序mHandler=新处理程序();
私人行动模式;
私有ListView mListView=null;
private ActionBarActivity MacActivity=null;
专用MultiChoiceModelListener mListener=null;
私有HashSet mTempIdsToCheckOnRestore;
私有HashSet-mItemsToCheck;
私有AdapterView.OnItemClickListener mOldItemClickListener;
专用控制器(){
}
公共静态控制器连接(ListView ListView,
ActionBarActivity活动,MultiChoiceModelListener侦听器){
控制器=新控制器();
controller.mListView=listView;
controller.mActivity=活动;
controller.mListener=侦听器;
setOnItemLongClickListener(控制器);
返回控制器;
}
私有void readInstanceState(Bundle savedInstanceState){
mTempIdsToCheckOnRestore=null;
如果(savedInstanceState!=null){
long[]checkedds=savedInstanceState
.getLongArray(getStateKey());
if(checkedds!=null&&checkedds.length>0){
mTempIdsToCheckOnRestore=new HashSet();
用于(长id:checkedIds){
mTempIdsToCheckOnRestore.add(id);
}
}
}
}
public void tryRestoreInstanceState(Bundle savedInstanceState){
readInstanceState(savedInstanceState);
tryRestoreInstanceState();
}
公共空间整理(){
if(mActionMode!=null){
mActionMode.finish();
}
}
public void tryRestoreInstanceState(){
如果(MTEMPIDTOCHECKONRESTORE==null
||mListView.getAdapter()=空){
返回;
}
布尔值=false;
Adapter=mListView.getAdapter();
对于(int pos=adapter.getCount()-1;pos>=0;pos--){
if(mTempIdsToCheckOnRestore.contains(adapter.getItemId(pos))){
idsFound=true;
if(mItemsToCheck==null){
mItemsToCheck=newhashset();
}
mItemsToCheck.添加(新的一对(位置、适配器
.getItemId(pos));
}
}
如果(idsFound){
//我们找到了一些已检查的ID。现在让我们还原
//多选
//国家。
MTEMPIDTOCHECKONRESTORE=null;//清除此临时字段
mActionMode=mActivity.startSupportActionMode(Controller.this);
}
}
公共布尔值saveInstanceState(Bundle expandle){
//TODO:通过持久化位置而不是
//身份证