kanytu / android-material-drawer-template

An Android template with navigation drawer for material design
Apache License 2.0
674 stars 217 forks source link

Where would nav item selection logic go? #10

Closed dkisselev closed 9 years ago

dkisselev commented 9 years ago

In this repo, when a navigation item is selected, the Main_activity just pops up a toast with that item's position, but I can't seem to figure out how to do more than that, things that actually affect the app's state.

Right now I'm looking to just change the Toolbar's title to the app title when the nav drawer is open, then to the title of the currently selected menu when it's closed (like Google Play Music),

I'm playing around with adding the code to onNavigationDrawerItemSelected (just for the second part of the problem), but get null pointers whenever I try to do something like getSupportActionBar().setTitle("Menu item" + position);

Then extending on that, I'd like to be able to swap out the container frame's fragment when an item is selected. So if I have fragment_one and fragment_two, where would I go to define the code that says 'load fragment_one into container on menu 1 tap'?

Perhaps a more complete example of an app that's using this template would really help.

Thanks!

dkisselev commented 9 years ago

Ok, so I've figured out that the reason that nothing was working for me was that onNavigationDrawerItemSelected is actually called for the first time before the View is inflated, which is why getSupportActionBar along with everything else was returning null.

I've solved that problem like so (put this under the Toast.makeText line in MainActivity.java):

if (getSupportActionBar() != null) {
            getSupportActionBar().setTitle("Menu item " + position);
        }

But now I'm wondering how to go further to build out some real functionality.

My main question now is whether this would be the correct place to put more complicated logic (like actually using the position in a switch statement to set fragments), or if it belongs in the Adapter or another class.

kanytu commented 9 years ago

Yes, the onNavigationDrawerItemSelected is where you should put almost all your logic. This template is the same as the one from Android Studio when you start a new application and selected the drawer template. So if you didn't used it before this is an example of how your onNavigationDrawerItemSelected should look like (taken from one of my apps):

if (position == 0) {
    if (getFragmentManager().findFragmentByTag("search") != null) return;
    FragmentTransaction t = getFragmentManager().beginTransaction();
    t.setCustomAnimations(R.anim.alpha_intro, R.anim.alpha_outro, R.anim.alpha_intro, R.anim.alpha_outro);
    SearchFragment fragment = new SearchFragment();
    t.replace(R.id.container, fragment, "search");
    t.commit();
} else if (position == 2) { //favorites
    if (getFragmentManager().findFragmentByTag("favorites") != null) return;
    FragmentTransaction t = getFragmentManager().beginTransaction();
    t.setCustomAnimations(R.anim.alpha_intro, R.anim.alpha_outro, R.anim.alpha_intro, R.anim.alpha_outro);
    FavoritesFragment fragment = new FavoritesFragment();
    t.replace(R.id.container, fragment, "favorites");
    t.commit();
}

So as you can see in this example all the switch logic between fragments takes place here. Keep in mind that the first fragment is always selected when the app starts.

Also if you want to communicate with the drawer fragment you have mNavigationDrawerFragment on your main activity that allows you to perform operations like menu item changes and such.

If you have further questions feel free to ask them here. If not, please mark this issue as closed.

Have a nice day.

dkisselev commented 9 years ago

Awesome, thanks, that really helps.

The one follow-up question to that is how I would set the toolbar title. I'm guessing that the title setting logic more of a function of how the drawer itself works rather than something that the onNavigationDrawerItemSelected function handles (When drawer is open, the title should be the name of the app, when closed it should be the current tab name), but I'm unsure about how I would get access to the actionbar to call setTitle on it from within the NavigationFragment or Adapter.

In Google's navigationdrawer example (I did look at it before, but didn't see the resemblance at first so thought your implementation was different/from scratch), the mainactivity extends from the Activity class, where they just override/call setTitle:

    @Override
    public void setTitle(CharSequence title) {
        mTitle = title;
        getActionBar().setTitle(mTitle);
    }

But it doesn't look like setTitle exists in ActionBarActivity

Thanks!

kanytu commented 9 years ago

You have two ways of doing this:

@Override
public void onNavigationDrawerItemSelected(int position) {
    Toast.makeText(this, "Menu item selected -> " + position, Toast.LENGTH_SHORT).show();
    if (mToolbar != null)
        mToolbar.setTitle("Menu Item  " + position);
}

Or

@Override
public void onNavigationDrawerItemSelected(int position) {
    Toast.makeText(this, "Menu item selected -> " + position, Toast.LENGTH_SHORT).show();
    if (getSupportActionBar() != null)
        getSupportActionBar().setTitle("Menu Item  " + position);
}

Notice the getSupportActionBar() != null because at the time this is called the actionbar can be null. Another more hacky way of doing that could be:

@Override
public void onNavigationDrawerItemSelected(final int position) {
    Toast.makeText(this, "Menu item selected -> " + position, Toast.LENGTH_SHORT).show();
    new Handler().postDelayed(new Runnable() {
        @Override
        public void run() {
            if (getSupportActionBar() != null)
                getSupportActionBar().setTitle("Menu Item  " + position);
        }
    }, 100);
}
dkisselev commented 9 years ago

I ended up implementing it in the NavigationDrawerFragment,

In MainActivity.java:

    @Override
    public void setTitle(CharSequence mTitle)
    {
        if (getSupportActionBar() != null) {
            getSupportActionBar().setTitle(mTitle);
        }
    }

Then in NavigationDrawerFragment.java:

    public void setup(int fragmentId, DrawerLayout drawerLayout, Toolbar toolbar) {
        mFragmentContainerView = getActivity().findViewById(fragmentId);
        mDrawerLayout = drawerLayout;
        mActionBarDrawerToggle = new ActionBarDrawerToggle(getActivity(), mDrawerLayout, toolbar, R.string.drawer_open, R.string.drawer_close) {
            @Override
            public void onDrawerClosed(View drawerView) {
                super.onDrawerClosed(drawerView);
                if (!isAdded()) return;
                getActivity().setTitle(getResources().getStringArray(R.array.drawer_items)[mCurrentSelectedPosition]);
                getActivity().invalidateOptionsMenu();
            }

            @Override
            public void onDrawerOpened(View drawerView) {
                super.onDrawerOpened(drawerView);
                if (!isAdded()) return;
                if (!mUserLearnedDrawer) {
                    mUserLearnedDrawer = true;
                    saveSharedSetting(getActivity(), PREF_USER_LEARNED_DRAWER, "true");
                }
                getActivity().setTitle(R.string.app_name);
                getActivity().invalidateOptionsMenu();
            }
        };

(I listed the titles for my navigation entries in a string array so I can pull them from the position like that)

I think the only part I'm missing is to set the title when the app if first opened because getSupportActionBar does return null there, but that can probably be fixed by forcing the title in onCreate for the MainActivity.

Thanks, that helps all around, hopefully this thread helps someone else in the same spot as me in the future.