Kreiranje menija kod android aplikacija

Kreiranje sadržaja menija

Ovaj specifični meni se prikazuje u sklopu

Gde se nalaze meniji?

Za svaki meni je potrebno definisati stavke koje se nalaze u njemu. To se definiše u XML formatu u fajlu koje se nalazi u specifičnom folderu pod nazivom “menu” (nalazi se u sklopu “res” foldera). Ovaj fajl generišemo desnim klikom na folder “menu” u project sekciji i izborom New / “Menu resurse file” opcije.

<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android">
   // ovde ide sadržaj menija
</menu>

Atributi item elementa menija

Stavke menija se definišu kroz element <item/> koji može imati definisane mnoge atribute, najčešće korišćeni atributi su sledeći:

  • id (android:id=”@+id/delete”)
  • title (android:title=”@string/delete”)
  • icon (android:icon=”@drawable/ic_delete”)
  • enabled (android:enabled=”false”)
  • checkable (android:checkable=”true”)
  • showAsAction (Ovi atributi su vezani za prikazivanje elemenata “options menija”u okviru action bar-a )
    • ifRoom (app:showAsAction=”ifRoom”)
    • withText (app:showAsAction=”withText”)
    • never (app:showAsAction=”never”)
    • always (app:showAsAction=”always”)
Primer
<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android">
    <item
            android:id="@+id/edit_menu_item"
            android:title="@string/edit"
            android:checkable="true"
            android:checked="true"
            android:icon="@drawable/ic_mode_edit" />
    <item
            android:id="@+id/make_default"
            android:title="@string/make_default"
            android:checkable="true"
            android:checked="true"/>
    <item
            android:id="@+id/delete_menu_item"
            android:title="@string/delete"
            android:icon="@drawable/ic_delete" />
</menu>

Grupe

Moguće je okupiti slične članove menija u grupe:

<group android:id="@+id/group_delete">
    <item android:id="@+id/menu_archive"
          android:title="@string/menu_archive" />
    <item android:id="@+id/menu_delete"
          android:title="@string/menu_delete" />
</group>

Podmeni

Pravljenje podmenija je jednostavno, u sklopu “item” elementa treba ugraditi novi “menu” element:

<menu xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:android="http://schemas.android.com/apk/res/android">
    <item
        android:id="@+id/edit_menu_item2"
        android:icon="@drawable/ic_mode_edit"
        android:title="@string/edit"
        app:showAsAction="ifRoom" />
    <item
        android:id="@+id/options_menu"
        android:icon="@drawable/ic_device_hub_black"
        android:title="Options">
        <menu>
            <item
                android:id="@+id/subMenu1"
                android:title="Submenu1"/>
            <item
                android:id="@+id/subMenu2"
                android:title="Submenu2"/>
        </menu>
    </item>
</menu>

NAPOMENA:
Kod elemenata kod kojih se koristi atribut android:checkable=”true” je nakon klika na ovakav član menija potrebno da podesite stanje u polju za potvrdu, jer checkBox (ili radio dugme) ne menja automatski svoje stanje. Nakon klika moramo da upitamo kakvo je stanje stavke bile pre ovog klika (da li je bilo čekirano) koristeći isChecked().
Ako je prethodno bilo čekirano onda sada nakon klika više nije i moramo da stavimo stanje setChecked(false) i obrnuto ako nije bilo čekirano item.isChecked()=false sada posle klika jeste i moramo da stavimo item.setChecked(true);

switch (item.getItemId()) {
     case R.id.make_default:
        if (item.isChecked()){
            item.setChecked(false);
            Toast.makeText(this, "Sada više nije čekirano", Toast.LENGTH_SHORT).show();
        }else {
            item.setChecked(true);
            Toast.makeText(this, "Sada je čekirano", Toast.LENGTH_SHORT).show();
        }
        return true;
}

Plivajući menu (floating context menu)

Kreiranje sadržaja menija

Prvo je potrebno definisati sadržaj menija u XML formatu.

Primer (neki_menu.xml)
<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content">
    <item
        android:checkable="true"
        android:id="@+id/make_default"
        android:title="@string/make_default" />
    <item
        android:id="@+id/save"
        android:title="@string/save" />
    <item
        android:id="@+id/remove"
        android:title="@string/remove" />
</menu>

U ovome primeru prvi element menija je tzv. checkbox.

Integrisanje menija u aktivnost

Nakon definisanja sadržaja je potrebno da se omogući da taj meni bude dostupan u aktivnosti.

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

Registrovanje dugmeta koje otvara meni

U sklopu aktivnosti je potrebno registrovati dugme (u onCreate() metodi) koje će biti povezano za taj meni:

ImageView ivOptionsMenuBtn;
ivOptionsMenuBtn = findViewById(R.id.ivOptionsDots);

registerForContextMenu(ivOptionsMenuBtn);

A zatim zakačiti clickListener za njega koji će na klik da pozove metodu openContextMenu(view):

ivOptionsMenuBtn.setOnClickListener(new View.OnClickListener() {
    @Override
    public void onClick(View v) {
        openContextMenu(v);
    }
});

Definisanje šta će da se dogodi klikom na člana menija

U metodi onContextItemSelected() definišemo šta će da se desi klikom na neki od članova menija. Za selektovnanje člana menija se koristi “id” itema definisanog u XML-u (neki_menu.xml):

@Override
public boolean onContextItemSelected(MenuItem item) {
    switch (item.getItemId()) {
        case R.id.make_default:
            Toast.makeText(this, "Make default", Toast.LENGTH_SHORT).show();
            return true;
        case R.id.save:
            Toast.makeText(this, "Save", Toast.LENGTH_SHORT).show();
            return true;
        case R.id.remove:
            Toast.makeText(this, "Remove", Toast.LENGTH_SHORT).show();
            return true;
        default:
            return super.onContextItemSelected(item);
    }
}

Options meni

options menu

Za options meni nije potrebno da se definiše dugme koje će da reaguje na klik i otvori ovaj meni, zato što ovo dugme android sam ubacuje u action bar i dodeljuje mu ikonicu sa tri vertikalne tačke.

Treba naglasiti da ovde imamo priliku definišemo koji će član menija u biti odmah prikazan u actionBar-u pored options ikone (tri vertikalne tačke). Ovo se obezbedjuje sa atributom app:showAsAction="ifRoom". Options meni se prikazuje baš na mestu kliknutog dugmeta. Ukoliko se neki član prikazuje odmah u action baru on se onda ne nalazi u samom meniju.

Kreiranje sadržaja menija

Pored ovih specifičnosti kao i kod svih drugih menija i ovde je neophodno da se definiše sadržaj menija u XML formatu.

<?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/share"
            android:icon="@drawable/ic_device_hub_black"
            android:title="device"
            app:showAsAction="ifRoom" />
    <item
            android:id="@+id/edit_menu_item"
            android:icon="@drawable/ic_mode_edit"
            android:title="@string/edit" />
    <item
            android:id="@+id/make_default"
            android:checkable="true"
            android:title="Make default" />
    <item
            android:id="@+id/delete_menu_item"
            android:title="@string/delete"
            android:icon="@drawable/ic_delete" />
    <item
            android:id="@+id/exit"
            android:title="Exit" />
</menu>

open options menu

Integrisanje menija u aktivnost

Na sličan način kao kod Context Float menija se i ovde integriše meni:

@Override
public boolean onCreateOptionsMenu(Menu menu) {
    MenuInflater inflater =getMenuInflater();
    inflater.inflate(R.menu.options_menu, menu);
    return true;
}

Definisanje šta će da se dogodi klikom na člana menija

U metodi onOptionsItemSelected definišemo šta će da se desiti nakon klika na neki od članova menija:

@Override
public boolean onOptionsItemSelected(MenuItem item) {
    switch (item.getItemId()) {
        case R.id.share:
            Toast.makeText(this, "Share", Toast.LENGTH_SHORT).show();
            return true;
        case R.id.edit_menu_item:
            Toast.makeText(this, "Edit", Toast.LENGTH_SHORT).show();
            return true;
        case R.id.make_default:
            if (item.isChecked()){
                item.setChecked(false);
                Toast.makeText(this, "Is not default", Toast.LENGTH_SHORT).show();
            }else {
                item.setChecked(true);
                Toast.makeText(this, "Is default", Toast.LENGTH_SHORT).show();
            }
            return true;
        case R.id.delete_menu_item:
            Toast.makeText(this, "Delete", Toast.LENGTH_SHORT).show();
            return true;
        case R.id.exit:
            Toast.makeText(this, "Exit", Toast.LENGTH_SHORT).show();
            return true;
        default:
            return super.onOptionsItemSelected(item);
    }
}

PopUp meni

Ovaj meni je specifičan jer je vezan za mesto gde je kliknuto. Meni se prikazuje tamo gde ima prostora ili ispod kliknutog mesta, ili iznad kliknutog mesta. PopUp meni se sakriva sa ekrana kada korisnik klikne na neki član menija ili negde sa strane van menija.

popup

Definisanje šta će da se dogodi klikom na člana menija

Da bi klasa (npr. aktivnost) mogla da izvrši akcije nakon klika potrebno je da klasa implementira interfejs PopupMenu.OnMenuItemClickListener.
Nakon imeplementiranja interfejsa je potrebno da se implementira (Override) i njegova abstraktna metoda onMenuItemClick(), kroz koju nam je omogućeno da definišemo za svaki član menija koja će akcija biti preduzeta nakon klika na član.

@Override
public boolean onMenuItemClick(MenuItem menuItem) {
    switch (menuItem.getItemId()) {
        case R.id.edit_menu_item:
            Toast.makeText(this, "Edit", Toast.LENGTH_SHORT).show();
            return true;
        case R.id.delete_menu_item:
            Toast.makeText(this, "Delete", Toast.LENGTH_SHORT).show();
            return true;
        case R.id.make_default:
            Toast.makeText(this, "MakeDefault", Toast.LENGTH_SHORT).show();
            return true;
        default:
            return false;
    }
}

Integrisanje menija u aktivnost

Da bi prikazali PopUp meni potrebno je da na okidaču (npr. neko dugme) definišemo onClick metodu (npr. shoPopup()) koja izgleda ovako:

 public void showPopup (View v){
    PopupMenu popup = new PopupMenu(this, v);
    // Dodavanje listenera na svaki član menija
    popup.setOnMenuItemClickListener(this);
    //Povezivanje sa sadrzajem menija
    MenuInflater inflater = popup.getMenuInflater();
    inflater.inflate(R.menu.popup_menu, popup.getMenu());
    // Prikazivanje menija
    popup.show();
}

Contextual Action Mode meni

Ovaj specifični meni se prikazuje u sklopu actionBar-a, tačnije preko actionBar-a se. Pored članova menija prikazanih ikonama u desnom kraju, nalazi se i naslov menija u sredini, i strelica za zatvaranje menija na levoj strani.

pre
pre

Kreiranje sadržaja menija

Kao i za svaki meni prvo je potrebno napraviti sadržaj menija u xml formatu (New “Menu resurse file”) u folderu “menu”

Primer (context_action_menu.xml)
<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android">
    <item
        android:id="@+id/edit_menu_item"
        android:title="@string/edit"
        android:icon="@drawable/ic_mode_edit" />
    <item
        android:id="@+id/delete_menu_item"
        android:title="@string/delete"
        android:icon="@drawable/ic_delete" />
</menu>

Definisanje ActionModeCallback metode

Pre svega u sklopu aktivnosti je potrebno definisati promenjivu tipa ActionMode (napomena izabrari verziju v.7) jer se ona koristi u okviru callback metode:

private ActionMode mActionMode;

A zatim i ActionModeCallback instancu u kojoj se vrši sav posao u vezi Contextual Action Mode menijem. Ima 4 metode, u prvoj onCreateActionMode() se povezuje predhodno definisan sadržaj menija sa Action Mode menijem. U metodi onActionItemClicked() se definišu akcije nakon klika na neki od članova. A ono šta se dešava kada se meni zatvori se definiše u metodi onDestroyActionMode().

private ActionMode.Callback mActionModeCallback = new ActionMode.Callback() {
    @Override
    public boolean onCreateActionMode(ActionMode actionMode, Menu menu) {
        // Povezivanje prethodno definisanog sadržaja sa ovim tipom menija
        actionMode.getMenuInflater().inflate(R.menu.context_action_menu, menu);
        // Definisanje Title menija
        actionMode.setTitle("Izaberite opciju");
        return true;
    }
    @Override
    public boolean onPrepareActionMode(ActionMode actionMode, Menu menu) {
        return false;
    }
    @Override
        public boolean onActionItemClicked(ActionMode actionMode, MenuItem menuItem) {
            //Definisanje akcije na klik svakog člana menija
            switch (menuItem.getItemId()) {
                case R.id.edit_menu_item:
                    // Akcija koja se odvija nakon klika na neki član menija:
                    Toast.makeText(MainActivity.this, "Editujemo nešto", Toast.LENGTH_SHORT).show();
                    // Možemo da zatvorimo meni nakon klika na izbor
                    actionMode.finish();
                    return true;
                case R.id.delete_menu_item:
                    Toast.makeText(MainActivity.this, "Brišemo nešto", Toast.LENGTH_SHORT).show();
                    // Možemo da zatvorimo meni nakon klika na izbor
                    actionMode.finish();
                    return true;
                default:
                    return false;
            }
        }
    @Override
    public void onDestroyActionMode(ActionMode actionMode) {
        // Definišemo vrednost ActionMode po zatvaranju menija
        mActionMode = null;
    }
};

Registrovanje dugmeta koje otvara meni

U sklopu aktivnosti je potrebno na odredjenom dugmetu definisati clickListener (u onCreate() metodi) sa kojim ćemo omogućiti da se na klik pozove prethodno definisana callback metoda mActionModeCallback():

mActionMode = startSupportActionMode(mActionModeCallback);

Pa bi ceo kod za listener ovako izgledao:

Button btnContextActionMenu = findViewById(R.id.btnContextActionMenu);
btnContextActionMenu.setOnLongClickListener(new View.OnLongClickListener() {
    @Override
    public boolean onLongClick(View view) {
        // Ako je aktivan menu vratiti false
        if(mActionMode != null){
            return false;
        }
        // Ako je nekativan onda ga aktiviramo
        mActionMode = startSupportActionMode(mActionModeCallback);
        return true;
    }
});