What I want to do is slide the ActionBar
along with the NavigationDrawer
when the drawer is opened. I am currently not using any third party libraries and if at all possible I want to keep it that way. All i need is an implementation of method like: getActionBarView.slide(dp);
This is the code I currently use to create the NavigationDrawer
:
mDrawerToggle = new ActionBarDrawerToggle(this, drawerLayout, R.drawable.ic_drawer, R.string.drawer_open, R.string.drawer_close) {
public void onDrawerClosed(View view) {
invalidateOptionsMenu();
// calling onPrepareOptionsMenu() to hide action bar icons
}
@Override
public void onDrawerSlide(View drawerView, float slideOffset) {
if (getDeviceType(getApplicationContext()) == DEVICE_TYPE_PHONE) {
drawerLayout.setScrimColor(Color.parseColor("#00FFFFFF"));
float moveFactor = (listView.getWidth() * slideOffset);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) {
all_menu_container_parent.setTranslationX(moveFactor);
} else {
TranslateAnimation anim = new TranslateAnimation(lastTranslate, moveFactor, 0.0f, 0.0f);
anim.setDuration(0);
anim.setFillAfter(true);
all_menu_container_parent.startAnimation(anim);
lastTranslate = moveFactor;
}
}
}
public void onDrawerOpened(View drawerView) {
// calling onPrepareOptionsMenu() to hide action bar icons
}
};
drawerLayout.setDrawerListener(mDrawerToggle);
But it doesn't do what I want, it produces this:
What I want to achieve is this:
The
NavigationDrawer
was specifically designed to be situated below theActionBar
and there is no way to implement theNavigationDrawer
to make theActionBar
move with it - unless maybe looking for theView
which makes up theActionBar
and animating it alongside theNavigationDrawer
, but I would never recommend something like this as it would be difficult and error prone. In my opinion you only have two options:Since you said that you don't want to use a library implementing a custom sliding menu is your only option, fortunately this is really not that hard once you know how to do it.
1) Basic Explanation
You can move the whole content of the
Activity
- I mean everything including theActionBar
- by putting a margin or a padding on theView
which makes up theActivity
. ThisView
is the parent of theView
with the idandroid.R.id.content
:On Honeycomb (Android version 3.0 - API level 11) or above - in other words after the
ActionBar
was introduced - you need to use margins to change theActivities
position and on previous versions you need to use a padding. To simplify this I recommend creating helper methods which perform the correct action for each API level. Let's first look at how to set the position of theActivity
:Notice that in both cases there is either a negative margin or a negative padding on the opposite sides. This is to essentially increase the size of the
Activity
beyond its normal bounds. This prevents the actual size of theActivity
to change when we slide it somewhere.We additionally need two methods to get the current position of the
Activity
. One for the x position, one for the y position:It is also very simple to add animations. The only important thing here is a bit of math to animate it from its previous position to its new position
You can display a
View
at the location which is revealed by sliding away theActivity
by adding it to the parent of theView
:And that is pretty much all you need to create a basic sliding menu that works on most if not all devices above Eclair (Android 2.1 - API level 7).
2) Animating the
Activity
The first part of creating a sliding menu is making the
Activity
move out of the way. As such we should first try to move theActivity
around like this:To create this we just have to put the code above together:
You can use the
ActivitySlider
class like this:3) Adding the sliding menu
Now we want to reveal a menu when the
Activity
moves out of the way like this:As you can see it also pushes the
ActionBar
to the side.The
ActivitySlider
class does not need to be modified that much to create a sliding menu, basically we just add two methods,showMenu()
andhideMenu()
. I will stick to best practices and use aFragment
as the sliding menu. The first thing we need need is aView
- for example aFrameLayout
- as a container for ourFragment
. We need to add thisView
to the parent of theView
of theActivity
:Since we set the visibility of the container
View
to VISIBLE only when the sliding menu is actually open we can use the following method to check if the menu is open or closed:To set the menu
Fragment
we add a setter method that performs aFragmentTransaction
and adds the menuFragment
to theFrameLayout
:I also tend to add a second setter which instantiates the
Fragment
from aClass
for convenience:There is one additional important thing to consider when it comes to the menu
Fragment
. We are operating much further up in theView
hierarchy than normally. As such we have to take things like the height of the status bar into account. If we didn't account for this the top of the menuFragment
would we be hidden behind the status bar. You can get the height of the status bar like this:We have to put a top margin on the container
View
of the menuFragment
like this:Finally we can put all this together:
I use a static helper method in
showMenu()
to convert dip to pixels. Here is the code of this method:You can use this new version of the
ActivitySlider
class like this:4) Conclusion & Testing
Doing something like this is surprisingly easy when you know that you can simply put a margin or a padding on the
View
of theActivity
. But the difficulty is in making it work on a lot of different devices. Implementations can change a lot across multiple API Levels and that can have considerable influence on how this behaves. Having said that any code I posted here should work on most if not all devices above Eclair (Android 2.1 - API level 7) without any problems.Of course the solution I posted here is not complete, it could use a little extra polishing and cleaning up, so feel free to improve the code to suit your needs!
I have tested everything on the following devices:
I hope I could help you and if you have any further questions or anything else is unclear please feel free to ask!