onItemSelectedListener for bottomnavigationbar - android

I am new to android and Kotlin, developing a bottom navigation bar using onitemselectedListener, since setOnNavigationItemSelectedListener is deprecated and I couldn't find any youtube tutorial that explains how to used onitemselectedlistener for navigationbar. navigation shows up on the emulator, but fragments are not showing up when i click on navigation Icons. here are my codes.
adding image of activity_main and emulator error image
fragmentWord image, that is connected to the first icon of "A" but doesn't show up
MainActivity
import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import androidx.fragment.app.Fragment
import com.aryanvedh.vocabapp2.databinding.ActivityMainBinding
class MainActivity : AppCompatActivity() {
private lateinit var binding: ActivityMainBinding
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binding = ActivityMainBinding.inflate(layoutInflater)
setContentView(binding.root)
val wordFragment = WordFragment()
val memorisedFragment = MemorisedFragment()
setCurrentFragment(wordFragment)
binding.bottomNavigationView.setOnItemSelectedListener { item ->
when (item.itemId) {
R.id.words -> setCurrentFragment(wordFragment)
R.id.memorised -> setCurrentFragment(memorisedFragment)
}
true
}
}
private fun setCurrentFragment(fragment: Fragment) =
supportFragmentManager.beginTransaction().apply {
replace(R.id.flFragment, fragment)
commit()
}
}```
any help? thanks

Use the function like this:
val navBar = findViewById<NavigationBarView>(R.id.navBar)
navBar.setOnItemSelectedListener {
when(it.itemId) {
R.id.item01 -> {
setCurrentFragment(Fragment01())
true
}
R.id.item02 -> {
setCurrentFragment(Fragment02())
true
}
R.id.item03 -> {
setCurrentFragment(Fragment03())
true
}
else -> {
false
}
}
}
It now should raise the fragments when each navigation bar item is selected.

You need to use the OnNavigationItemSelectedListener Method to capture once the item is selected in Bottom Navigation.
Here is the sample code attached from Documentation.
BottomNavigationView.OnNavigationItemSelectedListener { item ->
when(item.itemId) {
R.id.item1 -> {
// Respond to navigation item 1 click
true
}
R.id.item2 -> {
// Respond to navigation item 2 click
true
}
else -> false
}
}
Please refer to the Official Documentation for more information about BottomNavigationView.

Related

Displaying item after clicking back bottom navigation view

When I press the back button, it opens the previous fragment. But in the bottom navigation, another tab remains highlighted.
How do I make the tab on the bottom navigation change when the fragment changes too?
private lateinit var mainBottomBar: BottomNavigationView
private val navigationBottomViewListener = NavigationBarView.OnItemSelectedListener {
val fragment = when (it.itemId) {
R.id.homeMenu -> HomeFragment()
R.id.pomodoroMenu -> PomodoroFragment()
R.id.statisticsMenu -> StatisticsFragment()
else -> return#OnItemSelectedListener false
}
replaceFragmentWithAddBackStack(fragment)
return#OnItemSelectedListener true
}
private fun replaceFragmentWithAddBackStack(fragment: Fragment) {
supportFragmentManager.beginTransaction().addToBackStack(null).replace(R.id.mainContainer, fragment).commit()
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
mainBottomBar = findViewById(R.id.mainBottomBar)
mainBottomBar.setOnItemSelectedListener(navigationBottomViewListener)
}

how to put 2 different Fragments in a BottomNavigationView?

I try to put a BottomNavigationView like this in my main Activity, and I have a recycler view too :
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
loadFragment(HomeFragment(this))
//import the bottomNavigationView
val navigationView = findViewById<BottomNavigationView>(R.id.barre_nav)
navigationView.setOnNavigationItemSelectedListener {
when(it.itemId) {
R.id.nav_home -> {
loadFragment(HomeFragment(this))
return#setOnNavigationItemSelectedListener true
}
R.id.nav_choose -> {
loadFragment(ChooserFragment(ChooserActivity()))
return#setOnNavigationItemSelectedListener true
}
else -> false
}
}
}
private fun loadFragment(fragment: Fragment) {
val transactionMuscle = supportFragmentManager.beginTransaction()
transactionMuscle.replace(R.id.fragment_container, fragment)
transactionMuscle.addToBackStack(null)
transactionMuscle.commit()
}
But my problem with this code which is fine if I would to put the two view in the same container, but I wouldn't, is : I have a ChooserActivity and I would the second part of my bottomNavigationView to redirect to this page, and not the MainActivity Fragment with the Chooser composant. I would do the same as it do for the main Activity but with the ChooserActivity.
I doesn't know if I am clear, but I Thank you in advance.
EDIT to clarify :
My aim is to with mybottomNavigationView, when we click on the first button, it redirect to the MainActivity, and when we click on the second button, it redirect to the ChooserActivity. Th two must have there own containers. Hopefully it is better...
Solution
try this code:
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
val bottomNavigation: BottomNavigationView = findViewById(R.id.barre_nav)
bottomNavigation.setOnNavigationItemSelectedListener(mOnNavigationItemSelectedListener)
} //onCreate() end here
private val mOnNavigationItemSelectedListener = BottomNavigationView.OnNavigationItemSelectedListener { item ->
when (item.itemId) {
R.id.nav_home -> {
val homeFragment = HomeFragment.newInstance()
loadFragment(homeFragment)
return#OnNavigationItemSelectedListener true
}
R.id.nav_choose -> {
val chooserFragment = ChooserFragment.newInstance()
loadFragment(chooserFragment)
return#OnNavigationItemSelectedListener true
}
}
false
}
private fun loadFragment(fragment: Fragment) {
val transactionMuscle = supportFragmentManager.beginTransaction()
transactionMuscle.replace(R.id.fragment_container, fragment)
transactionMuscle.addToBackStack(null)
transactionMuscle.commit()
}
In You Fragments OnCreateView() Method add these lines too :
1.HomeFragment
companion object {
fun newInstance(): HomeFragment = HomeFragment()
}
2.ChooserFragment
companion object {
fun newInstance(): ChooserFragment= ChooserFragment()
}
Hope so it works :)
If you still face any issue , please add it into comments

Hide android bottom navigation view for child screens/ fragments

I'm trying to create a single activity Android application.
I have MainActivity (only activity) with BottomNavigationView, three top level fragments and some child fragments. My requirement is whenever the screen is showing top level fragments, bottom navigation should be visible such that switching is possible. But when I'm viewing any of the child fragments, bottom navigation should be hidden.
Is there any out-of-box way using the Navigation component or need to change the visibility manually ?
Update (Navigation component 1.0)
As of Navigation component 1.0.0-alpha08, method addOnNavigatedListener(controller: NavController, destination: NavDestination) was changed to addOnDestinationChangedListener(controller: NavController, destination: NavDestination, arguments: Bundle). Its behavior was also slightly changed (it is also called if the destinations arguments change).
Old Answer
You can use NavController.OnNavigatedListener to achieve this behavior (set it in Activity onCreate):
findNavController(R.id.container).addOnNavigatedListener { _, destination ->
when (destination.id) {
R.id.dashboardFragment -> showBottomNavigation()
else -> hideBottomNavigation()
}
}
private fun hideBottomNavigation() {
// bottom_navigation is BottomNavigationView
with(bottom_navigation) {
if (visibility == View.VISIBLE && alpha == 1f) {
animate()
.alpha(0f)
.withEndAction { visibility = View.GONE }
.duration = EXIT_DURATION
}
}
}
private fun showBottomNavigation() {
// bottom_navigation is BottomNavigationView
with(bottom_navigation) {
visibility = View.VISIBLE
animate()
.alpha(1f)
.duration = ENTER_DURATION
}
}
Using addOnDestinationChangedListener works, and it's the solution recommended in the official documentation, but it does cause some flickering, as the callback is executed before the fragment is attached.
I find the below answer more flexible, and handles animations better:
supportFragmentManager.registerFragmentLifecycleCallbacks(object : FragmentManager.FragmentLifecycleCallbacks() {
override fun onFragmentViewCreated(fm: FragmentManager, f: Fragment, v: View, savedInstanceState: Bundle?) {
TransitionManager.beginDelayedTransition(binding.root, Slide(Gravity.BOTTOM).excludeTarget(R.id.nav_host_fragment, true))
when (f) {
is ModalFragment -> {
binding.bottomNavigation.visibility = View.GONE
}
else -> {
binding.bottomNavigation.visibility = View.VISIBLE
}
}
}
}, true)
You can customize it depending on the transitions between your fragments, by choosing different animation (on my example it's a Slide), or by making the call at another lifecycle callback.
You have to make a method in MainActivity for visibility. Do call that method from fragments where you want to show or hide.
One thing I faced with such scenario is, bottom navigation visibility is not being properly gone. So I put bottom navigation view in Relative layout and hide that parent view.
you just need to write this code in MainActivity
class MainActivity : AppCompatActivity() {
private lateinit var navController: NavController
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
//Getting the Navigation Controller
navController = Navigation.findNavController(this, R.id.fragment)
//Setting the navigation controller to Bottom Nav
bottomNav.setupWithNavController(navController)
//Setting up the action bar
NavigationUI.setupActionBarWithNavController(this, navController)
//setting the Bottom navigation visibiliy
navController.addOnDestinationChangedListener { _, destination, _ ->
if(destination.id == R.id.full_screen_destination ){
bottomNav.visibility = View.GONE
}else{
bottomNav.visibility = View.VISIBLE
}
}
}
get more details from the android developer documentation:
Update UI components with NavigationUI
So even tho this question was already answered and the accepted answer is one that works, here is the code to actually achieve this behaviour:
MainActivity
fun hideBottomNav() {
bottomNavigationView.visibility = View.GONE
}
fun showBottomNav() {
bottomNavigationView.visibility = View.VISIBLE
}
Then you call the functions in your fragment onViewCreated(), onDetach() function, like:
Fragment
class FragmentWithOutBottomNav() : Fragment() {
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
(activity as MainActivity).hideBottomNav()
}
override fun onDetach() {
super.onDetach()
(activity as MainActivity).showBottomNav()
}
}
Hope I could help some people. Happy coding!
navController.addOnDestinationChangedListener { _, destination, _ ->
val isMainPage = bottomNavigationView.selectedItemId == destination.id
bottomNavigationView.isVisible = isMainPage
}

Android Kotlin Bottom navigation bar

I use bottom navigation bar (xx_activity bottom by default) but I have problems.
When I click on the item it's OK, the activity is good but the item of the activity not change...
import android.content.Intent
import android.os.Bundle
import android.support.design.widget.BottomNavigationView
import android.support.v7.app.AppCompatActivity
import kotlinx.android.synthetic.main.activity_grammaire.*
class GrammaireActivity : AppCompatActivity() {
private val mOnNavigationItemSelectedListener=BottomNavigationView.OnNavigationItemSelectedListener { item ->
when (item.itemId) {
R.id.navigation_grammaire -> {
val intent = Intent(this,GrammaireActivity::class.java)
startActivity(intent)
return#OnNavigationItemSelectedListener true
}
R.id.navigation_situations -> {
val intent = Intent(this,SituationsActivity::class.java)
startActivity(intent)
return#OnNavigationItemSelectedListener true
}
R.id.navigation_lexiquefrsa -> {
val intent = Intent(this,LexiqueFrSaActivity::class.java)
startActivity(intent)
return#OnNavigationItemSelectedListener true
}
R.id.navigation_lexiquesafr -> {
val intent = Intent(this,LexiqueSaFrActivity::class.java)
startActivity(intent)
return#OnNavigationItemSelectedListener true
}
R.id.navigation_infos -> {
val intent = Intent(this,InfosActivity::class.java)
startActivity(intent)
return#OnNavigationItemSelectedListener true
}
}
false
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_grammaire)
navigation.setOnNavigationItemSelectedListener(mOnNavigationItemSelectedListener)
}
}
I believe it's recommended to use Fragments with bottom navigation, rather than Activities.
With the onClick you would swap out the current Fragment with the one identified by the click.
I am not sure about "item of the activity not change" but i think you mean to say that the content of your current Activity doesn't change.
So for that you should replace Fragments in an Activity on the click of the BottomNavigation item. This is how it should be done
when (item.itemId) {
R.id.navigation_grammaire -> {
supportFragmentManager.beginTransaction.replace(R.id.container, FragmnetGrammaire().commit())
}
where "container" is the id of the view above your BottomNavigation bar. It can be FrameLayout.
FragmnetGrammaire(), is the instance of your Fragment.

How to load fragment on BottomNavigationView depending on selected item?

I have a simple application written in Kotlin that has a BottomNavigationView. The idea is to have a single activity (MainActivity) with a fragment to be loaded for each tab on the BottomNavigationView.
I have already created a fragment I would like to load when a tab is selected (HomeFragment) and am already changing the text under the icons on the BottomNavigationView when the active tab changes.
Now I would like to inflate / load the fragment when I change tabs. How would I go about doing this?
MainActivity.kt:
class MainActivity : AppCompatActivity() {
private val mOnNavigationItemSelectedListener = BottomNavigationView.OnNavigationItemSelectedListener { item ->
when (item.itemId) {
R.id.navigation_enrollments -> {
message.setText(R.string.title_enrollments)
return#OnNavigationItemSelectedListener true
}
R.id.navigation_timeline -> {
message.setText(R.string.title_timeline)
return#OnNavigationItemSelectedListener true
}
R.id.navigation_home -> {
message.setText(R.string.title_home)
return#OnNavigationItemSelectedListener true
}
R.id.navigation_alerts -> {
message.setText(R.string.title_alerts)
return#OnNavigationItemSelectedListener true
}
R.id.navigation_profile -> {
message.setText(R.string.title_profile)
return#OnNavigationItemSelectedListener true
}
}
false
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
navigation.setOnNavigationItemSelectedListener(mOnNavigationItemSelectedListener)
}
override fun onResume() {
super.onResume()
setContentView(R.layout.activity_main)
val bottomNavigationView = findViewById<BottomNavigationView>(R.id.navigation)
bottomNavigationView.selectedItemId = R.id.navigation_home
}
}
Instead of message.setText(R.string.title_enrollments) do
supportFragmentManager.beginTransaction()
.replace(containerViewId, fragmentInstance, "TAG")
.commitAllowingStateLoss()
Or you can use an extension function I use in my code to make it cleaner. Just add this in some .kt file
inline fun FragmentManager.transactStateless(func: FragmentTransaction.() -> Unit) {
val transaction = beginTransaction()
transaction.func()
transaction.commitAllowingStateLoss()
}
and now you can add remove fragment this way:
supportFragmentManager.transactStateless {
replace(containerViewId, fragmentInstance, "TAG")
}

Categories

Resources