0

J'ai un problème avec ma ListView. Je souhaite afficher un objet ActionBar contextuel onItemLongClick et le fragment de détail de l'élément de liste lorsque je fais un clic normal. Mais si je mets longClickable = "true" dans ma mise en page xml de l'élément de liste, onItemClickListener ne se déclenchera pas, si je supprime la ligne, je peux cliquer sur l'élément mais maintenant long click ne fonctionnera pas avec NullPointerException. Je passe des heures maintenant pour résoudre le problème avec par exemple android: descendantFocusability = "blocksDescendants" dans la mise en page ou focusable = "false" sur les éléments dans l'élément de la liste. Rien ne fonctionne. Voici un codeAndroid ListView longClickable = "true" désactive onItemClickListener

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

J'utilise une classe d'adaptateur personnalisé avec des objets personnalisés pour remplir ma liste.

public class CustomItemAdapter extends ArrayAdapter<Item> 

Dois-je éviter de définir des écouteurs?

Ceci est l'élément racine de ma mise en page:

<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" > 

Merci pour toute aide.

+0

Une fois que vous avez défini les écouteurs de clic dans le code, vous n'avez pas besoin de toucher le fichier XML. J'ai implémenté avec succès le comportement que vous visez sans aucune mention de 'cliquer' dans le fichier XML. – ygesher

Répondre

0

J'utilise le code suivant quand je veux obtenir exactement la même chose que vous avez décrit:

/* 
* 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); 
    } 
} 

Vous attachez simplement ceci à une activité et listview, mettre en œuvre l'interface et vous avez un multiselection avec le travail actionbar!

Questions connexes