Search code examples
androidandroid-fragmentsandroid-fragmentactivity

Cannot load Fragments from Navigation Drawer items


I have found a lot about this around but I really can't solve my problem. I have spent hours in this but nothing.

I have a Navigation Drawer Activity made with Android Studio 2.1.1 templates. Of course I want to change the view of my app, when I click on a item in the menu, showing different Fragments. This is the code that I have in the MainActivity:

        public boolean onNavigationItemSelected(MenuItem item) {
        // Handle navigation view item clicks here.
        int id = item.getItemId();

        if (id == R.id.nav_camera) {

            Context context = getApplicationContext();
            CharSequence text = "Hello toast!";
            int duration = Toast.LENGTH_SHORT;

            Toast toast = Toast.makeText(context, text, duration);
            toast.show();

            new gaussFragment();

        } else if (id == R.id.nav_gallery) {

        } else if (id == R.id.nav_slideshow) {

        } else if (id == R.id.nav_manage) {

        } else if (id == R.id.nav_share) {

        } else if (id == R.id.nav_send) {

        }

        DrawerLayout drawer = (DrawerLayout) findViewById(R.id.drawer_layout);
        drawer.closeDrawer(GravityCompat.START);
        return true;
    }

When I click on the first item of the navigation drawer (the one with the id R.id.nav_camera) I can see the toast but the new Fragment is not appearing. I am using this code in gaussFragment():

public class gaussFragment extends Fragment {

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
                             Bundle savedInstanceState) {
        // Inflate the layout for this fragment
        return inflater.inflate(R.layout.fragment_gauss, container, false);
    }

}

Of course as you can see here the fragment_gauss.xml is its relative layout having this code:

<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context="info.androidhive.tabsswipexx.gaussFragment">

    <!-- TODO: Update blank fragment layout -->
    <TextView
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:text="@string/hello_blank_fragment" />

</FrameLayout>

How could I solve this?


The content_main is the first thing that I see when the app launches. Should I try to add something like

<FrameLayout
        android:id="@+id/content_frame"
        android:layout_width="match_parent"
        android:layout_height="match_parent" />

and somehow load there my fragments?


Solution

  • If you're using the Navigation Drawer template provided by Android Studio then in the navigation Drawer main activity xml you'll find something like :

    <?xml version="1.0" encoding="utf-8"?>
    <android.support.v4.widget.DrawerLayout
        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/drawer_layout"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:fitsSystemWindows="true"
        tools:openDrawer="start">
    
        <!-- The main content view -->
        <include layout="@layout/app_bar_main"
            android:layout_width="match_parent"
            android:layout_height="match_parent" />
    
        <!-- the navigation drawer the comes from the left-->
        <android.support.design.widget.NavigationView
            android:id="@+id/nav_view"
            android:layout_width="wrap_content"
            android:layout_height="match_parent"
            android:layout_gravity="start"
            android:fitsSystemWindows="true"
    
            app:headerLayout="@layout/nav_header_main"
            app:menu="@menu/activity_main_drawer" />
    
    </android.support.v4.widget.DrawerLayout>
    

    If you take a closer look there you'll see that it consistst of two main parts that I have commented for you. One is for the navigation drawer stuff and the other is the main content wiew stuff. If you ctrl+click on layout="@layout/app_bar_main" you'll see that another xml opens which is the following:

    <?xml version="1.0" encoding="utf-8"?>
    <android.support.design.widget.CoordinatorLayout
        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:fitsSystemWindows="true"
        tools:context="copsonic.com.SoundExchange.demoApp.MainActivity">
    
        <!--Main View tool bar-->
        <android.support.design.widget.AppBarLayout
            android:layout_height="wrap_content"
            android:layout_width="match_parent"
            android:theme="@style/AppTheme.AppBarOverlay">
    
            <android.support.v7.widget.Toolbar
                android:id="@+id/toolbar"
                android:layout_width="match_parent"
                android:layout_height="?attr/actionBarSize"
                android:background="?attr/colorPrimary"
                app:popupTheme="@style/AppTheme.PopupOverlay" />
    
        </android.support.design.widget.AppBarLayout>
    
        <!--The content that will be displayed in the main view when the navigation drawer is not opened-->
        <include layout="@layout/content_main" />
    
        <!--Floating Action Button Stuff-->
        <android.support.design.widget.FloatingActionButton
            android:id="@+id/fab"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_gravity="bottom|end"
            android:layout_margin="@dimen/fab_margin"
            android:scaleType="center"
            android:src="@mipmap/ic_rx_tx"
            android:saveEnabled="false"
            app:backgroundTint="#000000"
            android:adjustViewBounds="false" />
    
    
    
    </android.support.design.widget.CoordinatorLayout>
    

    There you'll see 3 main parts, one for the tool bar, one for the Floating Action Button control and finally one for the content that will be displayed in the main view when the navigation drawer is not opened, this is the one you care about. If you ctrl+click in <include layout="@layout/content_main" /> You'll see a third xml were you must add a Fragmet container. In the end it's something like this:

    <?xml version="1.0" encoding="utf-8"?>
    <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:tools="http://schemas.android.com/tools"
        xmlns:app="http://schemas.android.com/apk/res-auto" android:layout_width="match_parent"
        android:layout_height="match_parent" android:paddingLeft="@dimen/activity_horizontal_margin"
        android:paddingRight="@dimen/activity_horizontal_margin"
        android:paddingTop="@dimen/activity_vertical_margin"
        android:paddingBottom="@dimen/activity_vertical_margin"
        app:layout_behavior="@string/appbar_scrolling_view_behavior"
        tools:showIn="@layout/app_bar_main"
        tools:context="copsonic.com.SoundExchange.demoApp.MainActivity">
    
        <!-- A fragmet container to dynamically swap between fragmets-->
        <FrameLayout
            android:id="@+id/fragment_container"
            android:layout_width="match_parent"
            android:layout_height="match_parent" />
    
    </RelativeLayout>
    

    So after all this from your main activity code you just have to do two things, first manage which fragment is going to be seen first, you do this in the OnCreate method by adding :

    FragmentTransmitter initialFragment = new FragmentTransmitter();
    
    
    // Check that the activity is using the layout version with
    // the fragment_container FrameLayout
    if (findViewById(R.id.fragment_container) != null) {
    
            // this check allows you not to load the default fragment unless 
            //it's the first time you launch the activity after having destroyed it
            if (savedInstanceState != null) {
                return;
            }
    
        // Create the fragment that is seen the first time your app opens
    
        //pass useful info to the fragment from main activity if needed 
        //(it is recommended not to do this in the constructor, so you have to do it through a Bundle)
        Bundle args = new Bundle();
        args.putSerializable("ModulationType",aModulation);
        initialFragment.setArguments(args);
    
    
        // In case this activity was started with special instructions from an
        // Intent, pass the Intent's extras to the fragment as arguments
        //initialFragment.setArguments(getIntent().getExtras());
    
        // Add the fragment to the 'fragment_container' FrameLayout
        getSupportFragmentManager().beginTransaction().add(R.id.fragment_container, initialFragment).commit();
    
    }
    

    And then the second thing is handle properly which fragment will be displayed each time an option is selected in the navigation drawer

    public boolean onNavigationItemSelected(MenuItem item) {
            // Handle navigation view item clicks here.
            int id = item.getItemId();
    
            if (id == R.id.nav_camera) {
    
                Context context = getApplicationContext();
                CharSequence text = "Hello toast!";
                int duration = Toast.LENGTH_SHORT;
    
                Toast toast = Toast.makeText(context, text, duration);
                toast.show();
    
                FragmentTransmitter Gauss= new new gaussFragment();
    
                //pass useful info to fragment if needed
                Bundle args = new Bundle();
                args.putSerializable(getString(R.string.ModulationType),aModulation);
                Gauss.setArguments(args);
    
                FragmentTransaction transaction =   getSupportFragmentManager().beginTransaction();
                transaction.replace(R.id.fragment_container, Gauss,"TAG_GaussFragment"); //pacing a tag is not mandatory but it is pretty useful if you want to know later which fragment is being displayed in the fragment container
                //transaction.addToBackStack(null);
                transaction.commit();
    
    
    
            } else if (id == R.id.nav_gallery) {
    
            } else if (id == R.id.nav_slideshow) {
    
            } else if (id == R.id.nav_manage) {
    
            } else if (id == R.id.nav_share) {
    
            } else if (id == R.id.nav_send) {
    
            }
    
            DrawerLayout drawer = (DrawerLayout) findViewById(R.id.drawer_layout);
            drawer.closeDrawer(GravityCompat.START);
            return true;
        }