现在如何在 Fragment 中创建选项菜单(setHasOptionMenu 已弃用)

问题描述 投票:0回答:2

当尝试像往常一样在 onCreate 和

setHasOptionsMenu(true)
中写入
override fun onCreateOptionsMenu
时,Android Studio 会划掉这些函数,表示它们已被弃用。

我看了他们的建议

https://developer.android.com/jetpack/androidx/releases/activity?authuser=5#1.4.0-alpha01

事实证明,他们要求在 Activity (MainActivity.kt) 中插入一些新函数,在 Fragment (DogListFragment.kt) 中插入一些新函数。但在我的应用程序中,所有菜单自定义仅在 Fragment 中完成,因此 Activity 无法做到这一点。 Activity 根本无法访问 RecyclerView,它位于属于 Fragment 的布局 (fragment_god_list.xml) 中。 Activity 的 Activity_main.xml 中只有

androidx.fragment.app.FragmentContainerView

有谁知道如何在 Fragment 中完成此操作,而无需对 Activity 中的菜单进行任何操作?

GitHub 项目:https://github.com/theMagusDev/DogglersApp

MainActivity.kt:

package com.example.dogglers

import android.os.Bundle
import androidx.appcompat.app.AppCompatActivity
import androidx.navigation.NavController
import androidx.navigation.fragment.NavHostFragment
import androidx.navigation.ui.setupActionBarWithNavController
import com.example.dogglers.databinding.ActivityMainBinding

private lateinit var navController: NavController

class MainActivity : AppCompatActivity() {

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

        // Setup view binding
        val binding = ActivityMainBinding.inflate(layoutInflater)
        setContentView(binding.root)

        // Setup navController
        val navHostFragment = supportFragmentManager
            .findFragmentById(R.id.nav_host_fragment) as NavHostFragment
        navController = navHostFragment.navController

        setupActionBarWithNavController(navController)
    }

    override fun onSupportNavigateUp(): Boolean {
        return navController.navigateUp() || super.onSupportNavigateUp()
    }
}

DogListFragment.kt:

package com.example.dogglers

import android.os.Bundle
import android.view.*
import androidx.core.content.ContextCompat
import androidx.fragment.app.Fragment
import androidx.recyclerview.widget.GridLayoutManager
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
import com.example.dogglers.adapter.DogCardAdapter
import com.example.dogglers.const.Layout
import com.example.dogglers.databinding.FragmentDogListBinding

class DogListFragment : Fragment() {
    private var _binding: FragmentDogListBinding? = null

    // This property is only valid between onCreateView and
    // onDestroyView.
    private val binding get() = _binding!!

    private lateinit var recyclerView: RecyclerView
    private var layoutType = Layout.VERTICAL

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

    override fun onCreateView(
        inflater: LayoutInflater,
        container: ViewGroup?,
        savedInstanceState: Bundle?
    ): View? {
        _binding = FragmentDogListBinding.inflate(inflater, container, false)
        return binding.root
    }

    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        recyclerView = binding.verticalRecyclerView
        setUpAdapter()
    }

    override fun onDestroyView() {
        super.onDestroyView()
        _binding = null
    }

    override fun onCreateOptionsMenu(menu: Menu, inflater: MenuInflater) {
        inflater.inflate(R.menu.layout_manu, menu)

        val layoutButton = menu.findItem(R.id.action_switch_layout)

        // Calls code to set the icon
        setIcon(layoutButton)
    }

    override fun onOptionsItemSelected(item: MenuItem): Boolean {
        when (item.itemId) {
            R.id.action_switch_layout -> {
                layoutType = when (layoutType) {
                    Layout.VERTICAL -> Layout.HORIZONTAL
                    Layout.HORIZONTAL -> Layout.GRID
                    else -> Layout.VERTICAL
                }
                setUpAdapter()

                return true
            }
            //  Otherwise, do nothing and use the core event handling

            // when clauses require that all possible paths be accounted for explicitly,
            //  for instance both the true and false cases if the value is a Boolean,
            //  or an else to catch all unhandled cases.

            else -> return super.onOptionsItemSelected(item)
        }
    }

    fun setUpAdapter() {
        recyclerView.adapter = when(layoutType){
            Layout.VERTICAL -> {
                recyclerView.layoutManager = LinearLayoutManager(context, RecyclerView.VERTICAL, false)
                DogCardAdapter(
                    context,
                    Layout.VERTICAL
                )
            }
            Layout.HORIZONTAL -> {
                recyclerView.layoutManager = LinearLayoutManager(context, RecyclerView.HORIZONTAL, false)
                DogCardAdapter(
                    context,
                    Layout.HORIZONTAL
                )
            }
            else -> {
                recyclerView.layoutManager = GridLayoutManager(context, 2, RecyclerView.VERTICAL, false)
                DogCardAdapter(
                    context,
                    Layout.GRID
                )
            }
        }
    }

    private fun setIcon(menuItem: MenuItem?) {
        if (menuItem == null)
            return
        menuItem.icon = when(layoutType) {
            Layout.VERTICAL -> ContextCompat.getDrawable(this.requireContext(), R.drawable.ic_vertical_layout)
            Layout.HORIZONTAL -> ContextCompat.getDrawable(this.requireContext(), R.drawable.ic_horizontal_layout)
            else -> ContextCompat.getDrawable(this.requireContext(), R.drawable.ic_grid_layout)
        }
    }
}

ActivityMain.xml:

<?xml version="1.0" encoding="utf-8"?>

<FrameLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity">

    <androidx.fragment.app.FragmentContainerView
        android:id="@+id/nav_host_fragment"
        android:name="androidx.navigation.fragment.NavHostFragment"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        app:defaultNavHost="true"
        app:navGraph="@navigation/nav_graph"/>

</FrameLayout>

FragmentDogList:

<?xml version="1.0" encoding="utf-8"?>

<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity">

    <androidx.recyclerview.widget.RecyclerView
        android:id="@+id/vertical_recycler_view"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:scrollbars="vertical"
        android:orientation="vertical"
        app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager"
        tools:listitem="@layout/vertical_list_item"/>

</FrameLayout>
android kotlin android-fragments android-menu
2个回答
1
投票

当您调用 setUpActionBarWithNavController() 方法时,您正在活动内设置工具栏。您的片段位于此活动内。你的片段也有这个actionBar。要在片段内使用菜单提供程序,您需要在片段的 onViewCreated() 方法内调用以下方法。

requireActivity().addMenuProvider(this, viewLifecycleOwner, Lifecycle.State.RESUMED)

此外,您需要使您的片段实现 MenuProvider 接口

class DogListFragment : Fragment(),MenuProvider {...

IDE 会要求您实现其提供者方法,即 onCreateMenu 和 onMenuItemSelected 在 OnCreateMenu 内部,使用 menu Inflator 来膨胀菜单布局 示例:-

 menuInflater.inflate(R.menu.search_menu,menu)

0
投票

没有人为我工作过。 只有以下过程有效。我认为这个原因是我从 xml 文件实现了菜单

  1. 在xml中添加了这部分

  2. 来自 CreatedView 上的片段

     binding.materialToolbar.addMenuProvider(
         object : MenuProvider{
             override fun onCreateMenu(menu: Menu, menuInflater: MenuInflater) {
                 ///No need to implement. Al
             }
    
             override fun onMenuItemSelected(menuItem: MenuItem): Boolean {
    
                 return when (menuItem.itemId) {
                     R.id.btn_booster -> {
                         startBoosterActivity()
                         true
                     }
    
                     R.id.btn_premium -> {
                         startActivity(PremiumActivity::class.java)
                         true
                     }
    
                     R.id.btn_search -> {
                         startActivity(SearchActivity::class.java)
                         true
                     }
    
                     else -> false
                 }
             }
                              }, viewLifecycleOwner, Lifecycle.State.RESUMED
     )
    
© www.soinside.com 2019 - 2024. All rights reserved.