🎨 UI – Views & Layouts · Lesson 18
Toolbar, Options Menu & Popup Menu
MaterialToolbar
The top bar shows the screen title, a navigation icon and action items. Use a NoActionBar theme and add your own MaterialToolbar — you control its look and can put it inside CoordinatorLayout.
XML + Kotlin
<!-- res/values/themes.xml: parent="Theme.Material3.DayNight.NoActionBar" -->
<com.google.android.material.appbar.AppBarLayout
android:layout_width="match_parent"
android:layout_height="wrap_content">
<com.google.android.material.appbar.MaterialToolbar
android:id="@+id/toolbar"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
app:title="My Notes" />
</com.google.android.material.appbar.AppBarLayout>
// Kotlin – in onCreate after setContentView
setSupportActionBar(binding.toolbar)Create a menu resource
Right-click res → New → Android Resource File → type Menu → name menu_main.
XML – res/menu/menu_main.xml
<!-- res/menu/menu_main.xml -->
<menu xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto">
<item
android:id="@+id/action_search"
android:icon="@drawable/ic_search"
android:title="Search"
app:actionViewClass="androidx.appcompat.widget.SearchView"
app:showAsAction="ifRoom|collapseActionView" />
<item
android:id="@+id/action_sort"
android:icon="@drawable/ic_sort"
android:title="Sort"
app:showAsAction="ifRoom" />
<item
android:id="@+id/action_settings"
android:title="Settings"
app:showAsAction="never" />
<item
android:id="@+id/action_about"
android:title="About"
app:showAsAction="never" />
</menu>Show and handle the menu
Kotlin – MainActivity
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
// … binding + setSupportActionBar(binding.toolbar)
addMenuProvider(object : MenuProvider {
override fun onCreateMenu(menu: Menu, menuInflater: MenuInflater) {
menuInflater.inflate(R.menu.menu_main, menu)
}
override fun onMenuItemSelected(menuItem: MenuItem): Boolean = when (menuItem.itemId) {
R.id.action_sort -> { showSortDialog(); true }
R.id.action_settings -> { startActivity(Intent(this@MainActivity, SettingsActivity::class.java)); true }
R.id.action_about -> { Toast.makeText(this@MainActivity, "Version 1.0", Toast.LENGTH_SHORT).show(); true }
else -> false
}
})
}
}SearchView in the toolbar
Kotlin
// inside onCreateMenu, after inflating
val searchView = menu.findItem(R.id.action_search).actionView as SearchView
searchView.queryHint = "Search notes…"
searchView.setOnQueryTextListener(object : SearchView.OnQueryTextListener {
override fun onQueryTextSubmit(query: String?): Boolean {
searchView.clearFocus() // hide keyboard
return true
}
override fun onQueryTextChange(newText: String?): Boolean {
adapter.submitList(allNotes.filter { it.title.contains(newText.orEmpty(), ignoreCase = true) })
return true
}
})Up (back) button and title
Kotlin – DetailActivity
// Second activity: show ← and a title
class DetailActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binding = ActivityDetailBinding.inflate(layoutInflater)
setContentView(binding.root)
setSupportActionBar(binding.toolbar)
supportActionBar?.setDisplayHomeAsUpEnabled(true)
supportActionBar?.title = "Note details"
supportActionBar?.subtitle = "Physics"
}
override fun onSupportNavigateUp(): Boolean {
finish() // close this screen
return true
}
}With the Navigation Component, setupActionBarWithNavController does this automatically (see the Navigation Component lesson).
Popup menu
XML + Kotlin
<!-- res/menu/menu_note_item.xml -->
<menu xmlns:android="http://schemas.android.com/apk/res/android">
<item android:id="@+id/action_edit" android:title="Edit" />
<item android:id="@+id/action_share" android:title="Share" />
<item android:id="@+id/action_delete" android:title="Delete" />
</menu>
// Kotlin – show it under the ⋮ button of a list row
binding.btnMore.setOnClickListener { anchor ->
PopupMenu(anchor.context, anchor).apply {
menuInflater.inflate(R.menu.menu_note_item, menu)
setOnMenuItemClickListener { item ->
when (item.itemId) {
R.id.action_edit -> openEditor(note)
R.id.action_share -> share(note)
R.id.action_delete -> confirmDelete(note)
}
true
}
show()
}
}Fragment-specific menus
Kotlin – Fragment
// From Student Diary – NotesFragment (menu only while this screen is visible)
requireActivity().addMenuProvider(object : MenuProvider {
override fun onCreateMenu(menu: Menu, menuInflater: MenuInflater) {
menuInflater.inflate(R.menu.menu_notes, menu)
}
override fun onMenuItemSelected(menuItem: MenuItem) = false
}, viewLifecycleOwner, Lifecycle.State.RESUMED)Common mistakes
- Not calling
setSupportActionBar→ menu never appears. - Returning
falsefor an item you handled → the click is passed on and may run twice. - Adding a MenuProvider in a fragment without
viewLifecycleOwner→ the menu items pile up every time you return. - Using
android.widget.SearchViewin the menu while importingandroidx.appcompat.widget.SearchView→ ClassCastException.
Summary
- NoActionBar theme + MaterialToolbar +
setSupportActionBar. - Menus are XML resources; handle clicks with
addMenuProvider. - SearchView via
actionViewClass; PopupMenu for per-item actions; Up button withsetDisplayHomeAsUpEnabled.
✅ Practice
Add a toolbar with Search, Sort and an overflow "About" item to your list screen. Search filters the list live; Sort opens a single-choice dialog.
Frequently Asked Questions
Why use MenuProvider instead of onCreateOptionsMenu?
onCreateOptionsMenu in Fragments is deprecated. MenuProvider is lifecycle-aware: added with viewLifecycleOwner, the menu items disappear automatically when the screen goes away.
What does showAsAction mean?
ifRoom shows the item as an icon in the toolbar when there is space; never keeps it in the ⋮ overflow menu; always forces it to be visible.
Why is my toolbar menu not showing?
Your theme probably has its own action bar and you did not call setSupportActionBar(binding.toolbar), or the theme is not a NoActionBar theme.
