Nelle interfacce Android è molto ricorrente imbattersi nel menu contestuale. Esso viene solitamente attivato in corrispondenza di un evento di long touch su un elemento del layout, ed offre comandi relativi a tale elemento. La sua forma naturale è un pannello flottante che mostra l'elenco di opzioni. È in tutto e per tutto un menu, costruito con un layout inserito tra le risorse del progetto nella cartella /res/menu, ed elaborato dal MenuInflater.
Esiste una forma alternativa, anch'essa molto diffusa, detta Contextual Action Bar (o CAB). Finalizzata agli stessi scopi di un menu contestuale, la CAB può essere considerata una Action Bar temporanea che riporta i comandi attivabili sotto forma di action.
La figura seguente mostra il medesimo menu, costituito dalle voci Edit, Share e Delete, realizzato nelle due versioni di menu contestuale flottante e CAB.
In questa lezione, impareremo ad introdurre una CAB all'interno di un'interfaccia utente, e lo sperimenteremo nel news reader che stiamo realizzando passo passo.
Creazione di una Contextual Action Bar
Una Contextual Action Bar può essere attivata in ogni momento nella nostra applicazione. Per consentire ciò, si devono svolgere tre operazioni.
Per prima cosa, è necessario creare il layout del menu in un file XML, posizionato nella cartella /res/menu del progetto.
Successivamente, inseriamo nell'Activity un membro che implementa l'interfaccia ActionMode.Callback. Essa descrive i metodi di interazione principali di una CAB, che sono:
-
onCreateActionMode
: invocato alla creazione della CAB; -
onPrepareActionMode
: attivato ogni volta che l'ActionMode viene invalidato; -
onActionItemClicked
: invocato nel momento in cui una delle action presenti nella CAB viene selezionata; -
onDestroyActionMode
: contiene le operazioni da svolgere al momento della distruzione della Contextual Action Bar.
Tutti i metodi appena citati ricevono come primo parametro in input un oggetto ActionMode. Questo contiene tutti i metodi necessari per interagire con la barra. Particolarmente utili sono setTitle
, che permette di impostare il titolo, e finish
, che forza la chiusura della Contextual Action Bar.
Una volta predisposto tutto il necessario secondo i primi due passi, non resta che attivare la CAB con il metodo, offerto dal Context, startActionMode che riceverà in input il riferimento all'oggetto ActionMode.Callback
.
Prima di passare all'esempio, è bene notare che solitamente si è abituati ad attivare un menu contestuale con un long touch su un elemento. Ciò può essere riprodotto con la CAB semplicemente invocando startActionMode
dall'interno di un listener OnLongClickListener
assegnato al widget che vogliamo collegare alla CAB.
L'esempio: una CAB a selezione multipla
Molto spesso capita che si voglia attuare l'operazione selezionata nella CAB su più elementi di una ListView
o GridView
. Lo si può fare in maniera molto simile a quanto visto nel paragrafo precedente, ma attuando dei piccoli accorgimenti.
Il news reader realizzato nelle lezioni precedenti mostra, per ogni categoria, una serie di titoli di notizie visualizzate in un ListFragment
. Quella che vogliamo realizzare è una CAB attivata alla selezione di uno o più elementi della lista e che mostri una sola action contenente il comando di condivisione dei titoli di notizie tramite le app installate sul dispositivo.
Per realizzare una CAB a selezione multipla su una ListView
è necessario:
-
attivare la modalità
CHOICE_MODE_MULTIPLE_MODAL
; -
impostare il
MultiChoiceModeListener
mediante il metodosetMultiChoiceModeListener
. UnMultiChoiceModeListener
implementa unActionMode.Callback
e servirà a gestire il ciclo di vita di un ActionMode.
Nella figura che segue, si vede un esempio di quanto detto, applicato al nostro news reader. Selezionando alcune notizie si può scegliere se condividerle. Il sistema propone tutte le app raggiungibili, e alla fine viene scelta Google Keep. Nella porzione destra dell'immagine si vede come le informazioni selezionate vengono trattate: accodate in una lista nel corpo della nota.
Per realizzare ciò, iniziamo col creare il layout del menu nel file /res/menu/cab.xml:
<menu xmlns:android="http://schemas.android.com/apk/res/android">
<item
android:id="@+id/action_share"
android:showAsAction="ifRoom"
android:title="Share"
android:icon="@android:drawable/ic_menu_share"/>
</menu>
Nella classe ContentFragment
gestiremo il collegamento tra la ListView
e la CAB nel metodo onActivityCreated
del ciclo di vita del Fragment:
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
getListView().setChoiceMode(ListView.CHOICE_MODE_MULTIPLE_MODAL);
getListView().setMultiChoiceModeListener(new AbsListView.MultiChoiceModeListener() {
@Override
public void onItemCheckedStateChanged(ActionMode mode,int position, long id, boolean checked) {
int checkedCount = getListView().getCheckedItemCount();
mode.setTitle(checkedCount + " Selezionati");
}
@Override
public boolean onPrepareActionMode(ActionMode mode, Menu menu) {
return false;
}
@Override
public void onDestroyActionMode(ActionMode mode) {
}
@Override
public boolean onCreateActionMode(ActionMode mode, Menu menu) {
mode.getMenuInflater().inflate(R.menu.cab, menu);
return true;
}
@Override
public boolean onActionItemClicked(ActionMode mode, MenuItem item) {
switch (item.getItemId()) {
case R.id.action_share:
StringBuffer text=new StringBuffer();
SparseBooleanArray a = getListView().getCheckedItemPositions();
for (int i = 0; i < a.size(); i++) {
if (a.valueAt(i)) {
text.append(((Content)getListView().getAdapter().getItem(a.keyAt(i))).getTitle());
text.append("\n");
}
}
Intent intent = new Intent(Intent.ACTION_SEND);
intent.setType("text/plain");
intent.putExtra(Intent.EXTRA_TEXT, text.toString());
intent.putExtra(android.content.Intent.EXTRA_SUBJECT, "Notizie da ricordare");
startActivity(Intent.createChooser(intent, "Share"));
}
mode.finish();
return false;
}
});
}
Dopo aver impostato la modalità di selezione CHOICE_MODE_MULPTIPLE_MODAL, implementiamo l'oggetto MultiChoiceModeListener
, in cui:
- nel metodo onItemCheckedStateChanged viene cambiato il titolo mostrato sulla CAB. Ciò avverrà ad ogni modifica della selezione;
-
in onActionItemClicked vengono letti tutti gli elementi selezionati, accodati in un unico testo ed inoltrati al sistema con un Intent di tipo
ACTION_SEND
. La risposta di Android sarà un elenco di applicazioni che possono trattare quel genere di dati; - in onCreateActionMode viene semplicemente costruita la Contextual Action Bar usando il layout /res/menu/main.xml come schema di progetto.
In allegato alla lezione è disponibile il codice sorgente dell'esempio appena discusso.