19

I'm currently struggling with the DrawerLayout animation doing weird stuff; The hamburger icon is laggy and often switch from hamburger to arrow without animation if I don't put an Handler to delay the fragment transaction animation.

So I ended up putting an handler to wait until the hamburger icon perform the animation but it just doesn't feel natural that we need to wait until the drawer close to switch fragment. I'm sure there is a better way to handle this...

Here is how I do currently:

private void selectProfilFragment() {
    final BackHandledFragment fragment;
    // TODO test this again
    Bundle bundle = new Bundle();
    bundle.putString(FragmentUserProfile.USER_FIRST_NAME, user.getFirstname());
    bundle.putString(FragmentUserProfile.USER_LAST_NAME, user.getLastname());
    bundle.putString(FragmentUserProfile.USER_PICTURE, user.getProfilepic());
    bundle.putString(FragmentUserProfile.USER_EMAIL, user.getEmail());
    bundle.putBoolean(FragmentUserProfile.USER_SECURITY, user.getParameters().getSecuritymodule().equals("YES"));
    fragment = new FragmentUserProfile();
    fragment.setArguments(bundle);
    mDrawerLayout.closeDrawer(mDrawerLinear);

    new Handler().postDelayed(new Runnable() {
        public void run() {
            FragmentTransaction ft = getSupportFragmentManager().beginTransaction();
            ft.setCustomAnimations(R.anim.pull_in_right, R.anim.push_out_left, R.anim.pull_in_left, R.anim.push_out_right);
            ft.replace(R.id.content_frame, fragment)
                    .addToBackStack(fragment.getTagText())
                    .commitAllowingStateLoss();
        }
    }, 300);
}

It's still glitching a little bit in between the DrawerLayout closing and opening fragment transaction animation.

Here is How I instanciate the drawer:

mDrawerLayout.setDrawerShadow(R.drawable.drawer_shadow, GravityCompat.START);

mDrawerListChild.setAdapter(new DrawerListAdapter(this, R.layout.drawer_layout_item, mPlanTitles));
mDrawerListChild.setOnItemClickListener(new DrawerItemClickListener());

mProfilPic.setOnClickListener(new View.OnClickListener() {
    @Override
    public void onClick(View v) {
        selectProfilFragment();
    }
});

mDrawerToggle = new ActionBarDrawerToggle(
        this,
        mDrawerLayout,
        toolbar,
        R.string.drawer_open,
        R.string.drawer_close
) {
    public void onDrawerClosed(View view) {
        invalidateOptionsMenu();
    }

    public void onDrawerOpened(View drawerView) {
        invalidateOptionsMenu();
    }
};
getSupportFragmentManager().addOnBackStackChangedListener(mOnBackStackChangedListener);
mDrawerLayout.setDrawerListener(mDrawerToggle);
setSupportActionBar(toolbar);
Jaythaking
  • 2,200
  • 4
  • 25
  • 67
  • 1
    I guess initialization of BackHandledFragment has heavy processing. Change BackHandledFragment`s `onCreateView` and `onActivityCreated` simple, and delay heavy processing. – nshmura Aug 11 '16 at 04:24
  • That's not the issue though because it only happens with the Profile Fragment... – Jaythaking Aug 15 '16 at 20:24
  • 1
    Sorry, I make a mistake. Does the initialization of FragmentUserProfile have heavy prosessing? – nshmura Aug 15 '16 at 23:03
  • 1
    Even with this, how are we suppose to handle the closing drawer animation THEN swapping fragment? Because, doing both at the same time doesn't feel natural... And yeah maybe FragmentProfil is a little heavy but then again, thats not the question – Jaythaking Aug 16 '16 at 19:33
  • 1
    I mean even if the processing of the fragment was REALLY quick, I would still need to wait until the Drawer close to perform the fragment swipe animation – Jaythaking Aug 16 '16 at 19:34
  • 1
    I have similar android app which has NavigationDrawer, but does not have animation of Fragment transition. My app does not skip drawer animation and hamburger icon animation. So if initialization of FragmentProfile is simple, the reason of animation skip is possibly too many animation. I recommend you to check gpu monitor to detect the reason. https://developer.android.com/studio/profile/am-gpu.html – nshmura Aug 17 '16 at 12:53

2 Answers2

3

Heres how you can do it. In the Activity containing fragment setup your drawer.

public void setupDrawer(){
 NavigationFragment drawerFragment = (NavigationFragment)
                getSupportFragmentManager().findFragmentById(R.id.navigation_drawer);
        mActionbarToggle = drawerFragment.setUp(R.id.navigation_drawer, mDrawerLayout, mToolbar); 
}

Now in the NavigationDrawerFragment define your setUp method

public ActionBarDrawerToggle setUp(int navigation_drawer, DrawerLayout drawerLayout, Toolbar mToolbar) {
        mFragmentContainerView = getActivity().findViewById(navigation_drawer);
        this.mDrawerLayout = drawerLayout;
        //mDrawerLayout.setDrawerShadow(R.drawable.drawer_shadow, GravityCompat.START);
        ActionBar actionBar = getActionBar();
        actionBar.setDisplayHomeAsUpEnabled(true);
        actionBar.setHomeButtonEnabled(true);
        mDrawerToggle = new ActionBarDrawerToggle(getActivity(), drawerLayout, mToolbar, R.string.drawer_open, R.string.drawer_close) {
            @Override
            public void onDrawerClosed(View drawerView) {
                super.onDrawerClosed(drawerView);
                if (!isAdded()) {
                    return;
                }
                getActivity().supportInvalidateOptionsMenu(); // calls onPrepareOptionsMenu()
            }

            @Override
            public void onDrawerOpened(View drawerView) {
                super.onDrawerOpened(drawerView);
                if (!isAdded()) {
                    return;
                }
                getActivity().supportInvalidateOptionsMenu(); // calls onPrepareOptionsMenu()
            }
        };
        mDrawerToggle.setToolbarNavigationClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {

                ((MainActivity) mContext).onBackPress();
            }
        });
        mDrawerLayout.post(new Runnable() {
            @Override
            public void run() {
                mDrawerToggle.syncState();
            }
        });
        mDrawerLayout.setDrawerListener(mDrawerToggle);

        return mDrawerToggle;
    }

That's it, your drawer is completely setUp.

swetabh suman
  • 1,949
  • 2
  • 19
  • 24
  • what is isAdded()? I'm not following you, how is that suppose to fix my issue? – Jaythaking Aug 17 '16 at 15:09
  • 1
    What the hell is a NavigationFragment? This set up method should've never left the activity. – Eugen Pechanec Sep 26 '16 at 20:12
  • you have to call the setup() from the activity which contains navigationFragment @EugenPechanec – swetabh suman Sep 28 '16 at 12:55
  • 1
    My point is there shouldn't ever be a NavigationFragment. You're calling a method of the fragment from inside an activity and that fragment only ever touches views outside of its own scope. Not only is the fragment pointless it also shows bad design. – Eugen Pechanec Sep 28 '16 at 12:58
3

I am not sure what causing this behavior though I want to draw your attention on few thing.

  1. I am not aware which ActionBarDrawerToggle class you are using but preferable to use android.support.v7.app.ActionBarDrawerToggle instead of android.support.v4.app.ActionBarDrawerToggle as it is deprecated.

  2. Use addDrawerListener() instead of setDrawerListener() as it is deprecated.

  3. Use spinBars and set value true to rotate bars during transition. e.x. in your styles.xml as described here.

  4. In onDrawerClosed and onDrawerOpened call syncState(). Also call this method on your ActionBarDrawerToggle. Check this.

    Hope this will help you.

Community
  • 1
  • 1
Pravin Divraniya
  • 4,223
  • 2
  • 32
  • 49