11

Kontextové menu pro komponentu ListView

Kontextové menu se velmi často používá v případě, kdy máme seznam určitých položek načten v seznamu (ListView, GridView,…) a chceme přiřadit každé položce z tohoto seznamu kontextové menu. Nejlépe si tuto možnost vysvětlíme na jednoduchém příkladu.


Příklad 2 – Kontextové menu pro ListView – Můj pestrý život

Přidejme k přehledu záznamů v aplikaci, kterou jsme naprogramovali v předchozích kapitolách. Do kontextového menu pro jednotlivé položky přidáme volby „Odstranit“, „Přepni důležitost“ a „Upravit“. Položky „Odstranit“ a „Přepni důležitost“ implementujeme, volbu „Upravit“ realizujeme až v příští kapitole, kde se zároveň naučíme vytvářet a volat nové aktivity (další obrazovky aplikace).


Celá aplikace bude ve výsledku vypadat takto:


Obrázek 1 –


Postup:

  1. Otevřeme si projekt Můj pestrý život z předchozích kapitol. (Pokud projekt z nějakého důvodu nemáte, můžete si vytvořit jednoduchou komponentu ListView, která bere položky z kontejneru ArrayList.)

    Připomeňme, že v projektu máme třídu Data (kontejner záznamů) a třídu Zaznam s textovými atributy nazev a popis a atributem dulezite, který je datového typu logická hodnota (boolean). Pro snazší práci a pro dodržení principu zapouzdření si do třídy Data přidáme metody:

  2. public Zaznam getZaznam(int pozice) {
        return this.data.get(pozice);
    }
    public void odstranZaznam(int pozice) {
        this.data.remove(pozice);
        this.notifyObservers();
    }
    

  3. V souboru res/values/strings.xml definujeme textové řetězce, popisující texty v menu:

        <string name="app_name">Můj pestrý život</string>
        <string name="menu_load_file">Obnov</string>
        <string name="menu_save_file">Ulož</string>
        <string name="kmenu_remove">Odeber záznam</string>
        <string name="kmenu_change_importance">Přepni důležitost</string>
        <string name="kmenu_edit">Uprav záznam...</string>
    </resources>
    

    Vytvoříme soubor res/menu/menu_prezence.xml a nadefinujeme v něm položky menu. Elementy a význam atributů zůstávají stejné jako v předchozích kapitolách při tvorbě hlavního menu a kontextového menu pro běžné položky:

    <?xml version="1.0" encoding="utf-8"?>
    <menu xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:app="http://schemas.android.com/apk/res-auto" >
        <item android:id="@+id/km_remove" android:title="@string/kmenu_remove"
            android:orderInCategory="100" app:showAsAction="never" />
        <item android:id="@+id/km_change_importance" android:title="@string/kmenu_change_importance"
            android:orderInCategory="100" app:showAsAction="never" />
        <item android:id="@+id/km_edit" android:title="@string/kmenu_edit"
            android:orderInCategory="100" app:showAsAction="never" />
        
    </menu>
    

  4. Seznamu (ListView) nyní zaregistrujemev metodě onCreate(…) hlavní aktivity kontextové menu – tím řekneme překladači, že chceme, aby položky ListView měly kontextové menu. To jsme se již naučili v předchozí kapitole:

    this.registerForContextMenu(this.seznam);
    

    Překryjeme metodu onCreateContextMenu třídy Activity (přidáme do naší aktivity metodu onCreateContextMenu(…):

    @Override
    public void onCreateContextMenu(ContextMenu menu, View v, ContextMenu.ContextMenuInfo menuInfo) {
        super.onCreateContextMenu(menu, v, menuInfo);
        MenuInflater inflater = getMenuInflater();
        inflater.inflate(R.menu.kontext_menu_zaznamy, menu);
    }
    

Aplikaci můžeme nyní zkusit spustit. Kontextové menu je u každé položky (záznamu), zatím ale nereaguje na výběr.


Reakce na volbu položky z menu:

  1. Překryjeme si metodu onContextItemSelected(…) pro reakci na výběr položky. Pro určení, na jakou položku v ListView jsme klikli, využijeme třídu AdapterContextMenuInfo. V případě potřeby o změně dat v ArrayListu informujeme adaptér metodou notifyDataSetChanged() – to už známe z kapitoly o ListView. Naše třídy již mají informaci o změně vyřešenu pomocí mechanismu pozorovatele.

  2. @Override
    public boolean onContextItemSelected(MenuItem item) {
        AdapterView.AdapterContextMenuInfo infoOZvolenePolozce =
                (AdapterView.AdapterContextMenuInfo) item.getMenuInfo();
        switch(item.getItemId()) {
            case R.id.km_change_importance:
                Zaznam zaznam = this.zaznamy.getZaznam(infoOZvolenePolozce.position);
                zaznam.invertujDulezite();
                return true;
            case R.id.km_edit:
                Toast.makeText(this, "Editace zatím není implementována", Toast.LENGTH_SHORT).show();
                return true;
            case R.id.km_remove:
                this.zaznamy.odstranZaznam(infoOZvolenePolozce.position);
            default:
                return super.onContextItemSelected(item);
        }
    }
    

Shrnutí:

  1. Při použití kontextového menu v seznamu (ListView,…) registrujeme kontextové menu pro celý seznam.

  2. Stejně jako u klasického kontextového menu nám metoda MenuItem.getItemId() sdělí ID zvolené položky menu.

  3. Pozici zvolené položky v adaptéru získáme pomocí vnořené třídy AdapterView.AdapterContextMenuInfo. Tato třída nese atribut position, který udává pozici zvolené položky v adaptéru. Instanci třídy získáme metodou MenuItem.getMenuInfo().