The Home fragment rises above the rest - android

when I switch between the fragment I created, the home fragment is not deleted, it writes on the others.
please i have an issue. I am using bottom navigation and nav controller. once I switch fragments, the home fragment keeps showing under the rest
`
class FeedActivity : AppCompatActivity() {
private lateinit var bottomNavigationView: BottomNavigationView
//loadFragment(HomeFragment())
bottomNavigationView = findViewById(R.id.bottom_navigation) as BottomNavigationView
bottomNavigationView.setOnItemSelectedListener {
when (it.itemId) {
R.id.nav_home -> {
loadFragment(HomeFragment())
true
}
R.id.nav_search -> {
loadFragment(SearchFragment())
true
}
R.id.nav_add -> {
loadFragment(AddFragment())
true
}
R.id.nav_notifications -> {
loadFragment(NotificationsFragment())
true
}
R.id.nav_profile -> {
loadFragment(ProfileFragment())
true
}
else -> throw IllegalStateException("Someone forgot to add enough fragment cases to 'when' clause!")
}
}
}
private fun loadFragment(fragment: Fragment){
val transaction = supportFragmentManager.beginTransaction()
transaction.replace(R.id.cercevekapsayici,fragment)
transaction.commit()
}`
`<RelativeLayout
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=".view.FeedActivity">
<FrameLayout
android:id="#+id/cercevekapsayici"
android:layout_above="#id/bottom_appbar"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
<androidx.recyclerview.widget.RecyclerView
android:id="#+id/recyclerView"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<com.google.android.material.appbar.AppBarLayout
android:id="#+id/bottom_appbar"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true" >
<com.google.android.material.bottomnavigation.BottomNavigationView
android:id="#+id/bottom_navigation"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="?android:attr/windowBackground"
app:itemIconTint="#color/cardview_dark_background"
app:labelVisibilityMode="unlabeled"
app:menu="#menu/bottom_navigation" />
</com.google.android.material.appbar.AppBarLayout>
[[enter image description here](https://i.stack.imgur.com/3D2Z8.png)](https://i.stack.imgur.com/llwZ5.png)`
I want the recyclerview to disappear when I switch to other fragments.

You can make your FramLayout height match parent :
<FrameLayout
android:id="#+id/cercevekapsayici"
android:layout_above="#id/bottom_appbar"
android:layout_width="match_parent"
android:layout_height="match_parent" />

Your loadFragment function replaces whatever Fragment is attached to R.id.cercevekapsayici, which is a FrameLayout that contains your fragments. But your RecyclerView is part of your main layout, so it will always be there whatever you attach to R.id.cercevekapsayici.
If you want it to be replaced, put it in a Fragment and add it to that FrameLayout - then it'll be removed when you switch to a different fragment.

Maybe you need to give background to the other fragments

Related

BottomNavigationView together with a FrameLayout - clicking on an icon doesn't change the state. The question works

everyone. I have a BottomnNavigationsBar and a FrameLayout inside my activity_main.xml file. In the frame I display a ViewPager within a Fragment. The navigation contains 3 elements. If I click on one, the clicked status does not change. The respective fragment is displayed correctly, but the icon does not change in color and size.
What am I doing wrong or what do I have to change?
Here is my MainActivity:
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
viewBinding = ActivityMainBinding.inflate(layoutInflater)
setContentView(viewBinding.root)
setFragementTo(HomeFragment.newInstance("",""))
viewBinding.bottomNavigationView.setOnItemSelectedListener{
when(it.itemId)
{
R.id.home ->{
setFragementTo(HomeFragment.newInstance("",""))
}
R.id.neu ->{
setFragementTo(NewFragment.newInstance("",""))
}
R.id.settings ->{
setFragementTo(FilterFragment.newInstance("",""))
}
}
false
}
}
private fun setFragementTo(fragment: Fragment) {
supportFragmentManager.beginTransaction().replace(R.id.myFrameInMain,fragment).commit()
}
activity_main.xml:
<androidx.constraintlayout.widget.ConstraintLayout 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">
<FrameLayout
android:id="#+id/myFrameInMain"
android:layout_width="0dp"
android:layout_height="0dp"
app:layout_constraintBottom_toTopOf="#+id/bottomNavigationView"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"></FrameLayout>
<com.google.android.material.bottomnavigation.BottomNavigationView
android:background="#drawable/bottom_nav_style"
app:itemRippleColor="#color/white"
app:itemTextColor="#color/item_bottom_nav"
app:itemIconTint="#color/item_bottom_nav"
android:id="#+id/bottomNavigationView"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:menu="#menu/bottom_nav"/>
</androidx.constraintlayout.widget.ConstraintLayout>
Here I click on the middle icon in the navigation. The fragment appears correctly, but the icon in the navigation does not
And here the filter icon:
I think I got it. I had to change the parameter from false to true in the setOnItemSelectedListener method

bottom navigation view doesnt shows fargment unless double click

i fixed the previous error but now this here. fragment isnt visible if i dont click bottom navigation two times. my code:
activity_main.xml
<androidx.fragment.app.FragmentContainerView
android:id="#+id/FragmentContainerView"
android:layout_width="match_parent"
android:layout_height="0dp"
app:layout_constraintBottom_toTopOf="#+id/bottom_navigation"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.0"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<com.google.android.material.bottomnavigation.BottomNavigationView
android:id="#+id/bottom_navigation"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:menu="#menu/bottom_navigation_menu" />
MainActivity.kt
binding.bottomNavigation.setOnItemReselectedListener { item ->
when(item.itemId) {
R.id.home -> {
replaceFragment(HomeFragment())
}
R.id.favs -> {
replaceFragment(FavsFragment())
}
}
}
}
private fun replaceFragment(fragment: Fragment) {
val fragmentManager = supportFragmentManager
val fragmentTransaction = fragmentManager.beginTransaction()
fragmentTransaction.replace(R.id.FragmentContainerView, fragment)
fragmentTransaction.commit()
}
First we create navigation.xml (you can create navigation.xml if you click the ResourceManager button on the left, select navigation at the top and click the + sign), then we name it my_nav and click the new destination button on the top and select all the fragments you will use. I suggest you to select your main fragment first
<fragment
android:id="#+id/fragment"
android:name="androidx.navigation.fragment.NavHostFragment"
android:layout_width="match_parent"
android:layout_height="0dp"
app:defaultNavHost="true"
app:layout_constraintBottom_toTopOf="#+id/bottom_navigation"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.0"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:navGraph="#navigation/my_nav" />
or try this
binding.bottomNavigation.setItemSelected(R.id.home, true)
by the way, some advice for you
binding.apply{
//If I do it this way, you don't need to write bindings for your objects every time.
//eg:
bottomNavigation.setOnItemReselectedListener { item ->
}
}
Instead of setOnItemReselectedListener you should use setOnItemSelectedListener to avoid "double-clicking".
But you still have to add initial fragment to FragmentContainerView. For example, in onCreate() you can call your replaceFragment() with the fragment that you need to be shown at first.

Using Navigation's actions instead of direct fragment id crashes app

I'm having an issue with a very simple task with Navigation component.
I have just 2 screens: MainFragment and SearchFragment.
When I try to go from MainFragment to SearchFragment by navigation with an action it works perfectly. Then I press the back button and naturally it goes back to the MainFragment.
The issue is, when I click the same button the second time to go again to the SearchFragment, I receive the following error:
java.lang.IllegalArgumentException: Navigation action/destination action_mainFragment_to_searchFragment cannot be found from the current destination Destination(searchFragment)
I'm navigating from the MainFragment to Search like this:
findNavController().navigate(MainFragmentDirections.actionMainFragmentToSearchFragment())
I tried redoing the nav_graph.xml but without success.
If I just navigate with the id directly, it works fine and I go back and forth as many times as I want
findNavController().navigate(R.id.searchFragment)
Any ideas how to fix the issue with the safe args?
Edit:
This is my nav_graph
<?xml version="1.0" encoding="utf-8"?>
<navigation 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:id="#+id/nav_graph_main"
app:startDestination="#id/mainFragment">
<fragment
android:id="#+id/mainFragment"
android:name="news.presentation.main.MainFragment"
android:label="fragment_main"
tools:layout="#layout/fragment_main">
<action
android:id="#+id/action_mainFragment_to_searchFragment"
app:destination="#id/searchFragment" />
</fragment>
<fragment
android:id="#+id/searchFragment"
android:name="news.presentation.search.SearchFragment"
android:label="fragment_search"
tools:layout="#layout/fragment_search" />
</navigation>
This is the activity (it's basically just a container for the fragments):
This is the activity_home.xml
<?xml version="1.0" encoding="utf-8"?>
<androidx.fragment.app.FragmentContainerView 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:id="#+id/homeFragContainer"
android:name="androidx.navigation.fragment.NavHostFragment"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:defaultNavHost="true"
app:navGraph="#navigation/nav_graph_main"
tools:context=".presentation.HomeActivity" />
And this is the HomeActivity.kt
#AndroidEntryPoint
class HomeActivity : AppCompatActivity(R.layout.activity_home)
This is the HomeFragment:
#AndroidEntryPoint
class MainFragment : Fragment(R.layout.fragment_main) {
private val binding by viewBinding(FragmentMainBinding::bind)
private val viewModel by viewModels<MainViewModel>()
private val articlesAdapter = ArticlesAdapter(::onSubscriptionClicked)
private lateinit var layoutManager: LinearLayoutManager
override fun onViewCreated(view: View, bundle: Bundle?) {
super.onViewCreated(view, bundle)
setupViews()
setupViewModel()
setupRecyclerView()
}
private fun setupViews() {
binding.toolbar.title = getString(R.string.app_name)
binding.fab.setOnClickListener {
viewModel.intent.offer(MainViewModel.Intent.SearchClicked)
}
}
private fun setupViewModel() {
viewModel.state
.onEach(::handleState)
.launchIn(lifecycleScope)
viewModel.feedFlow
.onEach(articlesAdapter::submitList)
.launchIn(lifecycleScope)
}
private fun setupRecyclerView() {
layoutManager = LinearLayoutManager(requireContext())
binding.recycler.layoutManager = layoutManager
binding.recycler.adapter = articlesAdapter
binding.recycler.addOnScrollListener(object : RecyclerView.OnScrollListener() {
override fun onScrollStateChanged(recyclerView: RecyclerView, newState: Int) {
super.onScrollStateChanged(recyclerView, newState)
val canScroll = recyclerView.canScrollVertically(-1)
binding.toolbar.isLifted = canScroll
}
})
}
private fun onSubscriptionClicked(article: Article) {
viewModel.intent.offer(MainViewModel.Intent.ItemClicked(article))
}
private fun handleState(state: MainViewModel.State) = when (state) {
NavigateToSearch -> findNavController().navigate(MainFragmentDirections.actionMainFragmentToSearchFragment())
is FeedReady -> binding.progress.isVisible = false
Loading -> binding.progress.isVisible = true
is NavigateToArticle -> {
// works
// findNavController().navigate(
// R.id.articleFragment,
// bundleOf("articleLink" to state.link)
// )
}
}
}
And this is the XML for it:
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout 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"
android:clipChildren="false"
android:clipToPadding="false"
tools:context=".presentation.main.MainFragment">
<androidx.recyclerview.widget.RecyclerView
android:id="#+id/recycler"
android:layout_width="match_parent"
android:layout_height="0dp"
app:layout_constraintBottom_toTopOf="#id/bottomNav"
app:layout_constraintTop_toBottomOf="#id/toolbar"
tools:listitem="#layout/item_article_big" />
<com.google.android.material.floatingactionbutton.ExtendedFloatingActionButton
android:id="#+id/fab"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_margin="#dimen/standard"
android:text="Add Feed"
android:textAlignment="center"
app:icon="#drawable/ic_add"
app:layout_constraintBottom_toTopOf="#id/bottomNav"
app:layout_constraintEnd_toEndOf="parent" />
<com.google.android.material.bottomnavigation.BottomNavigationView
android:id="#+id/bottomNav"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:layout_constraintBottom_toBottomOf="parent"
app:menu="#menu/menu_main" />
<tgo1014.news.presentation.customview.LiftableToolbar
android:id="#+id/toolbar"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:clipChildren="false"
android:clipToPadding="false"
app:layout_constraintTop_toTopOf="parent" />
<com.google.android.material.progressindicator.LinearProgressIndicator
android:id="#+id/progress"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:indeterminate="true"
app:layout_constraintBottom_toBottomOf="#id/toolbar"
app:layout_constraintTop_toBottomOf="#id/toolbar"
tools:visibility="visible" />
</androidx.constraintlayout.widget.ConstraintLayout>
the error is due to the lifecycle.
Replace this:
viewModel.state
.onEach(::handleState)
.launchIn(lifecycleScope)
by
viewModel.state
.onEach(::handleState)
.launchIn(viewLifecycleOwner.lifecycleScope)

Navigating between fragment bug (BottomNavigationView Visibility) [duplicate]

I have my MainActivity setup which looks like this :
<androidx.constraintlayout.widget.ConstraintLayout 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=".ui.host.HostActivity">
<fragment
android:id="#+id/mainNavigationFragment"
android:name="androidx.navigation.fragment.NavHostFragment"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:defaultNavHost="true"
app:navGraph="#navigation/nav_graph" />
<com.google.android.material.bottomnavigation.BottomNavigationView
android:id="#+id/bottomNavigationView"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="?android:attr/windowBackground"
app:labelVisibilityMode="labeled"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:menu="#menu/main_nav_menu" />
</androidx.constraintlayout.widget.ConstraintLayout>
And the bottom navigation has 3 tabs which can only be shown after some initial authentication and setup user calls have been performed.
What is the best way to show a Loading/Setting up user screen before I let user start using the bottom nav view.
One way I am thinking is to delay the setup of NaHostFragment in my Activity until all the setup is done.
So basically toggle the visibility of mainNavigationFragment and BottomNavigationView till the setup is completed.
Are there any other ideas ?
The NavigationUI documentation actually uses hiding a BottomNavigationView as its example. You could also use an OnDestinationChangedListener to update the visibility of your BottomNavigationView, say, only hiding it while the user is on the login screen (note that as per the Conditional Navigation documentation, you shouldn't be doing this in the start destination of your graph, but redirecting users to those screens):
navController.addOnDestinationChangedListener { _, destination, _ ->
if(destination.parent?.id == R.id.login) {
bottomNavigationView.visibility = View.GONE
} else {
bottomNavigationView.visibility = View.VISIBLE
}
}
in my Activity
//using view model
loginViewModel.isLoggedIn.observe(this, Observer { loggedIn ->
if(!loggedIn) {
startActivity(Intent(this#MainActivity,LoginActivity::class.java))
finish()
}
else {
//set up the controller
val navController = findNavController(R.id.nav_host_fragment)
nav_view.setupWithNavController(navController)
navController.addOnDestinationChangedListener { controller, destination, arguments ->
when(destination.id) {
R.id.navigation_home,R.id.navigation_profile,R.id.navigation_account -> {
nav_view.visibility = View.VISIBLE
}
else -> {
nav_view.visibility = View.GONE
}
}
}
}

Fragment not loading after second click on bottom navigation

i am trying to add viewpager and tablayout along with bottom navigation. First time fragment loads fine then i click the item the fragment is not loading properly
here is my main activity code
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout 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"
android:orientation="vertical"
tools:context=".MainActivity">
<include layout="#layout/toolbar"
android:id="#+id/layout_toolbar"/>
<FrameLayout
android:id="#+id/fragmentContainer"
android:layout_width="match_parent"
android:layout_weight="1"
android:layout_height="0dp"/>
<com.google.android.material.bottomnavigation.BottomNavigationView
android:id="#+id/bottomNav"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:menu="#menu/bottom_nav_menu"
android:background="#drawable/bg_bottom_bar"
/>
</LinearLayout>
Kotlin Code
bottomNav.setOnNavigationItemSelectedListener {
var selectedFragment: Fragment? = null
when (it.itemId) {
R.id.homeFragment -> {
replaceFragment(fragment = HomeFragment())
return#setOnNavigationItemSelectedListener true
}
R.id.fixtures -> {
replaceFragment(fragment = AllMatchsFragment())
return#setOnNavigationItemSelectedListener true
}
}
false
}
private fun replaceFragment(fragment: Fragment) {
supportFragmentManager.beginTransaction().replace(R.id.fragmentContainer, fragment).commit()
}
Here is fragment code where i want to load viewpager and tablayout:
homePagerAdapter = HomeViewpagerAdapter(activity!!.supportFragmentManager)
homePagerAdapter!!.populateFragment(AllMatchsFragment())
homePagerAdapter!!.populateFragment(LiveMatchesFragment())
view.homeViewPager.adapter=homePagerAdapter
view.tabLayout.setupWithViewPager(view.homeViewPager)
return view
Fragment XML
<com.google.android.material.tabs.TabLayout
android:id="#+id/tabLayout"
android:layout_width="172dp"
android:layout_height="wrap_content"
app:tabMode="fixed"
app:tabTextColor="#color/colorPrimary"
app:tabSelectedTextColor="#color/colorAccent"
>
</com.google.android.material.tabs.TabLayout>
<androidx.viewpager.widget.ViewPager
android:id="#+id/homeViewPager"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_below="#id/tabLayout"/>
ViewPagerAdapter
val tabNameList= listOf("All","Live")
val fragmentList = mutableListOf<Fragment>()
override fun getItem(position: Int): Fragment {
return fragmentList[position]
}
override fun getCount(): Int {
return 2
}
override fun getPageTitle(position: Int): CharSequence? {
return tabNameList[position]
}
fun populateFragment(fragment: Fragment){
fragmentList.add(fragment)
}
When I perform second click on the second viewpager got stuck and fragment disappear when I close and reopen the app it works fine and after second click again remain the same.
Try to use childFragmentManager instead of supportFragmentManager
homePagerAdapter = HomeViewpagerAdapter(activity!!.supportFragmentManager)

Categories

Resources