4

I'm working with a simple app with Bottom Navigation View. I have 3 fragments (layout and java). I have BottonNavigationView, declared in my MainActivity.java. My bottonnavigation have 3 items, for the 3 fragments. So, in my MainActivity.java, when i select a item, it start one fragment. So, when i select again another item, nothing happens, because in the java fragment i need to declare the BottonNavigationView, but i don't know how to set it to switch the actual fragment with another fragment. I tried this link, but no success: https://developer.android.com/training/basics/fragments/fragment-ui.html

Sorry my bad english

Here the codes:

Main Activity

 @Override
public boolean onNavigationItemSelected(@NonNull MenuItem item) {
    Fragment selectedFragment = null;
    switch (item.getItemId()) {
        case R.id.navigation_home:
            selectedFragment = HomeFragment.newInstance();
            break;
        case R.id.navigation_dashboard:
            selectedFragment = DashboardFragment.newInstance();
            break;
        case R.id.navigation_notifications:
            selectedFragment = NotificationsFragment.newInstance();
            break;
    }
    FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();
    transaction.replace(R.id.content, selectedFragment);
    transaction.commit();
    return true;
}

Fragment Java Example

public class HomeFragment extends Fragment {
public static HomeFragment newInstance() {
HomeFragment fragment = new HomeFragment();
return fragment;
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View rootView = inflater.inflate(R.layout.navigation_home, container, false);
return inflater.inflate(R.layout.navigation_home, container, false);
}
CodigosTutoriales
  • 1,018
  • 1
  • 10
  • 21
Tony Starkus
  • 556
  • 2
  • 8
  • 25
  • why you always create new instance? – PeerNet Jun 08 '17 at 00:59
  • in my main_activity layout, i have a linearlayout with FrameLayout and BottomNavigationView, i think i need to create a new instance, no ? – Tony Starkus Jun 08 '17 at 01:04
  • you can create fragments just once, and you can use them again. – PeerNet Jun 08 '17 at 01:05
  • Can you show me a code ? and how i will switch between fragments on item selected ? – Tony Starkus Jun 08 '17 at 01:11
  • For example, Fragment homeFragment = HomeFragment.newInstance(); Fragment notificationsFragment = NotificationsFragment.newInstance(); And in switch case, you can set selectedFragment = homeFragment or something else – PeerNet Jun 08 '17 at 01:29
  • @TonyStarkus according to this your showed code is correct. First: Do you have data to show in other `fragments`? Second: For which layout is id `content`? Your issue is somewhere in rest of the code – Yupi Jun 08 '17 at 01:32
  • @Yupi I have just a TextView for the fragments (the text is the fragment name). The id content is the framelayout in my activity_main.xml layout – Tony Starkus Jun 08 '17 at 19:16
  • @TonyStarkus then check your xml in menu folder are you putting right one in `BottomNavigationView` and also are id from your menu correct? If that is correct then update your question with xml code of your `activity_main` and of your `MainActivity` – Yupi Jun 08 '17 at 19:28
  • @Thien Huynh solved my problem man. Just one more question: i have three fragments (Home, Dashboard and Notifications). The Home fragment is the principal menu of my app. So, if i am in Dashboard or Notifications, and i press the button, i want to set the onKeyDown to back for Home Fragment, and, in home fragment, if i press back button, i want to close de app. ou know how to do that ? – Tony Starkus Jun 08 '17 at 19:54
  • @TonyStarkus override `onBackPressed()` and implement desired code – Yupi Jun 08 '17 at 20:32
  • Like this :@Override public boolean onKeyDown(int keyCode, KeyEvent event) { if ((keyCode == KeyEvent.KEYCODE_BACK)) { HomeFragment.newInstance(); return true; } return super.onKeyDown(keyCode, event); } – Tony Starkus Jun 08 '17 at 20:41
  • Oh man, this code don't work. I will create another question in the forum. Thank you so much for the help !!! – Tony Starkus Jun 08 '17 at 20:41

6 Answers6

9

You can try it:

@Override
public boolean onNavigationItemSelected(@NonNull MenuItem item) {
    Fragment selectedFragment = null;
    switch (item.getItemId()) {
        case R.id.navigation_home:
            selectedFragment = HomeFragment.newInstance();
            break;
        case R.id.navigation_dashboard:
            selectedFragment = DashboardFragment.newInstance();
            break;
        case R.id.navigation_notifications:
            selectedFragment = NotificationsFragment.newInstance();
            break;
    }
    getSupportFragmentManager().beginTransaction().replace(R.id.content, selectedFragment).commit();
    return true;
}
E.Akio
  • 2,249
  • 3
  • 14
  • 27
Thien Huynh
  • 166
  • 7
  • 1
    Wow man, looks like is working, thank you. Just one more question: i have three fragments (Home, Dashboard and Notifications). The Home fragment is the principal menu of my app. So, if i am in Dashboard or Notifications, and i press the button, i want to set the onKeyDown to back for Home Fragment, and, in home fragment, if i press back button, i want to close de app. ou know how to do that ? – Tony Starkus Jun 08 '17 at 19:53
  • If you want transition between Fragments, call addToBackStack(). https://stackoverflow.com/questions/7992216/android-fragment-handle-back-button-press – Thien Huynh Jun 09 '17 at 02:02
  • Thanks @Thien, is a lot of codes but i will try them. Thanks – Tony Starkus Jun 09 '17 at 21:12
  • @ThienHuynh how do you set the fragment initially on the first run? – RazorHead Feb 03 '18 at 03:56
  • @RazorHead navigationView.getMenu().getItem(0).setChecked(true); With item 0 it mean HomeFragment is the first. – Thien Huynh Feb 06 '18 at 02:07
  • @ThienHuynh sorry but I meant to ask how do you load the initial fragment the first time activity starts. your suggestion activates the bottom nav. – RazorHead Feb 24 '18 at 23:53
  • Wait how is this any different than the OP mentioned in his question ? Am I missing something ? I can't see any difference. – Syed Ahmed Jamil Dec 10 '19 at 00:03
6

You don't have to create newInstance every time. you can save the fragment states. follow the below link

fragmentManager.beginTransaction().hide(toBeHidden).show(toBeShown).commit();

https://medium.com/@oluwabukunmi.aluko/bottom-navigation-view-with-fragments-a074bfd08711

rajeswari ratala
  • 650
  • 7
  • 14
2

In this case is better to try get exist fragment from fragmentManager like fragmentManager.findFragmentByTag(tag). You can switch more smoothly and you don't need for example load some content from network (if you have such code in fragment or presenter of fragment)

Djek-Grif
  • 1,391
  • 18
  • 18
0

You should create once newIstance from each your Fragments. and later you can hide active fragment and then show new fragment.

    Fragment activeFragment;
    ArrayList<Fragment> fragment;

public boolean onNavigationItemSelected(@NonNull MenuItem item) {
            Fragment selectedFragment = null;
            switch (item.getItemId()) {
                case R.id.navigation_fragment:
                    selectedFragment = ShowMyFragment.newInstance();
                    replaceFragment(selectedFragment);
                    return true;
}
});
    private void replaceFragment(Fragment selectedFragment) {
        boolean lastOpened = false;
        for ( int i=0; i<fragment.size();i++ )
        {
            if ( fragment.get(i) == selectedFragment ) {
                lastOpened = true;
                break;
            }
        }
        if (!lastOpened) {
            getSupportFragmentManager().beginTransaction().replace(R.id.content, selectedFragment).commit();
        }
        else
        {
            getSupportFragmentManager().beginTransaction().hide(activeFragment).show(selectedFragment).commit();
        }

        activeFragment = selectedFragment;
    }
  • Not working if you change toolbar in fragments. After screen rotation toolbar menus are overlaying – Neuron Sep 06 '19 at 05:40
0

Just to add a blank implementation like this in onCreate bottomNavView.setOnNavigationItemReselectedListener {}

100rbh
  • 763
  • 1
  • 7
  • 10
0

My full solution, I think will be usefull for juniors:

So, we have MainActivity:

import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.fragment.app.Fragment

class MainMenuActivity : AppCompatActivity() {

override fun onCreate(savedInstanceState: Bundle?) {
  super.onCreate(savedInstanceState)
  setContentView(R.layout.activity_main)

  val bottomNav: BottomNavigationView = findViewById(R.id.bottom_naviagtion)
  bottomNav.setOnNavigationItemSelectedListener(navListener)

    if (savedInstanceState == null) {
         supportFragmentManager.beginTransaction().replace(
              R.id.fragment_container,
             HomeFragment()
         ).commit()
     }
 }

 private val navListener: BottomNavigationView.OnNavigationItemSelectedListener =
      BottomNavigationView.OnNavigationItemSelectedListener { item ->
         var selectedFragment: Fragment? = null
         when (item.itemId) {
        R.id.bottom_home -> selectedFragment =
            HomeFragment()
        R.id.bottom_events -> selectedFragment =
            EventFragment()
        R.id.bottom_contacts -> selectedFragment =
            ContactsFragment()
        R.id.bottom_menu -> selectedFragment =
            MenuFragment()
    }
    supportFragmentManager.beginTransaction().replace(
        R.id.fragment_container,
        selectedFragment!!
     ).commit()
     true
 }
}

activity_main.xml:

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

<FrameLayout
    android:id="@+id/fragment_container"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:layout_above="@id/bottom_naviagtion"/>

<View
    android:layout_width="match_parent"
    android:layout_height="10dp"
    android:layout_above="@id/bottom_naviagtion"
    android:background="@drawable/shadow"/>

<com.google.android.material.bottomnavigation.BottomNavigationView
    android:id="@+id/bottom_naviagtion"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:layout_alignParentBottom="true"
    app:menu="@menu/bottom_menu"
    android:background="?android:attr/windowBackground" />

</RelativeLayout>

Each fragment class looks like:

import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.fragment.app.Fragment

class HomeFragment : Fragment() {
   override fun onCreateView(
       inflater: LayoutInflater,
       container: ViewGroup?,
       savedInstanceState: Bundle?
   ): View? {
       return inflater.inflate(R.layout.fragment_home, container, false)
   }
 }

.xml file for HomeFragment (fragment_home.xml) looks like (other fragments looks the same):

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">

<TextView
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:text="@string/home"
    android:textSize="30sp"
    android:layout_centerInParent="true"/>

</RelativeLayout>

NavigationBottomMenu .xml looks (bottom_menu.xml):

<?xml version="1.0" encoding="utf-8"?>
<menu
xmlns:android="http://schemas.android.com/apk/res/android">

<item
    android:id="@+id/bottom_home"
    android:icon="@drawable/home_selector"
    android:title="Home" />


<item
    android:id="@+id/bottom_events"
    android:icon="@drawable/events_selector"
    android:title="Events" />

<item
    android:id="@+id/bottom_contacts"
    android:icon="@drawable/contacts_selector"
    android:title="Contacts"/>

<item
    android:id="@+id/bottom_menu"
    android:icon="@drawable/menu_selector"
    android:title="Menu" />

</menu>

Used icons from drawble folder were imported like Vector Asset