My question is in continuation to this question Toolbar NavigationIcon loose theme. This is a known bug in support library 21.
In my case i have two activities with two different theme toolbars. When I navigate back from Activity2 to Activity1, Activity1 toolbar buttons (back and overflow) take Activity2's theme.
I am trying to do a workaround for this problem and this what I have tried so far.
onResume() of my Activity1
#Override
protected void onResume() {
super.onResume();
supportInvalidateOptionsMenu();
if(mToolbar != null) {
// set navigation icon
mToolbar.setNavigationIcon(R.drawable.abc_ic_ab_back_mtrl_am_alpha);
}
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
getSupportActionBar().setHomeButtonEnabled(true);
}
onPrepareOptionsMenu of Activity1
#Override
public boolean onPrepareOptionsMenu(Menu menu) {
// set overflow icon
for(int i = 0; i < mToolbar.getChildCount(); i++) {
if(mToolbar.getChildAt(i) instanceof ActionMenuView) {
ActionMenuView v = (ActionMenuView)mToolbar.getChildAt(i);
for(int j = 0; j < v.getChildCount(); j++) {
if(v.getChildAt(j) instanceof TintImageView) {
TintImageView v1 = (TintImageView)v.getChildAt(j);
v1.setImageResource(R.drawable.abc_ic_menu_moreoverflow_mtrl_alpha);
}
}
}
}
return super.onPrepareOptionsMenu(menu);
}
with this workaround my back button is working fine but overflow icon comes in Activity2's theme untill I press it once. Once pressed it changes its theme. Also I am using Searchview in Activity1 and when its activated then only overflow icon appears.
Let me know if more information is required.
Related
Is it possible to programmatically detect when a menu is overflowed?
My intention is to have a menu item always be visible (SHOW_AS_ACTION_ALWAYS), except for in the case where it would cause other items to overflow, in which case, don't show the menu item at all. That is:
if (overflowed) actionBarMenu.removeItem(id);
You are not saying where this menu is appearing, so I'll just give an example of what you can do with a Toolbar. What you need to do is to get the reference to the ActionMenuView from the Toolbar and then call isOverflowMenuShowing on it, something like this:
private boolean isOverflowShowing(Toolbar toolbar) {
if(toolbar == null) {
return false;
}
for(int i = 0; i < toolbarView.getChildCount(); i++) {
View v = toolbarView.getChildAt(i);
if(v instanceof ActionMenuView) {
return ((ActionMenuView)v).isOverflowMenuShowing();
}
}
return false;
}
This is crude and dirty - and I haven't tested it - but it should get you started.
I am trying to disable the Up button in the Support Actionbar on certain user actions. According to http://developer.android.com/reference/android/app/ActionBar.html#setHomeButtonEnabled(boolean), setHomeButtonEnabled should do what I want. However, the button remains clickable. (I can disable the other icons in the actionbar without problem).
I am trying to disable it from a fragment.
My code to disable is:
#Override
public void onPrepareOptionsMenu (Menu menu) {
if (isUpdating) {
getBaseActivity().getSupportActionBar().setHomeAsUpIndicator(getResources().getDrawable(R.drawable.ic_backgrey));
getBaseActivity().getSupportActionBar().setHomeButtonEnabled(false);
for (int i = 0; i < menu.size(); i++) {
menu.getItem(i).setEnabled(false);
menu.getItem(i).getIcon().setAlpha(64);
}
} else {
getBaseActivity().getSupportActionBar().setHomeButtonEnabled(true);
getBaseActivity().getSupportActionBar().setHomeAsUpIndicator(getResources().getDrawable(R.drawable.ic_back));
for (int i = 0; i < menu.size(); i++) {
menu.getItem(i).setEnabled(true);
menu.getItem(i).getIcon().setAlpha(255);
}
}
}
and my code in activity onCreate is:
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
getSupportActionBar().setHomeAsUpIndicator(getResources().getDrawable(R.drawable.ic_back));
and my Fragment onCreate contains
setHasOptionsMenu(true)
In your fragment add
getBaseActivity().getSupportActionBar().setDisplayHomeAsUpEnabled(false);
and in your Activity add
getSupportActionBar().setDisplayHomeAsUpEnabled(false);
In oncreate() setDisplayHomeAsUpEnabled should be set to false as well.
getSupportActionBar().setDisplayHomeAsUpEnabled(false);
http://developer.android.com/reference/android/app/ActionBar.html#setDisplayHomeAsUpEnabled(boolean)
I am changing the colour of action bar using the following code.
actionBar= getSupportActionBar();
actionBar.setBackgroundDrawable(new ColorDrawable(backgroundColor));
This works perfectly fine in onCreate() method(i.e when my activity starts).
But when I am using the same code in Android 4.1 to change color of action bar in onClick() method(i.e when user clicks say a button) then it changes the color of action bar to 'white' ONLY whatsoever be the value of backgroundColor.
In Android 2.3 it works perfectly fine in both cases, whether called from onCreate or onClick().
It seems to be dead end for me.
It seems like for Android 4.0 up to Android 4.1 (4.2 is ok) you cannot change the action bar background once the activity has started.
So I guess a solution in those cases is to restart the activity with a different background color.
Not very elegant but thats the best I can come up with.
Something like this perhaps:
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Button btn = (Button) findViewById(R.id.btn);
if (getIntent().hasExtra("color")) {
getSupportActionBar().setBackgroundDrawable(
new ColorDrawable(getIntent().getIntExtra("color", 0)));
}
btn.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
Intent it = getIntent();
it.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
it.putExtra("color", Color.BLUE);
startActivity(it);
}
});
}
A workaround I used to solve this problem was to maintain a reference to the ColorDrawable that was used to set the background initially. Then, to change its colour, modify the colour of the Drawable, and then tell the activity to invalidate its options, which causes the ActionBar to be redrawn. Here's my code to set the action bar color:
ColorDrawable sBackgroundDrawable;
...
#TargetApi(Build.VERSION_CODES.HONEYCOMB)
protected void setActionBarColor(int color){
if(getSherlockActivity() != null && !mCallback.isNavDrawerShowing()){
if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.ICE_CREAM_SANDWICH && Build.VERSION.SDK_INT <= Build.VERSION_CODES.JELLY_BEAN){
if(sBackgroundDrawable == null){
sBackgroundDrawable = new ColorDrawable(color);
getSherlockActivity().getSupportActionBar().setBackgroundDrawable(sBackgroundDrawable);
}else{
sBackgroundDrawable.setColor(color);
getSherlockActivity().invalidateOptionsMenu();
}
}else{
getSherlockActivity().getSupportActionBar().setBackgroundDrawable(new ColorDrawable(color));
}
}
}
Based off of what steve_the_kid mentioned I was able to solve this by saving the color drawable.
ColorDrawable actionBarBackground = new ColorDrawable();
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
getActionBar().setBackgroundDrawable(actionBarBackground());
actionBarBackground.setColor(someColor);
}
void onSomethingClick() {
actionBarBackground.setColor(someOtherColor);
}
Sorry for such a late reply,But to help others I am replying to this question after so long.
Just set the Title of the action bar or make change in the icons or menu along with changing the colorDrawables.A simple change will recreate the action bar with new color.Even if you need same title or icon every time set same title or same icon.
I hope this will help others
I have an app with ActionBarSherlock using theme Theme.Sherlock.Light.DarkActionBar. Action bar is dark and my menu icons are light. When I run my app on small layouts, 2 or 3 menu items with icons are displayed in the overflow menu.
On Android 3+ the overflow menu items will not display their icons, but on Android 2.3 and earlier I see menu tiles with almost invisible icons, because the tile color is white and icons are close to be white.
As you can see, the light icons are invisible on a white background, but they must have light color to be visible on a dark action bar:
Can I remove icons when menu items are displayed in the overflow menu?
you could use configuration qualifiers.
e.g.
make a drawable folder
/res/drawable-v11/ put all the "light" icons in it.
and for the darker icons use the
/res/drawable/ folder.
be sure to use the same filenames in both folders.
I hope I have understood your problem and this might help you.
However, if you want to change the drawables JUST for the overflow menu, I don't think it's possible. Also because the menu icons are not intended to be used like that. ActionBarSherlock is probably also because of issues like this, not an official library.
I was also facing the same issue:
there are many ways you can achieve this rather than removing image:
1)you can use respective drawable folder to put light and dark image.
2)You can also change the background color by code of your menu by checking your device version.
If you device doen't support overflow menu, the, you can change the background color of your menu as well as you can also change menu text color.
I was also facing the same issue and resolved using following one:
static final Class<?>[] constructorSignature = new Class[] {Context.class, AttributeSet.class};
class MenuColorFix implements LayoutInflater.Factory {
public View onCreateView(String name, Context context, AttributeSet attrs) {
if (name.equalsIgnoreCase("com.android.internal.view.menu.ListMenuItemView")) {
try {
Class<? extends ViewGroup> clazz = context.getClassLoader().loadClass(name).asSubclass(ViewGroup.class);
Constructor<? extends ViewGroup> constructor = clazz.getConstructor(constructorSignature);
final ViewGroup view = constructor.newInstance(new Object[]{context,attrs});
new Handler().post(new Runnable() {
public void run() {
try {
view.setBackgroundColor(Color.BLACK);
List<View> children = getAllChildren(view);
for(int i = 0; i< children.size(); i++) {
View child = children.get(i);
if ( child instanceof TextView ) {
((TextView)child).setTextColor(Color.WHITE);
}
}
}
catch (Exception e) {
Log.i(TAG, "Caught Exception!",e);
}
}
});
return view;
}
catch (Exception e) {
Log.i(TAG, "Caught Exception!",e);
}
}
return null;
}
}
public List<View> getAllChildren(ViewGroup vg) {
ArrayList<View> result = new ArrayList<View>();
for ( int i = 0; i < vg.getChildCount(); i++ ) {
View child = vg.getChildAt(i);
if ( child instanceof ViewGroup) {
result.addAll(getAllChildren((ViewGroup)child));
}
else {
result.add(child);
}
}
return result;
}
#Override
public void onCreateContextMenu(ContextMenu menu, View v, ContextMenuInfo menuInfo) {
LayoutInflater lInflater = getLayoutInflater();
if ( lInflater.getFactory() == null ) {
lInflater.setFactory(new MenuColorFix());
}
super.onCreateContextMenu(menu, v, menuInfo);
MenuInflater inflater = getMenuInflater();
inflater.inflate(R.menu.myMenu, menu);
}
3) change background color from styles.xml file
<style name="Theme.MyTheme" parent="Theme.Sherlock.ForceOverflow">
<item name="actionBarStyle">#style/Widget.MyTheme.ActionBar</item>
<item name="android:actionBarStyle">#style/Widget.MyTheme.ActionBar</item>
</style>
<style name="Widget.MyTheme.ActionBar" parent="Widget.Sherlock.ActionBar">
<item name="android:background">#ff000000</item>
<item name="background">#ff000000</item>
</style>
For me, all of the 3 worked fine
Hope, this will work for you as well
Another option is to remove the icons from the non-action items in onPrepareOptionsMenu.
The idea is to use actionbarsherlock's MenuItemImpl.isActionButton to figure out if each item is an action item, and if not to remove the icon. This is made a little bit tricky because onPrepareOptionsMenu is called (at least) twice by ABS - the first time when it is building the action bar, in which case MenuItemImpl.isActionButton has not yet been set and will always return false. If that's the case, you want to leave the icons alone. Once the action bar has been built the isActionButton method will return true for action bar items, false otherwise. So you want to remove the icons for the ones that return false. This is what I came up with:
#Override
public boolean onPrepareOptionsMenu(Menu menu) {
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.HONEYCOMB) {
boolean buildingOptionsMenu = false;
for (int i=0; i<menu.size(); ++i) {
MenuItemImpl mi = (MenuItemImpl)menu.getItem(i);
if (mi.isActionButton()) {
buildingOptionsMenu = true;
break;
}
}
if (buildingOptionsMenu) {
for (int i=0; i<menu.size(); ++i) {
MenuItemImpl mi = (MenuItemImpl)menu.getItem(i);
if (!mi.isActionButton()) {
mi.setIcon(null);
mi.setIcon(0);
}
}
}
}
return super.onPrepareOptionsMenu(menu);
}
You'll need these two imports:
import com.actionbarsherlock.view.Menu;
import com.actionbarsherlock.internal.view.menu.MenuItemImpl;
This works in ABS 4.3.0, but since it uses internal library classes it might not work with other versions of the library.
OS 2.x was a mess since the options menu background could be black or white, depending on the device, with no way to know which for sure.
The easy fix was to use grey (#888888) icons for Android 2.x & under and put your modern (ICS/JB) icons in a v11 folder for modern devices:
drawable // old school icons
drawable-v11 // modern icons
Of course that means drawable-mdpi-v11, drawable-hdpi-v11, and so on.
A simple alternative to adding a whole set of duplicate dark icons for 2.x versions can be simply removing the icons from all the items that can go to the overflow menu. For example:
res/menu
<item
android:id="#+id/menu_send_email"
android:showAsAction="ifRoom"
android:title="#string/menu_send_email"/>
res/menu-v11 (or even res/menu-v9, because 2.3 usually has a dark menu)
<item
android:id="#+id/menu_send_email"
android:icon="#drawable/ic_action_send_email"
android:showAsAction="ifRoom"
android:title="#string/menu_send_email"/>
Of course, you need to make the titles short enough to fit into the ActionBar at least on some larger screens, or settle with the fact that they always go into the overflow.
I would like to dynamically change the "home" icon in the ActionBar. This is easily done in v14 with ActionBar.setIcon(...), but I can't find anyway to accomplish this in previous versions.
If your actionbar works like Sherlock and is based on menu items, this is my solution:
#Override
public boolean onPrepareOptionsMenu(Menu menu) {
MenuItem switchButton = menu.findItem(R.id.SwitchSearchOption);
if(searchScriptDisplayed){
switchButton.setIcon(R.drawable.menu_precedent);
}else{
switchButton.setIcon(R.drawable.icon_search);
}
return super.onPrepareOptionsMenu(menu);
}
If you are using the ActionbarCompat code provided by google, you can access the home icon via the ActionBarHelperBase.java class for API v4 onwards.
//code snippet from ActionBarHelperBase.java
...
private void setupActionBar() {
final ViewGroup actionBarCompat = getActionBarCompat();
if (actionBarCompat == null) {
return;
}
LinearLayout.LayoutParams springLayoutParams = new LinearLayout.LayoutParams(
0, ViewGroup.LayoutParams.MATCH_PARENT);
springLayoutParams.weight = 1;
// Add Home button
SimpleMenu tempMenu = new SimpleMenu(mActivity);
SimpleMenuItem homeItem = new SimpleMenuItem(tempMenu,
android.R.id.home, 0, mActivity.getString(R.string.app_name));
homeItem.setIcon(R.drawable.ic_home_ftn);
addActionItemCompatFromMenuItem(homeItem);
// Add title text
TextView titleText = new TextView(mActivity, null,
R.attr.actionbarCompatTitleStyle);
titleText.setLayoutParams(springLayoutParams);
titleText.setText(mActivity.getTitle());
actionBarCompat.addView(titleText);
}
...
You should be able to modify the code to the home button accessible to the activities that extend ActionBarActivity and change it that way.
Honeycomb seems a little harder and it doesn't seem to give such easy access. At a guess, its id should also be android.R.id.home so you may be able to pull that from the view in ActionBarHelperHoneycomb.java
I would say you do something like this :
getSupportActionBar().setHomeButtonEnabled(true);
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
getSupportActionBar().setHomeAsUpIndicator(R.drawable.ic_menu_drawer);
see the link How to change the icon actionBarCompat
The ActionBar will use the android:logo attribute of your manifest, if one is provided. That lets you use separate drawable resources for the icon (Launcher) and the logo (ActionBar, among other things).