Show menu actions only in certain fragments - NavigationComponents - android

I have a navigation host activity that inflates 2 fragments, one the main host fragment and the event fragments, I need to show in the event fragment a menu action , but this menu action is also shown in the main fragment which I dont want to show
How do I show this menu only in the event fragment ?
MainActivity
class MainActivity: AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
val navController = Navigation.findNavController(this, R.id.nav_host_fragment)
setupActionBar(navController)
}
private fun setupActionBar(navController: NavController) {
NavigationUI.setupActionBarWithNavController(this, navController)
}
override fun onSupportNavigateUp(): Boolean {
return Navigation.findNavController(this, R.id.nav_host_fragment).navigateUp()
|| super.onSupportNavigateUp()
}
override fun onCreateOptionsMenu(menu: Menu?): Boolean {
MenuInflater(this).inflate(R.menu.menu, menu)
return super.onCreateOptionsMenu(menu)
}
override fun onOptionsItemSelected(item: MenuItem?): Boolean {
NavigationUI.onNavDestinationSelected(item!!, Navigation.findNavController(this, R.id.nav_host_fragment))
return super.onOptionsItemSelected(item)
}
Menu
<menu xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto">
<item
android:id="#+id/eventsFragment"
app:showAsAction="ifRoom|always"
android:title="¿ Where to buy ?" />
</menu>
I need to show this menu only in the eventsFragment
EventFragment
class EventsFragment : Fragment() {
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
// Inflate the layout for this fragment
return inflater.inflate(R.layout.fragment_event, container, false)
}
But instead of just showing it just in the EventFragment it also shows it in the first fragment that MainActivity as hosts inflates
How can I just have this menu in my EventsFragment?

In MainActivity menuItem setVisible(false):
override fun onCreateOptionsMenu(menu: Menu?): Boolean {
MenuInflater(this).inflate(R.menu.menu, menu)
val menuItem : MenuItem = menu.findItem(R.id.eventsFragment);
if (menuItem!= null)
menuItem.setVisible(false);
return super.onCreateOptionsMenu(menu)
}
In EventsFragment setvisibility of menuitem to true as shown below:
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setHasOptionsMenu(true)
}
override fun onPrepareOptionsMenu(menu: Menu) {
val menuItem = menu.findItem(R.id.eventsFragment)
if (menuItem != null)
menuItem.isVisible = true
}

You could try considering Inflating the menu from inside the fragment. ie. fragments onCreate() method and destroying it from onDestroy() function of the fragment

Related

I can't work MenuProvider in Fragment for menu

class FirstFragment : Fragment(), MenuProvider {
...
override fun onCreateMenu(menu: Menu, menuInflater: MenuInflater) {
//not called
menuInflater.inflate(R.menu.menu_, menu)
}
override fun onMenuItemSelected(menuItem: MenuItem): Boolean {
return true
}
}
<com.google.android.material.navigation.NavigationView
android:id="#+id/nv"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_gravity="start"
app:menu="#menu/menu_"/>
I'm trying to add a menu to the fragment (not the action bar), even if I add it in XML,
I can't access it in the code. I tried many ways on the internet, I added menuhost to oncreate,
I updated the version of the modules, but it didn't work, what do I need to know?
I also tried this code,i don't get error but function is not called
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
val menuHost: MenuHost = requireActivity() as MenuHost
menuHost.addMenuProvider(object : MenuProvider {
override fun onCreateMenu(menu: Menu, menuInflater: MenuInflater) {
//not called
menuInflater.inflate(R.menu.menu_, menu)
}
override fun onMenuItemSelected(menuItem: MenuItem): Boolean {
}
}, viewLifecycleOwner, Lifecycle.State.RESUMED)
I solved I saw this code to video:
activity?.addMenuProvider(this)
I added in OnViewCreaded, it's worked

Back arrow won't trigger onOptionsItemSelected

I want add confirmation dialog before my fragment close. I have added the onOptionsItemSelected function in my fragment. however when i click the back arrow button the function is not executed. Here's my code
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
(activity as AppCompatActivity).supportActionBar?.show()
(activity as AppCompatActivity).supportActionBar?.setDisplayHomeAsUpEnabled(true)
(activity as AppCompatActivity).supportActionBar?.setDisplayShowHomeEnabled(true)
setHasOptionsMenu(true)
}
override fun onCreateOptionsMenu(menu: Menu, inflater: MenuInflater) {
inflater.inflate(R.menu.menu_input, menu)
return super.onCreateOptionsMenu(menu, inflater)
}
override fun onOptionsItemSelected(item: MenuItem): Boolean {
when (item.itemId) {
android.R.id.home -> "testing".debugTag("Debug")
}
return super.onOptionsItemSelected(item)
}
Try to set the action bar in onCreate.
setSupportActionBar( yourActionBar );

Android kotlin show Navigation Drawer icon instead of Back Button in some fragment

I want to show navigation drawer icon instead of Back button on a certain fragment. I created the App with Navigation graph.
Let's say i have 2 fragments (LoginFragment and DashboardFragment) and one activity (MainActivity)
MainActivity.kt
class MainActivity : AppCompatActivity() {
lateinit var drawerLayout: DrawerLayout
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
val binding = DataBindingUtil.setContentView<ActivityMainBinding>(this, R.layout.activity_main)
drawerLayout = binding.drawerLayout
val navController = this.findNavController(R.id.myNavHostFragment)
// prevent nav gesture if not on start destination
navController.addOnDestinationChangedListener { nc: NavController, nd: NavDestination, args: Bundle? ->
if (nd.id == nc.graph.startDestination) {
drawerLayout.setDrawerLockMode(DrawerLayout.LOCK_MODE_UNLOCKED)
} else {
drawerLayout.setDrawerLockMode(DrawerLayout.LOCK_MODE_LOCKED_CLOSED)
}
}
NavigationUI.setupActionBarWithNavController(this, navController, drawerLayout)
NavigationUI.setupWithNavController(binding.navView, navController)
}
// Set up the back button on action bar
override fun onSupportNavigateUp(): Boolean {
val navController = this.findNavController(R.id.myNavHostFragment)
return NavigationUI.navigateUp(navController, drawerLayout)
}
}
LoginFragment.kt
class LoginFragment : Fragment() {
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
val binding:FragmentLoginBinding = DataBindingUtil.inflate(inflater,
R.layout.fragment_login, container, false)
// Hide the Action bar
(activity as AppCompatActivity).supportActionBar?.hide()
binding.loginButton.setOnClickListener {
//Some unimportant validation
}
return binding.root
}
}
DashboardFragment.kt
class DashboardFragment : Fragment() {
lateinit var binding : FragmentDashboardBinding
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
// Binding object for this fragment and the layout
binding = DataBindingUtil.inflate(inflater,
R.layout.fragment_dashboard, container, false)
//Navigate to Product stock fragment when clicked
binding.productStockButton.setOnClickListener(Navigation.createNavigateOnClickListener(
R.id.action_dashboardFragment_to_productStockOutletList
))
//Navigate to Switching History fragment when clicked
binding.switchingHistoryButton.setOnClickListener(Navigation.createNavigateOnClickListener(
R.id.action_dashboardFragment_to_switchingHistoryFragment
))
//Navigate to Outlet List fragment for Outstanding Product when clicked
binding.outstandingOrderButton.setOnClickListener(Navigation.createNavigateOnClickListener(
R.id.action_dashboardFragment_to_outletListFragment
))
// Set action bar title to "Main Dashboard"
(activity as AppCompatActivity).supportActionBar?.title = "Main Dashboard"
// Declare that this fragment has menu
setHasOptionsMenu(true)
(activity as AppCompatActivity).supportActionBar?.show()
(activity as AppCompatActivity).supportActionBar?.setDisplayHomeAsUpEnabled(false)
//Return.... i don't know.
return binding.root
}
override fun onCreateOptionsMenu(menu: Menu, inflater: MenuInflater) {
super.onCreateOptionsMenu(menu, inflater)
inflater?.inflate(R.menu.nav_overflow_menu, menu)
}
}
And this is my Navigation graph (I set up LoginFragment as home)
I want to show the navigation drawer in the DashboardFragment instead of LoginFragment. (With LoginFragment still be the start of the graph). I already hide the Up button of the DashboardFragment
This is the current look of the dashboard. As you can see that the back button is already gone.
Is there anything i can do with it ? If there is something unclear let me know.
try this I hope that it will help you, this will hide actionBar on LoginFragment as it's the startDestination on graph and show it otherwise
class MainActivity : AppCompatActivity() {
private lateinit var appBarConfiguration: AppBarConfiguration
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
val toolbar: Toolbar = findViewById(R.id.toolbar)
setSupportActionBar(toolbar)
val drawerLayout: DrawerLayout = findViewById(R.id.drawer_layout)
val navView: NavigationView = findViewById(R.id.nav_view)
val navController = findNavController(R.id.nav_host_fragment)
// prevent nav gesture if not on start destination
navController.addOnDestinationChangedListener { nc: NavController, nd: NavDestination, args: Bundle? ->
if (nd.id == nc.graph.startDestination) {
drawerLayout.setDrawerLockMode(DrawerLayout.LOCK_MODE_LOCKED_CLOSED)
supportActionBar?.hide()
} else {
supportActionBar?.show()
drawerLayout.setDrawerLockMode(DrawerLayout.LOCK_MODE_UNLOCKED)
}
}
// here this ids are form fragment which should show navigation icon
appBarConfiguration = AppBarConfiguration(setOf(
R.id.nav_home,R.id.nav_gallery, R.id.nav_slideshow), drawerLayout)
setupActionBarWithNavController(navController, appBarConfiguration)
navView.setupWithNavController(navController)
}
override fun onCreateOptionsMenu(menu: Menu): Boolean {
// Inflate the menu; this adds items to the action bar if it is present.
menuInflater.inflate(R.menu.main, menu)
return true
}
override fun onSupportNavigateUp(): Boolean {
val navController = findNavController(R.id.nav_host_fragment)
return navController.navigateUp(appBarConfiguration) || super.onSupportNavigateUp()
}
}

Add functioning SearchView to one specific Fragment

I got a fragment where I want to add a SearchView. I got it already in the Menu, its clickable and everything, but every guide I find to actually search something is either out of date or not exactly what I need.
This is my fragment
class ViewFragment : Fragment () {
override fun onCreateView(inflater: LayoutInflater,container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
val binding: ViewFragmentBinding = DataBindingUtil.inflate(
inflater, R.layout.view_fragment, container, false)
val application = requireNotNull(this.activity).application
setHasOptionsMenu(true)
binding.setLifecycleOwner(this)
viewFragmentViewModel.navigateToEdit.observe(this, Observer {translation ->
translation?.let {
this.findNavController().navigate(
ViewFragmentDirections
.actionViewFragmentToEditFragment(translation)
)
viewFragmentViewModel.onEditNavigated()
}
})
val adapter = TranslationAdapter(TranslationListener { translationID ->
viewFragmentViewModel.onTranslationClicked(translationID)
})
binding.translationList.adapter = adapter
viewFragmentViewModel.translations.observe(viewLifecycleOwner, Observer {
it?.let {
adapter.submitList(it)
}
})
return binding.root
}
override fun onCreateOptionsMenu(menu: Menu, inflater: MenuInflater){
inflater.inflate(R.menu.search_menu, menu)
super.onCreateOptionsMenu(menu, inflater)
}
And this is my menu with the search
<menu 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">
<item
android:id="#+id/action_search"
android:icon="#android:drawable/ic_menu_search"
app:showAsAction="always|collapseActionView"
app:actionViewClass="android.widget.SearchView"
android:title="Search"/>
</menu>
Can anyone tell me how I can get set everything up so I can access the search string the user has entered and submit a new list to the RecycleView? Or just point me in the right direction!
Thank you in advance!
EDIT: Heres The update. I have an MutableLiveData Where i put the query and observe it so I can act on its observe function. I got a variable translationList in the ViewModel that I wanted to update.
class ViewFragment : Fragment (), SearchView.OnQueryTextListener {
private var searchText = MutableLiveData<String>()
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
...
val adapter = TranslationAdapter(TranslationListener { translationID ->
viewFragmentViewModel.onTranslationClicked(translationID)
})
binding.translationList.adapter = adapter
viewFragmentViewModel.translations.observe(viewLifecycleOwner, Observer {
it?.let {
adapter.submitList(it)
}
})
searchText.observe(this, Observer {searchString ->
searchString?.let {
if(searchString == ""){
adapter.submitList(viewFragmentViewModel.translations.value)
}
else{
adapter.submitList(viewFragmentViewModel.searchTranslations(searchString))
}
}
})
}
override fun onCreateOptionsMenu(menu: Menu, inflater: MenuInflater){
inflater.inflate(R.menu.search_menu, menu)
val menuItem = menu.findItem(R.id.action_search)
val searchView = menuItem.actionView as SearchView
searchView.setOnQueryTextListener(this)
super.onCreateOptionsMenu(menu, inflater)
}
override fun onQueryTextChange(newText: String?): Boolean {
searchText.value = newText
return true
}
override fun onQueryTextSubmit(query: String?): Boolean {
return false
}
}
For the closure, since I already had an list with all my objects from the database I wanted to search in, its easier to just go through that list with a filter.
Step - 1: Implements SearchView.OnQueryTextListener in your ViewFragment
class ViewFragment : Fragment(), SearchView.OnQueryTextListener {
...
override fun onQueryTextSubmit(query: String?): Boolean {
return false
}
override fun onQueryTextChange(newText: String?): Boolean {
//Do your operation here
return true
}
}
Step - 2: Get SearchView from menu and initialize with listener
override fun onCreateOptionsMenu(menu: Menu, inflater: MenuInflater) {
inflater.inflate(R.menu.search_menu, menu)
val meniItem = menu?.findItem(R.id.action_search)
val searchView = meniItem?.actionView as SearchView?
searchView?.setOnQueryTextListener(this)
super.onCreateOptionsMenu(menu, inflater)
}
Step - 3: Inside onQueryTextChange take your search query and do operation
Update: Change your implementation like below:
fun searchTranslations(searchString: String) : List<Translation>? {
return database.getTranslationsBySearch(searchString).value
}
And Dao
#Query("SELECT * FROM word_translation_table WHERE word_ger LIKE '% :string %' OR word_es LIKE '% :string %' ")
fun getTranslationsBySearch(string: String): LiveData<List<Translation>>

setSupportActionBar inside of a Fragment

I have a Fragment:
class HomeFragment : Fragment() { ... }
Now I'm trying to add an Actionbar to it, but this doesn't work:
setSupportActionBar(findViewById(R.id.toolbar_main))
How can I set the Support and then add Items to the ActionBar?
This is how it works in an AppCompatActivity:
// This adds items to the ActionBar
override fun onCreateOptionsMenu(menu: Menu): Boolean {
menuInflater.inflate(R.menu.menu_toolbar_main, menu)
return true
}
// This is the OnClickListener for the Buttons in the ActionBar
override fun onOptionsItemSelected(item: MenuItem) = when (item.itemId) {
R.id.toolbar_edit -> {
true
}
R.id.toolbar_search -> {
true
}
else -> {
// If we got here, the user's action was not recognized.
// Invoke the superclass to handle it.
super.onOptionsItemSelected(item)
}
}
Big thanks in advance!
Override onCreateOptionsMenu in your Fragment and inflate your menu inside. Than in onCreate method of Fragment set setHasOptionsMenu() to true. To inflate different menus depending on Fragment creation clear the menu first.
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setHasOptionsMenu(true)
}
override fun onCreateOptionsMenu(menu: Menu?, inflater: MenuInflater?) {
super.onCreateOptionsMenu(menu, inflater)
inflater?.inflate(Your menu here, menu)
}

Categories

Resources