I have an activity with new support Toolbar and navigation drawer. The Toolbar relates to the content e.g. list of items. Multiple items can be selected - then ActionMode is shown (Context Action Bar). However the system ActionMode position, size and layout order does not correspond to the Toolbar, which would be appropriate.
Question is: how can I adjust the system ActionMode to correspond to (be aligned with) my Toolbar? Or is there any other recommended alternative? See my cases below
Portrait
NavDrawer may be hidden in side (1-green) - this is OK for both Toolbar and ActionMode.
Both Toolbar and its content are overlapped by the navigation drawer the drawer is opened (2-yellow). However, when ActionMode is active, it is displayed always over the NavDrawer (3-red), but I want it to look like (2-yellow), because the ActionMode is related to the hidden content.
This issue is similar to this question:
How to make the Contextual ActionMode Bar overlay the appcompat-v7 Toolbar but not the navigation drawer?
Tablet/landscape
In landscape the NavDrawer fits next to the toolbar and content (left). The ActionMode always overlays the NavDrawer and Toolbar and has full screen width (right-red). Again I would like the ActionMode to be in the same position as Toolbar is (left-yellow).
I solved it by using another Toolbar (actionModeToolbar), which I can put anywhere in layout and show or hide it as appropriate.
I found some useful hints how to use Toolbar here:
https://gist.github.com/gabrielemariotti/ae63392e1c70bc33af8b
Here is how I created ActionMode using Toolbar with legacy ActionMode.Callback. I have used methods similar to system ActionMode for partial compatibility.
Note, that ActionMode.Callback is not required anymore, because system ActionMode is not used and code can be refactored.
class ToolbarActionMode {
Toolbar actionModeToolbar;
ActionMode.Callback callback;
void startActionMode() {
actionModeToolbar.setNavigationOnClickListener(new View.OnClickListener() {
#Override public void onClick(View v) {
toolbarActionMode.finishActionMode();
}
});
actionModeToolbar.setOnMenuItemClickListener(new Toolbar.OnMenuItemClickListener() {
#Override public boolean onMenuItemClick(MenuItem menuItem) {
return callback.onActionItemClicked(null, menuItem);
}
});
// will create menu using inflateMenu(R.menu.menu_res)
callback.onCreateActionMode(null, null);
invalidate();
actionModeToolbar.setVisibility(View.VISIBLE);
}
void finishActionMode() {
callback.onDestroyActionMode(null);
actionModeToolbar.setVisibility(View.GONE);
}
void invalidate() {
// will update title + menu
callback.onPrepareActionMode(null, actionModeToolbar.getMenu());
}
void setTitle(CharSequence title) {
actionModeToolbar.setTitle(title);
}
void inflateMenu(int menuRes) {
actionModeToolbar.inflateMenu(menuRes);
}
}
Related
Is there any way to listen if actionbar is invisible or visible.(a callback/listener method). "isShowing()" not working in my cases.
My Case :
I've a YouTube player in full screen mode with overlaying an actionbar (android.support.v7.app.ActionBar) and a dialog fragment added at bottom of the screen. Now, I need a listener to hide and show that dialog fragment, but there have no such listener in youtube player api. So, I'm trying to get it through inheriting actionbar visibility. Unfortunately, I couldn't find a listener if actionbar is now Visible or Invisible.
Create two functions in activity
void showActionbar() { getSupportActionBar().show(); }
void hideActionbar() { getSupportActionBar().hide(); }
Call them in your fragment when you want to show or hide. Here is how you call
((ActivityName)getActivity()).showActionbar();
((ActivityName)getActivity()).hideActionbar();
You can also check if actionbar showing with
boolean IsActionbarVisible() { if(getSupportActionBar().isShowing())
return true; else return false; }
I know that if I have a support v7 Toolbar set on my Activity I can make changes to the overflow menu right before it is displayed by overriding onPrepareOptionsMenu()
However I have a standalone support v7 Toolbar. I still want to display an overflow menu and be able to update it right before it is opened. I know how to display it...
Toolbar toolbar = ...
toolbar.inflateMenu(R.menu.my_menu);
toolbar.setOnMenuItemClickListener(new Toolbar.OnMenuItemClickListener() {
#Override
public boolean onMenuItemClick(MenuItem item) {
// TODO
return false;
}
});
... but how can I make changes right before the overflow menu is open?
I have a ViewPager where pages contain charting views which react to sliding movements. Due to this i resorted to changing the page by sliding from the edge of the screen. But that leaves me with the problem that this is also the gesture to open the NavigationDrawer.
Until now i used the following code to achieve this:
protected override void OnCreate(Bundle savedInstanceState)
{
base.OnCreate(savedInstanceState);
SetContentView(GetLayoutId());
Toolbar = FindViewById<Toolbar>(Resource.Id.toolbar);
if (Toolbar != null)
{
// set this flag so the colors colorPrimaryDark and android:statusBarColor have an effect
// setting android:statusBarColor to transparent causes the drawer to be dran underneath a translucent status bar
Window.AddFlags(WindowManagerFlags.DrawsSystemBarBackgrounds);
// make the toolbar the replacement of the action bar
SetSupportActionBar(Toolbar);
}
// add the hamburger icon
m_DrawerLayout = FindViewById<DrawerLayout>(Resource.Id.drawer_layout);
var actionBarDrawerToggle = new ActionBarDrawerToggle(this, m_DrawerLayout, Toolbar, Resource.String.empty, Resource.String.empty);
m_DrawerLayout.AddDrawerListener(actionBarDrawerToggle);
// make sure the drawer can't be opened by swiping, to do this we set the lock mode to closed
// but if we just do this, it can't be closed by swiping either, so set the lock mode to unlocked when the drawer is opened, and locked again when it's closed
m_DrawerLayout.DrawerOpened += (object sender, DrawerLayout.DrawerOpenedEventArgs e) =>
{
m_DrawerLayout.SetDrawerLockMode(DrawerLayout.LockModeUnlocked);
};
m_DrawerLayout.DrawerClosed += (object sender, DrawerLayout.DrawerClosedEventArgs e) =>
{
m_DrawerLayout.SetDrawerLockMode(DrawerLayout.LockModeLockedClosed);
};
m_DrawerLayout.SetDrawerLockMode(DrawerLayout.LockModeLockedClosed);
//calling sync state is necessay or else the hamburger icon wont show up
actionBarDrawerToggle.SyncState();
}
It worked as intended, until i updated to the Android Support Design Library 23.1.1.1, now setting the lock mode to closed also prevents the menu from being opened by tapping on the hamburger icon.
Looking at the source code for the latest version of the ActionBarDrawerToggle class, this does indeed seem to be the new intended behavior. It's toggle() method now looks like this:
private void toggle() {
int drawerLockMode = mDrawerLayout.getDrawerLockMode(GravityCompat.START);
if (mDrawerLayout.isDrawerVisible(GravityCompat.START)
&& (drawerLockMode != DrawerLayout.LOCK_MODE_LOCKED_OPEN)) {
mDrawerLayout.closeDrawer(GravityCompat.START);
}
else if (drawerLockMode != DrawerLayout.LOCK_MODE_LOCKED_CLOSED) {
mDrawerLayout.openDrawer(GravityCompat.START);
}
}
whereas it previously just checked the drawer's opened/closed state.
This is unfortunate, since it will now take a workaround to achieve the old behavior. Perhaps the simplest thing to do is just to revert to an older version of the support library. However, if you want to keep the newest version, one possible solution is as follows.
First remove the Toolbar argument from the ActionBarDrawerToggle constructor call.
actionBarDrawerToggle = new ActionBarDrawerToggle(this,
m_DrawerLayout,
Resource.String.empty,
Resource.String.empty);
This will cause the Activity's OnOptionsItemSelected() method to fire upon clicking the toggle, since you've set the Toolbar as the support ActionBar. We will also need to call SupportActionBar.SetDisplayHomeAsUpEnabled(true) to actually show the toggle, since the ActionBarDrawerToggle class interacts somewhat differently with an ActionBar than it does with a Toolbar, with respect to their child Views.
In the Activity's OnOptionsItemSelected() method, we then simply unlock the drawer before calling the toggle's own OnOptionsItemSelected() method, which handles the opening and closing of the drawer.
public override bool OnOptionsItemSelected (IMenuItem item)
{
switch (item.ItemId)
{
case Android.Resource.Id.Home:
m_DrawerLayout.SetDrawerLockMode(DrawerLayout.LockModeUnlocked);
actionBarDrawerToggle.OnOptionsItemSelected(item);
return true;
...
}
...
}
Your actionBarDrawerToggle will need to be a field of your Activity, and you can remove the DrawerOpened handler.
Is there a way to animate the default 3-vertical-dotted menu icon on toolbar?
I use toolbar as actionbar with the standard code:
Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
setSupportActionBar(toolbar);
and I also use the onCreateOptionsMenu method inside activity where I inflate my menu.xml file
but I don't know how to gain more control over the overflow icon which is created automatically. What I'm most interested in is how to reference the menu icon So I can animate it. I don't care about the animation type. It can be a simple rotation animation
Well, you play with the View specifically ActionMenuView so try this, copy the codes into your Activity
//we declare our objects globally
Toolbar tool; ActionMenuView amv;
then override onPrepareOptionsMenu, what you decide to return is your choice
#Override
public boolean onPrepareOptionsMenu(Menu menu) {
//to be safe you can check if children are greater than 1
amv = (ActionMenuView) tool.getChildAt(1);//hope you've met amv
return true;
}
now this is the crucial part- whenever you want to animate the "3 verticall dots" -(your overflow) you have to check visible children-(i.e if you want to) actually forget that
amv.getChildAt(amv.getChildCount()-1).startAnimation(AnimationUtils.loadAnimation(
MainActivity.this,R.anim.abc_fade_in));
that gives you a basic fade-in animation- you can pimp your ride now.
EDIT 1:
The above code made assumptions that you have nothing added to your Toolbar aside from just inflating the menu in onCreateOptionsMenu.
Suppose you have a complex ToolBar use this rather for your initialisation
#Override
public boolean onPrepareOptionsMenu(Menu menu) {
for(int i =0; i < tool.getChildCount(); ++i){
if(tool.getChildAt(i).getClass().getSimpleName().equals("ActionMenuView")){
amv = (ActionMenuView) tool.getChildAt(i);
break;
}
}
return true;
}
Also where you call your initialisation of amv View can be in either onCreateOptionsMenu or onPrepareOptionsMenu, i chose onPrepareOptionsMenu because i wanted readability
Hope it helps
I'm trying to build an app with a split actionbar/toolbar like in the Gmail app.
Is there any view element for this behaviour or do I have to write such a toolbar myself?
The search icon is moving with the master fragment when opening the slidingDrawer.
To accomplish this you can add one of the new Toolbar widgets to each of your fragments layouts. The new Toolbar class was designed to be much more flexible than a traditional Actionbar and will work well in this split design. This post is a good overview for implementing a standalone Toolbar. For posterity's sake I've included the sample code for it below.
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.blah);
Toolbar toolbar = (Toolbar) findViewById(R.id.my_awesome_toolbar);
// Set an OnMenuItemClickListener to handle menu item clicks
toolbar.setOnMenuItemClickListener(new Toolbar.OnMenuItemClickListener() {
#Override
public boolean onMenuItemClick(MenuItem item) {
// Handle the menu item
return true;
}
});
// Inflate a menu to be displayed in the toolbar
toolbar.inflateMenu(R.menu.your_toolbar_menu);
}