我的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" >
感谢您的帮助。
答案 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);
}
}
您只需将此附加到活动和列表视图,实现界面,您就可以使用操作栏进行多选!