2012-01-12 9 views
18

Sto tentando di ricreare ciò che Google ha fatto con ListView nell'app Gmail. In particolare, vorrei che ogni elemento della lista includesse un CheckBox e due TextViews (uno sopra l'altro). Ho bisogno di ascoltatori per quando il CheckBox è selezionato (o cliccato) e quando viene cliccato su qualsiasi altro elemento della lista. Infine, mi piacerebbe che ActionBar riflettesse che gli elementi sono selezionati e fornisci opzioni come Seleziona tutto, Seleziona Nessuno, ecc. (Vedi this screenshot).ListView simile a Gmail con caselle di controllo (e utilizzando ActionBar)

enter image description here

Finora, ecco il layout mi è venuta.

<?xml version="1.0" encoding="utf-8"?> 
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" 
    android:layout_width="match_parent" 
    android:layout_height="match_parent" 
    android:orientation="horizontal" > 

    <CheckBox android:id="@+id/checkBox" 
     android:layout_width="wrap_content" 
     android:layout_height="wrap_content" 
     android:layout_gravity="center_vertical|center_horizontal" /> 

    <LinearLayout android:id="@+id/linearLayout1" 
     android:layout_width="match_parent" 
     android:layout_height="wrap_content" 
     android:orientation="vertical" 
     android:padding="6dp" 
     android:focusable="true" 
     android:clickable="true" > 

     <TextView android:id="@+id/titleTextView" 
      android:layout_width="match_parent" 
      android:layout_height="wrap_content" 
      android:textSize="16sp" /> 

     <TextView android:id="@+id/dateTextView" 
      android:layout_width="match_parent" 
      android:layout_height="wrap_content" 
      android:textSize="12sp" /> 

    </LinearLayout> 

</LinearLayout> 

Questa mostra tutto correttamente, ma ho bisogno di indicazioni su come impostare gli ascoltatori per le due viste (@ + id/CheckBox e @ + id/linearLayout1). Ho esaminato lo List16 API demo, ma stanno utilizzando il layout simple_list_item_activated_1 e non sono sicuro di quale sia l'XML per questo. Come suggerisce il loro codice, ho creato una classe ModeCallback che implementa ListView.MultiChoiceModeListener e imposto la modalità scelta di ListView su CHOICE_MODE_MULTIPLE_MODAL, ma non so come far funzionare il CheckBox nel mio layout.

Qualcuno ha copiato correttamente il comportamento di ListView dell'app Gmail? Ho cercato un bel po 'e non sono riuscito a trovare nulla (nonostante molti altri facessero domande simili, like this one - la maggior parte delle risposte puntava semplicemente su questa stessa demo API).

Inoltre, per il contesto, sto caricando i dati da un database SQLite nell'elenco e ho creato il mio adattatore Cursore (che funziona bene). Ho la sensazione che ho bisogno di impostare gli ascoltatori in questa classe nei metodi newView() e bindView(), ma tutto quello che ho provato non ha funzionato.

Qualche idea?

+0

Devo spiegare meglio la mia domanda o sto chiedendo troppo? :/ – mturco

risposta

7

La modalità in figura è denominata modalità di azione. Se si utilizza la visualizzazione di riga personalizzata e l'adattatore personalizzato, non è necessario utilizzare CHOICE_MODE_MULTIPLE_MODAL per avviare la modalità di azione. L'ho provato una volta e ho fallito, e ho il sospetto che sia usato per l'adattatore integrato.

Per chiamare la modalità di azione da soli nel codice, chiamare il metodo startActionMode in qualsiasi metodo di ascolto di qualsiasi vista, lasciare che sia la casella di controllo, la visualizzazione di testo o qualcosa del genere. Quindi si passa ModeCallback come parametri e si esegue qualsiasi operazione che si desidera eseguire nella classe ModeCallback.

Non penso che questo funzionerebbe su Android pre-3.0.

Ecco un breve esempio. Ho un'attività elenco espandibile e vorrei richiamare il menu di modalità di azione quando il check utente/deselezionare la casella di controllo, e qui è il mio metodo getChildView nella mia classe adattatore personalizzato:

public View getChildView(int groupPosition, int childPosition, 
      boolean isLastChild, View convertView, ViewGroup parent) { 

     if (convertView == null) { 
      LayoutInflater inflater = (LayoutInflater) getSystemService(Context.LAYOUT_INFLATER_SERVICE); 
      convertView = inflater.inflate(R.layout.childrow, null); 
     } 
     CheckBox cb = (CheckBox)convertView.findViewById(R.id.row_check); 
     cb.setChecked(false); // Initialize 
     cb.setTag(groupPosition + "," + childPosition); 
     cb.setFocusable(false); // To make the whole row selectable 
     cb.setOnCheckedChangeListener(new OnCheckedChangeListener() { 
      public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) { 
       String tag = (String)buttonView.getTag(); 
       String[] pos = tag.split(","); 
       if (isChecked) { 
        if (mActionMode == null) mActionMode = startActionMode(mMultipleCallback);      
       } 
       else { 
        if (mActionMode != null) { // Only operate when mActionMode is available 

         mActionMode.finish(); 
         mActionMode = null; 
        } 
       } 
      } 
     }); 

     TextView tvTop = (TextView)convertView.findViewById(R.id.row_text_top); 
     TextView tvBottom = (TextView)convertView.findViewById(R.id.row_text_bottom); 
     tvTop.setText(mChildren.get(groupPosition).get(childPosition)); 
     tvBottom.setText(mChildrenSize.get(groupPosition).get(childPosition)); 
     return convertView; 
    } 
+0

Grazie! Ci proverò stasera e vedrò se riesco a farlo funzionare. Segnando questo come la risposta fino ad allora. – mturco

2

Rispondendo inoltre di tocnbuff410 utilizzare il seguente codice per aggiornare controllare gli elementi contano

public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) { 
if (isChecked) { 
    ++checkBoxCount; 
} else { 
    --checkBoxCount; 
} 
... 

if (mActionMode != null) { 
    mActionMode.setSubtitle(checkBoxCount + " item(s) selected."); 
} 

posso confermare che seguente codice non funzionerebbe su caselle di listviews personalizzati.Tuttavia, premere a lungo funzionerebbe ancora:

listView.setChoiceMode(ListView.CHOICE_MODE_MULTIPLE_MODAL); 
listView.setMultiChoiceModeListener(new ModeCallback()); 

Selezionare la casella di controllo su ListView personalizzato non attiverebbe la modalità di azione. Solo le ListViews integrate, ad es. estendere ListActivity lo farebbe automaticamente.

+0

Anche molto utile. Grazie! – mturco

11

Funzionerà in SDK 7 (Android 2.1) e versioni successive. (insieme a SherlockActionBar)

Totaly mimic gmail listbox experience.

I override onTouchEvent quindi premere nell'angolo sinistro per attivare la modalità di selezione; Mescch meglio di provare a cliccare sul piccolo cheackbox.

I override performItemClick in modo da premere non a sinistra agirà come un'azione di stampa regolare.

Sovrascrivo setItemChecked in modo che aggiorni mActionMode in base alle esigenze.

public class SelectListView extends ListView { 

    private SherlockFragmentActivity mActivity; 
    ActionMode mActionMode; 

     public SelectListView(Context context) { 
    this(context, null, 0); 
} 

public SelectListView(Context context, AttributeSet attrs) { 
    this(context, attrs, 0); 
} 


public SelectListView(Context context, AttributeSet attrs, int defStyle) { 
    super(context, attrs, defStyle); 
    setChoiceMode(ListView.CHOICE_MODE_MULTIPLE); 
    mActivity = (SherlockFragmentActivity) context; 
} 

    @Override 
    public boolean performItemClick(View view, int position, long id) { 
     OnItemClickListener mOnItemClickListener = getOnItemClickListener(); 
     if (mOnItemClickListener != null) { 
      playSoundEffect(SoundEffectConstants.CLICK); 
      if (view != null) 
       view.sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_CLICKED); 
      mOnItemClickListener.onItemClick(this, view, position, id); 
      return true; 
     } 
     return false; 
    } 

    boolean mSelectionMode = false; 
    int mStartPosition; 

    @Override 
    public boolean onTouchEvent(MotionEvent ev) { 

     final int action = ev.getAction(); 
     final int x = (int) ev.getX(); 
     final int y = (int) ev.getY(); 

     if (action == MotionEvent.ACTION_DOWN && x < getWidth()/7) { 
      mSelectionMode = true; 
      mStartPosition = pointToPosition(x, y); 
     } 
     if (!mSelectionMode) 
      return super.onTouchEvent(ev); 
     switch (action) { 
     case MotionEvent.ACTION_DOWN: 
      break; 
     case MotionEvent.ACTION_MOVE: 
      if (pointToPosition(x, y) != mStartPosition) 
       mSelectionMode = false; 
      break; 
     case MotionEvent.ACTION_CANCEL: 
     case MotionEvent.ACTION_UP: 
     default: 
      mSelectionMode = false; 
      int mItemPosition = pointToPosition(x, y); 
      if (mStartPosition != ListView.INVALID_POSITION) 
       setItemChecked(mItemPosition, !isItemChecked(mItemPosition)); 
     } 

     return true; 
    } 

    @Override 
    public void setItemChecked(int position, boolean value) { 
     super.setItemChecked(position, value); 
     // boolean r = getAdapter().hasStableIds(); 
     int checkedCount = getCheckItemIds().length; 

     if (checkedCount == 0) { 
      if (mActionMode != null) 
       mActionMode.finish(); 
      return; 
     } 
     if (mActionMode == null) 
      mActionMode = mActivity.startActionMode(new ModeCallback()); 

     mActionMode.setTitle(checkedCount + " selected"); 

    } 

    class ModeCallback implements ActionMode.Callback { 

     @Override 
     public boolean onCreateActionMode(ActionMode mode, Menu menu) { 

      menu.add(getResources().getString(R.string.aBar_remove)).setIcon(R.drawable.ic_action_trash) 
        .setShowAsAction(MenuItem.SHOW_AS_ACTION_ALWAYS); 

      return true; 
     } 

     @Override 
     public boolean onPrepareActionMode(ActionMode mode, Menu menu) { 
      return true; 
     } 

     @Override 
     public boolean onActionItemClicked(ActionMode mode, MenuItem item) { 
      Toast.makeText(mActivity, "Delted items", Toast.LENGTH_SHORT).show(); 
      mode.finish(); 
      return true; 
     } 

     @Override 
     public void onDestroyActionMode(ActionMode mode) { 
      mActionMode = null; 
      clearChecked(); 
     } 

    } 

    public void clearChecked() { 
     SparseBooleanArray CItem = getCheckedItemPositions(); 
     for (int i = 0; i < CItem.size(); i++) 
      if (CItem.valueAt(i)) 
       super.setItemChecked(CItem.keyAt(i), false); 
    } 

} 

è possibile utilizzare qualsiasi adattatore listbox necessario.

se si dispone di una casella di controllo sul vostro list_item_layout tou necessità di misura l'adattatore come questo:

ArrayAdapter<String> mAdapter = new ArrayAdapter<String>(this, R.layout.simple_list_item_multiple_choice, 
      R.id.text1, Cheeses.sCheeseStrings) { 

     @Override 
     public View getView(int position, View convertView, ViewGroup parent) { 
      View v = super.getView(position, convertView, parent); 
      CheckBox checkBox = (CheckBox) v.findViewById(R.id.CheckBox); 
      checkBox.setChecked(((ListView)parent).isItemChecked(position)); 
      return v; 
     } 

    }; 

Non dimenticare di utilizzare Android: "attr/activatedBackgroundIndicator" background = sul tuo list_item_layout.xml

+0

implemento la barra delle azioni contestuale con la casella di controllo quando faccio scorrere la lista, quindi non mantengo il conteggio delle caselle di controllo impostato sulla barra di azione. qualsiasi aiuto? –

+0

funziona come un fascino. : D – Uzair

Problemi correlati