简体   繁体   中英

ToolBar menu item click in a fragment (Kotlin)

In my app, i have an Activity, which has a FrameLayout in it. In this FrameLayout, there is a fragment, containing a ToolBar and a RecyclerView.

In this toolbar, i have a search button, which should start an Activity on item click. However, when i try to use onOptionsItemSelected, the apps gets built and installed succesfully, but when i try to tap that button in question, nothing happens. The Logcat, doesnt say anything either.

Can some points me what im doing wrong? Are there simpler or other easy ways to manage on ToolBar item clicks?

Fragment.kt

class FragmentTrack : Fragment() {
    ...

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setHasOptionsMenu(true)
    }

    override fun onCreateView(
        inflater: LayoutInflater,
        container: ViewGroup?,
        savedInstanceState: Bundle?
    ): View? = inflater.inflate(R.layout.fragment_track, container, false)

    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        super.onViewCreated(view, savedInstanceState)

        ...

        topToolbar.setNavigationOnClickListener {
            val dialog = FragmentBottomSheetDrawer()
            dialog.show(childFragmentManager, dialog.tag)

        }
    }

    override fun onCreateOptionsMenu(menu: Menu, inflater: MenuInflater) {
        inflater.inflate(R.menu.menu_toolbar, menu)
        super.onCreateOptionsMenu(menu, inflater)
    }

    override fun onOptionsItemSelected(item: MenuItem): Boolean {
        when(item.itemId) {
            R.id.fsvSearch -> Toast.makeText(context, "Clicked search button", Toast.LENGTH_SHORT).show()
        }
        return true
    }
}

fragment.xml

<?xml version="1.0" encoding="utf-8"?>
<androidx.coordinatorlayout.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    xmlns:app="http://schemas.android.com/apk/res-auto">

    <com.google.android.material.appbar.AppBarLayout
        android:id="@+id/appbar"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="vertical"
        android:theme="@style/Theme.Design.NoActionBar">

        <androidx.appcompat.widget.Toolbar
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:id="@+id/topToolbar"
            android:background="@color/colorPrimaryDark"
            app:navigationIcon="@drawable/ic_outline_menu_24"
            app:popupTheme="@style/popupMenuThemeDark"
            app:titleTextColor="@android:color/white"
            app:title="Revo"
            app:menu="@menu/menu_toolbar"
            app:layout_scrollFlags="scroll|enterAlways" />

    </com.google.android.material.appbar.AppBarLayout>

    <androidx.recyclerview.widget.RecyclerView
        android:id="@+id/rvTracks"
        android:layout_height="match_parent"
        android:layout_width="match_parent"
        android:clipToPadding="false"
        app:layout_behavior="@string/appbar_scrolling_view_behavior"
        />

</androidx.coordinatorlayout.widget.CoordinatorLayout>

toolbar_menu.xml

<?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/fsvSearch"
            android:icon="@drawable/ic_search_24px"
            android:title="@string/search"
            app:showAsAction="always"/>
 
        <item
            android:id="@+id/fsvOrder"
            android:icon="@drawable/ic_sort_24px"
            android:title="@string/sort"
            app:showAsAction="ifRoom">
                <menu>
                        <group android:id="@+id/sortMenu" android:checkableBehavior="single">
                                <item
                                    android:id="@+id/sortIncrease"
                                    android:title="@string/increasing"/>
 
                                <item
                                    android:id="@+id/sortDecrease"
                                    android:title="@string/decreasing"/>
 
                                <item
                                    android:id="@+id/sortMArtist"
                                    android:title="@string/artist"/>
 
                                <item
                                    android:id="@+id/sortAlbum"
                                    android:title="@string/albums"/>
 
                                <item
                                    android:id="@+id/sortYear"
                                    android:title="@string/year"/>
 
                                <item
                                    android:id="@+id/sortDate"
                                    android:title="@string/date"/>
 
                        </group>
                </menu>
        </item>
 
        <item
            android:id="@+id/fsvGrid"
            android:icon="@drawable/ic_grid_on_24px"
            android:title="@string/grid"
            app:showAsAction="ifRoom">
                <menu>
                        <group android:id="@+id/gridMenu" android:checkableBehavior="single">
                                <item
                                    android:id="@+id/gridOne"
                                    android:title="1"/>
 
                                <item
                                    android:id="@+id/gridTwo"
                                    android:title="2"/>
 
                                <item
                                    android:id="@+id/gridThree"
                                    android:title="3"/>
 
                                <item
                                    android:id="@+id/gridFour"
                                    android:title="4"/>
                        </group>
                </menu>
        </item>
</menu>

I found a solution thanks to some external help. Its possible to work on the Toolbars item in an easier way.

In the onViewCreated method, we must add:

    topToolbar.inflateMenu(R.menu.menu_toolbar)

    topToolbar.setOnMenuItemClickListener {
            when(it.itemId) {
                R.id.fsvSearch -> //your code
            }
            true
        }

Also, if the menu gets duplicated, remove the app:menu tag in the Toolbars xml

thanks Meltix for this, I've done a lot of research but most of the posts in SO are about Java and old fashioned ActionBar. There is not much info about material ToolBar and kotlin examples. In my case I'm working on an old app developed mostly in Java but now developing new functionalities in Kotlin. In my fragment, I wasn't able to change the ActionBar's icons and behaviour (I wanted a particular ActionBar for my fragment). The solution I found is to hide the ActionBar and create a Toolbar inflating a custom menu inside. Also I added a back arrow button (thanks to John: here ). I've came to the conclusion (maybe I'm wrong) that you can't manage ActionBars from kotlin fragments, that's why you have to use toolbars. Here is my code in case it can help someone.

MyFragment.kt

override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
    // hide the old actionBar
    (activity as AppCompatActivity).supportActionBar!!.hide()
    
    // create the toolbar
    val toolbar = binding?.myToolbar
    
    // add the back arrow button, see function below
    val resId = getResIdFromAttribute(toolbar.context, android.R.attr.homeAsUpIndicator)
    toolbar.navigationIcon = ContextCompat.getDrawable(toolbar.context, resId)
    // tapping on the arrow will pop the current fragment
    toolbar.setNavigationOnClickListener { parentFragmentManager?.popBackStackImmediate() }

    // change toolbar title
    toolbar.title = "Some title"
    
    // inflate a custom menu, see code below
    toolbar.inflateMenu(R.menu.my_custom_menu)
    toolbar.setOnMenuItemClickListener {
        when (it.itemId) {
            R.id.infoButton -> someAction()
        }
        true
    }
}

// get back arrow icon
@AnyRes
fun getResIdFromAttribute(context: Context, @AttrRes attr: Int): Int {
    if (attr == 0) return 0
    val typedValueAttr = TypedValue()
    context.theme.resolveAttribute(attr, typedValueAttr, true)
    return typedValueAttr.resourceId
}

my_fragment.xml

...
<androidx.appcompat.widget.Toolbar
    android:id="@+id/myToolBar"
    android:layout_height="match_parent"
    android:layout_width="match_parent"
    android:visibility="visible"
    app:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar"
    android:background="@color/azulOscuro"
    >
</androidx.appcompat.widget.Toolbar>

my_custom_menu.xml

<?xml version="1.0" encoding="utf-8"?>
    <menu xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:jsmovil="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools">
    <item
        android:id="@+id/infoButton"
        android:icon="@drawable/ic_info_blanco"
        android:title="@string/tutorial"
        android:textColor="@color/blanco"
        jsmovil:showAsAction="always"
        />
</menu>

Result

在此处输入图像描述

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM