Górne menu- Toolbar

W aplikacjach mobilnych opartych na systemie Android górne menu (Toolbar) stanowi kluczowy element interfejsu użytkownika. Umożliwia ono szybki dostęp do najważniejszych funkcji aplikacji, takich jak ustawienia, pomoc, informacje o programie czy wyjście. W odróżnieniu od klasycznego ActionBar, Toolbar jest komponentem bardziej elastycznym i konfigurowalnym, co pozwala na jego pełne dostosowanie do wyglądu i potrzeb aplikacji.

Podczas tej lekcji nauczysz się, jak utworzyć i osadzić własny Toolbar w aplikacji stworzonej w Android Studio z użyciem języka Kotlin. Dowiesz się, jak zbudować plik XML definiujący zawartość menu, jak obsłużyć kliknięcia w jego elementy oraz jak dostosować jego wygląd do kolorystyki aplikacji. Krok po kroku prześledzisz cały proces tworzenia funkcjonalnego i estetycznego górnego paska narzędzi.

Kontrolka Toolbar

Kontrolka Toolbar to nowoczesny i bardziej konfigurowalny odpowiednik klasycznego paska akcji (ActionBar). Umożliwia osadzanie przycisków, ikon, tytułu oraz rozwijanego menu w górnej części aplikacji. Aby móc z niej skorzystać, należy najpierw odwołać się do niej z poziomu kodu Kotlin.

Układ widoku aplikacji będzie się składać z trzech elementów:

Marginesy dobierz według własnego uznania.

Android Studio górne menu toolbar

W pierwszym kroku tworzymy zmienną, która będzie reprezentować Toolbar zdefiniowany w pliku activity_main.xml. Użycie funkcji findViewById() pozwala przypisać widok Toolbar'u do zmiennej w kodzie. W tym momencie może jeszcze pojawić się błąd kompilacji, ponieważ brakuje odpowiedniego importu klasy Toolbar.

Tworzymy zmienną odwołującą się do kontrolki Toolbar. Jej inicjacja wywołuje komunikat błędu.

Android Studio jak utworzyć toolbar

Importujemy wymaganą bibliotekę

Wskazówka:


import androidx.appcompat.widget.Toolbar

Własny Toolbar zdefiniowany w XML wymaga integracji z systemowym menu oraz nawigacją. W tym celu stosuje się metodę setSupportActionBar(). Odpowiedni fragment kodu

Wskazówka:


// Ustawienie toolbaru jako ActionBar
val toolbar = findViewById(R.id.my_toolbar)
setSupportActionBar(toolbar)

Od tej pory tworzony Toolbar jest traktowany jako wbudowany ActionBar, czyli podstawowy pasek narzędzi w ramach danej aktywności, na którym może być wyświetlany tytuł aktywności, opcje nawigacji na poziomie aplikacji i inne interaktywne elementy.

Tworzenie zawartości menu paska Toolbar

Aby Toolbar mógł wyświetlać własne przyciski i opcje, należy przygotować specjalny plik menu w formacie XML. Plik ten zawiera definicje wszystkich elementów, które mają pojawić się na pasku narzędzi, takich jak ikony, nazwy opcji czy ich pozycja (na pasku lub w rozwijanym menu).

Plik menu umieszczamy w katalogu res/menu, który może być utworzony ręcznie lub za pomocą kreatora. Z poziomu Android Studio wystarczy kliknąć prawym przyciskiem myszy na folder res, a następnie wybrać New ? Android Resource File. W nowym oknie podajemy nazwę pliku (np. menu_toolbar.xml) i wybieramy typ zasobu menu.

W hierarchii projektu wskaż folder res i z menu prawego przycisku myszki wybierz New/ Android Resources File

Android Studio jak utworzyć toolbar New/ Android Resources File Android Studio plik xml dla górnego menu toolbar

Prawidłowo wykonane kroki zmieniają układ hierarchii projektu- pojawia się nowy folder wraz z plikiem XML, w którym tworzy się zawartość menu.

Android Studio toolbar hierarchia projektu

Przykładowo taka prosta zawartość pliku menu_toolbar.xml

Wskazówka:


<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:android="http://schemas.android.com/apk/res/android">

    <item
        android:id="@+id/menu_settings"
        android:title="Ustawienia"/>

    <item
        android:id="@+id/menu_help"
        android:title="Pomoc"/>
    
    <item android:title="Item" />
</menu>

Tworzy menu o postaci

Android Studio toolbar górne menu

Jeżeli chcemy aby elementy menu były w miarę możliwości zawarte w górnym pasku na przykład w postaci ikon, to wprowadzamy poniższe zmiany do pliku XML zawartości menu

Wskazówka:


<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:android="http://schemas.android.com/apk/res/android">

    <item
        android:id="@+id/menu_settings"
        android:title="Ustawienia"
        android:icon="@android:drawable/ic_menu_preferences"
        app:showAsAction="ifRoom" />

    <item
        android:id="@+id/menu_help"
        android:title="Pomoc"
        android:icon="@android:drawable/ic_menu_help"
        app:showAsAction="ifRoom" />

    <item
        android:id="@+id/menu_zamknij"
        android:title="Zamknij"/>
    
</menu>
toolbar app:showAsAction

Atrybut app:showAsAction w pliku menu XML decyduje o tym, gdzie i w jaki sposób dany element menu zostanie wyświetlony w aplikacji.

Ustawienie app:showAsAction="ifRoom" oznacza, że element menu zostanie pokazany bezpośrednio na pasku Toolbar tylko wtedy, gdy będzie na to wystarczająco dużo miejsca. Jeśli miejsca zabraknie, element zostanie automatycznie przeniesiony do rozwijanego menu (ikona z trzema kropkami).

Z kolei app:showAsAction="never" wymusza umieszczenie elementu wyłącznie w rozwijanym menu, niezależnie od ilości dostępnego miejsca na pasku. Tego atrybutu używa się zwykle dla mniej używanych funkcji lub takich, które nie wymagają natychmiastowego dostępu.

Dzięki tym ustawieniom mamy pełną kontrolę nad rozmieszczeniem opcji menu i ich widocznością w interfejsie użytkownika.

Przykład modyfikacji zawartości pliku XML o dwa kolejne elementy menu, które znajdą się w rozwijanym menu.

Wskazówka:


<!-- Te element tylko w rozwijanym menu -->
<item
    android:id="@+id/menu_o_aplikacji"
    android:title="O aplikacji"
    app:showAsAction="never" />
<item
    android:id="@+id/menu_zamknij"
    android:title="Zamknij"
    app:showAsAction="never" />

Wczytanie menu z pliku XML

Aby wyświetlić elementy menu w Toolbarze, Android musi wczytać ich definicję z przygotowanego pliku XML (np. menu_toolbar.xml). Do tego celu służy MenuInflater ? klasa, która ?nadmuchuje? (inflatuje) strukturę XML i przekształca ją w obiekt Menu, który następnie jest renderowany w interfejsie.

W głównym pliku importujemy bibliotekę obsługi menu (android.view.Menu)

Wskazówka:


import android.os.Bundle
import android.view.Menu
import androidx.appcompat.widget.Toolbar

Kolejnym krokiem jest nadpisanie metody override fun onCreateOptionsMenu(), która automatycznie wywoływana jest przy tworzeniu Toolbaru. W tej metodzie menuInflater.inflate(R.menu.menu_toolbar, menu) wczytuje zawartość naszego pliku menu_toolbar.xml do menu w aplikacji.

Przykładowa implementacja wygląda tak:

Wskazówka:


class MainActivity : AppCompatActivity() {
    
    // Inflacja menu - wczytanie elementów menu z pliku XML
    override fun onCreateOptionsMenu(menu: Menu?): Boolean {
        menuInflater.inflate(R.menu.menu_toolbar, menu)
        return true
    }
}

Po skompilowaniu aplikacji zostanie załadowane nowe menu.

toolbar nowe menu

Zmiana koloru tła i ikon Toolbaru

W pliku colors.xml definiujemy kolor tła obszaru paska Toolbar

Wskazówka:


<?xml version="1.0" encoding="utf-8"?>
<resources>
    <color name="black">#FF000000</color>
    <color name="white">#FFFFFFFF</color>
    <color name="zolty">#FFC107</color>
</resources>

Przechodzimy do pliku układu głównego widoku activity_main.xml wprowadzamy poniższe zmiany dla elementu Toolbar

Wskazówka:


<androidx.appcompat.widget.Toolbar
    android:id="@+id/my_toolbar"
    android:layout_width="match_parent"
    android:layout_height="?attr/actionBarSize"
    android:elevation="4dp"
    app:title="@string/moj_toolbar"
    android:background="@color/zolty"

    android:theme="@style/ThemeOverlay.AppCompat.Light"
    app:titleTextColor="@android:color/white"
    app:popupTheme="@style/ThemeOverlay.AppCompat.Light"/>

Kompilujemy aplikację i sprawdzamy wygląd menu.

Zmiana koloru tła i ikon Toolbaru

Kolor tła został zmieniony ale nie są widoczne ikony menu rozwijanego (overflow menu) po kliknięciu w ikonę trzech kropek. Dzieje się tak, ponieważ należy wymusić w kodzie programu wyświetlenie tych ikon. Rozwiązanie to jest dostępne dla API 11 i wzwyż. Wprowadź poniższe zmiany w pliku MainActivity.kt

Wskazówka:


// Inflacja menu - wczytanie elementów menu z pliku XML
@SuppressLint("RestrictedApi")
override fun onCreateOptionsMenu(menu: Menu?): Boolean {
    menuInflater.inflate(R.menu.menu_toolbar, menu)
    // Wymuszenie ikon w overflow menu (działa od API 11 wzwyż)
    if (menu is androidx.appcompat.view.menu.MenuBuilder) {
        menu.setOptionalIconsVisible(true)
    }
    return true
}

Uruchom aplikację i sprawdź efekt działania

Toolbaru Inflacja menu

Obsługa elementów menu

Obsługę kliknięcia elementów menu przedstawimy jako wyświetlenie krótkiego komunikatu. Jedynie w opcji Zamknij zrealizujemy rzeczywiste zamkniecie programu. Do pliku MainActivity.kt dopisujemy funkcję wyświetlającą komunikat.

Wskazówka:


private fun pokazKomunikat(tekstKomunikatu: String) {
    android.widget.Toast.makeText(this, tekstKomunikatu, android.widget.Toast.LENGTH_SHORT).show()
}

Obsługę kliknięcia w elementy menu realizuje nadpisanie metody onOptionsItemSelected(), której argumentami są elementy menu.

Wskazówka:


override fun onOptionsItemSelected(item: android.view.MenuItem): Boolean {
    return when (item.itemId) {
        R.id.menu_settings -> {
            // Obsługa kliknięcia ?Ustawienia?
            pokazKomunikat("Kliknięto: Ustawienia")
            true
        }
        R.id.menu_help -> {
            pokazKomunikat("Kliknięto: Pomoc")
            true
        }
        R.id.menu_o_aplikacji -> {
            pokazKomunikat("Kliknięto: O aplikacji")
            true
        }
        R.id.menu_zamknij -> {
            pokazKomunikat("Kliknięto: Zamknij")
            finishAffinity() // Zamyknij wszystkie aktywności
            true
        }
        else -> super.onOptionsItemSelected(item)
    }
}

Uruchom aplikację i sprawdź efekt działania.

Toolbaru obsługa menu

Zmiana tła wybranego elementu menu

W Androidzie elementy menu w menu rozwijanym (overflow) nie wspierają bezpośrednio atrybutu android:background w XML. Czyli konstrukcja android:background="@color/zolty" zapisana w pliku XML budowy menu nie będzie obsłużona.

Problem można rozwiązać na przykład bezpośrednio w kodzie nadpisując tworzone menu aplikacji. W tym celu tworzy się zmienną wykorzystującą łącznik do elementu, do którego można dołączać znaczniki.

Wskazówka:


override fun onCreateOptionsMenu(menu: Menu?): Boolean {
    menuInflater.inflate(R.menu.menu_toolbar, menu)
    // Wymuszenie ikon w overflow menu (działa od API 11 wzwyż)
    if (menu is androidx.appcompat.view.menu.MenuBuilder) {
        menu.setOptionalIconsVisible(true)
    }
    // Znajdź konkretny element menu i ustaw mu kolor tła
    val item = menu!!.findItem(R.id.menu_zamknij)
    //utwórz łacznik do obiektu do którego mozna dołaczac znaczniki
    val span = android.text.SpannableString(item.title)
    span.setSpan(
        android.text.style.BackgroundColorSpan(
            resources.getColor(R.color.zolty, theme)
        ),
        0, span.length,
        android.text.Spannable.SPAN_INCLUSIVE_INCLUSIVE
    )
    item.title = span
    return true
}
Toolbaru zmiana tła elementu

Zmiana tła całego elementu w rozwijanym menu (overflow) to jedno z trudniejszych zadań, ponieważ Android nie udostępnia oficjalnie API (na dzień w którym ten tekst powstał), które by na to pozwalało. Ale jest sposób, który działa ? z dostępem do wewnętrznych widoków popup menu przez refleksję.

Technika użyta w tym przypadku to tzw. refleksja (ang. reflection) ? zaawansowany mechanizm języka Kotlin (i Javy), który pozwala na dostęp do elementów klas w czasie działania programu, nawet jeśli są one prywatne lub normalnie niedostępne przez standardowe API.

Dzięki refleksji możemy m.in.:

W przypadku rozwijanego menu (overflow) Android nie udostępnia publicznego sposobu na zmianę tła pojedynczego elementu. Dzięki refleksji można ?zajrzeć? do struktury, która buduje rozwijane menu, a następnie ręcznie zmienić tło wybranego wiersza, korzystając z jego obiektu widoku (View).

Należy jednak pamiętać, że użycie refleksji wiąże się z pewnym ryzykiem:

Mimo to, refleksja jest potężnym narzędziem, zwłaszcza tam, gdzie standardowe możliwości są ograniczone.

Pełny kod pliku MainActivity.kt

Wskazówka:


import android.annotation.SuppressLint
import android.os.Bundle
import android.view.Menu
import androidx.appcompat.widget.Toolbar
import androidx.activity.enableEdgeToEdge
import androidx.appcompat.app.AppCompatActivity
import androidx.core.view.ViewCompat
import androidx.core.view.WindowInsetsCompat

class MainActivity : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        enableEdgeToEdge()
        setContentView(R.layout.activity_main)
        ViewCompat.setOnApplyWindowInsetsListener(findViewById(R.id.main)) { v, insets ->
            val systemBars = insets.getInsets(WindowInsetsCompat.Type.systemBars())
            v.setPadding(systemBars.left, systemBars.top, 
						systemBars.right, systemBars.bottom)
            insets
        }
        // Ustawienie toolbaru jako ActionBar
        val toolbar = findViewById<Toolbar>(R.id.my_toolbar)
        setSupportActionBar(toolbar)
    }

    // Inflacja menu - wczytanie elementów menu z pliku XML
    @SuppressLint("RestrictedApi")
    override fun onCreateOptionsMenu(menu: Menu?): Boolean {
        menuInflater.inflate(R.menu.menu_toolbar, menu)
        // Wymuszenie ikon w overflow menu (działa od API 11 wzwyż)
        if (menu is androidx.appcompat.view.menu.MenuBuilder) {
            menu.setOptionalIconsVisible(true)
        }
        // Znajdź konkretny element menu i ustaw mu kolor tła
        val item = menu!!.findItem(R.id.menu_zamknij)
        //utwórz łacznik do obiektu do którego mozna dołaczac znaczniki
        val span = android.text.SpannableString(item.title)
        span.setSpan(
            android.text.style.BackgroundColorSpan(
                resources.getColor(R.color.zolty, theme)
            ),
            0, span.length,
            android.text.Spannable.SPAN_INCLUSIVE_INCLUSIVE
        )
        item.title = span
        return true
    }



    override fun onOptionsItemSelected(item: android.view.MenuItem): Boolean {
        return when (item.itemId) {
            R.id.menu_settings -> {
                // Obsługa kliknięcia ?Ustawienia?
                pokazKomunikat("Kliknięto: Ustawienia")
                true
            }
            R.id.menu_help -> {
                pokazKomunikat("Kliknięto: Pomoc")
                true
            }
            R.id.menu_o_aplikacji -> {
                pokazKomunikat("Kliknięto: O aplikacji")
                true
            }
            R.id.menu_zamknij -> {
                pokazKomunikat("Kliknięto: Zamknij")
                finishAffinity() // Zamyknij wszystkie aktywności
                true
            }
            else -> super.onOptionsItemSelected(item)
        }
    }

    private fun pokazKomunikat(tekstKomunikatu: String) {
        android.widget.Toast.makeText(this, tekstKomunikatu,
			android.widget.Toast.LENGTH_SHORT).show()
    }

}
Układ okresowy- kod qr
Układ okresowy

Układ okresowy pierwiastków- darmowa aplikacja na Androida

Pobierz ze sklepu Google Play
Alkomat- wirtualny test kod qr
Alkomat- wirtualny test

Alkomat- darmowa aplikacja na Androida

Pobierz ze sklepu Google Play
Światłomierz fotograficzny kod qr
Światłomierz fotograficzny

Światłomierz fotograficzny- darmowa aplikacja na Androida

Pobierz ze sklepu Google Play
Taklarz- olinowanie stałe kod qr
Olinowanie stałe- kalkulator średnic

Olinowanie stałe- darmowa aplikacja na Androida

Pobierz ze sklepu Google Play
przepis na gogfry

Przepis na gofry

zobacz
przepis na bitą śmietanę

Przepis na bitą śmietanę

zobacz