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).
Related
I am using Navigation View in android studio to create a navigation drawer in my app. In the navigation drawer, I want one item to be colored in green, one in red and others in black (just like the one in the screenshot below). However, I can't seem to find the solution to this. I know I can change the color of all the items using 'itemTextColor' in XML but that's not what I want to do.
So it seems it not as easy to change specific items colours, its either all or nothing (via app:itemIconTint and app:itemTextColor on the com.google.android.material.navigation.NavigationView), but it seems you can do something like this (I did it in Java as you never mentioned if you were using Kotlin or Java):
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// .. other code
NavigationView navigationView = findViewById(R.id.nav_view);
// .. other code
int menuItemPosition = 0; // the position of the menu item in NavigationView you want to change the color of
MenuItem menuItem = navigationView.getMenu().getItem(menuItemPosition);
this.changeMenuItemColor(menuItem, Color.RED);
}
private void changeMenuItemColor(MenuItem menuItem, #ColorInt int color) {
SpannableString coloredMenuItemTitle = new SpannableString(menuItem.getTitle());
coloredMenuItemTitle.setSpan(new ForegroundColorSpan(Color.RED), 0, coloredMenuItemTitle.length(), 0);
menuItem.setTitle(coloredMenuItemTitle);
}
I'm running into a strange issue when adding a Toolbar to my Form in my Codenameone app. If I set a toolbar on my form, it shows another title with the toolbar hamburger and new title below the title of the previous form instead of replacing it like I would expect. It looks like this:
The functionality works fine replacing the old title like I would expect when I run in the Codenameone simulator, but I get this weird behavior shown in the image when I make an Android build and run it on a Nexus 5 (6.0.1). The back arrow and "12 of 12" is the title from the previousForm
This is my code, am I doing anything wrong here with the Toolbar usage?
void goShowResource(final Form previousForm) {
previous = previousForm;
final Toolbar bar = new Toolbar();
final Form rd = new Form("resource details");
final Resource thisResource = this;
rd.setToolbar(bar);
bar.addCommandToSideMenu(new Command("command 1") {
#Override
public void actionPerformed(ActionEvent evt) {
AddResources ar = new AddResources(settings, thisResource);
ar.goAddResources(rd);
}
});
bar.addCommandToSideMenu(new Command("command 2") {
#Override
public void actionPerformed(ActionEvent evt){
UpdateResource ur = new UpdateResource(settings);
ur.goUpdateResource(rd, thisResource);
}
});
rd.setLayout(new BoxLayout(BoxLayout.Y_AXIS));
showDetails(rd);
rd.show();
}
edit: Additonal info, if I open the sidemenu once, the old title bar at the top shrinks away, and I'm left with the the single correct yet incorrectly formatted title area.
You should use the Toolbar for all the forms in the app or disable the default which is native menu bar when working with the toolbar. You can do the latter by editing the theme and selecting the constants tab then pressing "Add" and selecting commandBehavior=Side.
Android currently defaults to the native ActionBar behavior and Toolbar implicitly overrides that, however when a transition occurs from the native to the lightweight component things can get pretty hairy (and might also look unnatural) so we recommend picking one UI paradigm and going with it.
Since the ActionBar is a volatile API we recommend Toolbar going forward as its far more customizable and gives us a lot of control.
This can be fixed by removing all command from the form after setting the toolbar, then add a fresh back command to the toolbar if required.
void goShowResource(final Form previousForm) {
previous = previousForm;
final Toolbar bar = new Toolbar();
final Form rd = new Form("resource details");
final Resource thisResource = this;
rd.removeAllCommands();
rd.setBackCommand(null);
rd.setToolbar(bar);
//Add back command
Command back = new Command("back") {
#Override
public void actionPerformed(ActionEvent evt) {
previousForm.showBack();
}
};
bar.addCommandToSideMenu(back);
bar.addCommandToSideMenu(new Command("command 1") {
#Override
public void actionPerformed(ActionEvent evt) {
AddResources ar = new AddResources(settings, thisResource);
ar.goAddResources(rd);
}
});
bar.addCommandToSideMenu(new Command("command 2") {
#Override
public void actionPerformed(ActionEvent evt){
UpdateResource ur = new UpdateResource(settings);
ur.goUpdateResource(rd, thisResource);
}
});
rd.setLayout(new BoxLayout(BoxLayout.Y_AXIS));
showDetails(rd);
rd.show();
}
Since SplitActionBar is no longer supported in Android 5.0, I am trying to use an ActionMenuView to achieve a SplitActionBar effect. But I could not find much information on how to use ActionMenuView.
I know I can add a ActionMenuView in the layout file, but I don't know how to add menu items. It doesn't seem like I could inflate them like I do with SplitActionBar.
Could you give some sample code on how to use ActonMenuView? Thanks!
Getting ActionMenuView to display a whole screen's width of icons is a chore. Here is an example to do what you want. Make sure your ActionMenuView XML item is wrap_content for height and width, then gravity to the right. Surround it in a LinearLayout which takes the whole width and provides background color.
Use this code to initialize the ActionMenuView (obviously you will need to change the button callbacks)
ActionMenuView actionMenuView = (ActionMenuView) findViewById(R.id.editBar);
final Context context = this;
MenuBuilder menuBuilder = new MenuBuilder(context);
menuBuilder.setCallback(new MenuBuilder.Callback() {
#Override
public boolean onMenuItemSelected(MenuBuilder menuBuilder, MenuItem menuItem) {
return onOptionsItemSelected(menuItem);
}
#Override
public void onMenuModeChange(MenuBuilder menuBuilder) {
}
});
// setup a actionMenuPresenter which will use up as much space as it can, even with width=wrap_content
ActionMenuPresenter presenter = new ActionMenuPresenter(context);
presenter.setReserveOverflow(true);
presenter.setWidthLimit(getResources().getDisplayMetrics().widthPixels, true);
presenter.setItemLimit(Integer.MAX_VALUE);
// open a menu xml into the menubuilder
getMenuInflater().inflate(R.menu.editbar, menuBuilder);
// runs presenter.initformenu(mMenu) too, setting up presenter's mmenu ref... this must be before setmenuview
menuBuilder.addMenuPresenter(presenter, this);
// runs menuview.initialize too, so menuview.mmenu = mpresenter.mmenu
actionMenuView.setPresenter(presenter);
presenter.updateMenuView(true);
For what it's worth, I had to read the support library source code for 8 hours to get this to work. The documentation is garbage.
It seems the API has changed in the meantime. Currently, the following code works:
ActionMenuView actions = new ActionMenuView(activity);
MenuBuilder menuBuilder = (MenuBuilder) actions.getMenu();
menuBuilder.setCallback(new MenuBuilder.Callback() {
#Override
public boolean onMenuItemSelected(MenuBuilder menuBuilder, MenuItem menuItem) {
return onOptionsItemSelected(menuItem);
}
#Override
public void onMenuModeChange(MenuBuilder menuBuilder) {
}
});
inflater.inflate(R.menu.my_menu, menuBuilder);
If you are using the v7 appCompat library make sure your activity extends from ActionBarActivity and that you use the support version of the ActionMenuView.
Likewise if you are not using the support library be sure to use the ActionMenuView outside the support library.
From there you can get the ActionMenuView from your layout and populate its menu using the following method:
getMenuInflater().inflate(R.menu.your_menu_here, actionMenuView.getMenu())
If you aren't in an activity where getMenuInflater() is accessible create your own MenuInflater or SupportMenuInflater.
In appcompat-v7:27.0.2, the ActionMenuView requires a minimum width of 56dp. Do not use android:layout_width="wrap_content".
If your popup theme is being ignored, make sure you call setPopupTheme(int) before any call to getMenu() on ActionMenuView.
Inflate
you can use this code in your activity :
menuInflater.inflate(R.menu.{your_menu_res_id}, {your_ActionMenuView_instance}.menu)
like this :
menuInflater.inflate(R.menu.settings_menu, settings_menu.menu)
Item Click Listener
then you can add item click listenter :
{your_ActionMenuView_instance}.setOnMenuItemClickListener()
like this :
settings_menu.setOnMenuItemClickListener { menuItem ->
when (menuItem.itemId) {
R.id.menu_settings_save -> {
// your code
return#setOnMenuItemClickListener true
}
else -> return#setOnMenuItemClickListener false
}
}
This is a short question:
I'm trying to force the action bar (used by a Toolbar) to use LTR alignment. I've succeeded making the layout itself use LTR, but not the "up" button (as I've done here, before Toolbar was introduced) .
It seems this view doesn't have an ID, and I think using getChildAt() is too risky.
Can anyone help?
The answer
Here's one way I've found to solve this, based on this answer .
I made it so that it is guarranteed to find only the "up" button, and whatever it does, it will revert back to the previous state it was before.
Here's the code:
#TargetApi(Build.VERSION_CODES.JELLY_BEAN_MR1)
#Override
public boolean onCreateOptionsMenu(final Menu menu)
{
// <= do the normal stuff of action bar menu preparetions
if(VERSION.SDK_INT>=VERSION_CODES.JELLY_BEAN_MR1&&getResources().getConfiguration().getLayoutDirection()==View.LAYOUT_DIRECTION_RTL)
{
final ArrayList<View> outViews=new ArrayList<>();
final CharSequence previousDesc=_toolbar.getNavigationContentDescription();
for(int id=0;;++id)
{
final String uniqueContentDescription=Integer.toString(id);
_toolbar.findViewsWithText(outViews,uniqueContentDescription,View.FIND_VIEWS_WITH_CONTENT_DESCRIPTION);
if(!outViews.isEmpty())
continue;
_toolbar.setNavigationContentDescription(uniqueContentDescription);
_toolbar.findViewsWithText(outViews,uniqueContentDescription,View.FIND_VIEWS_WITH_CONTENT_DESCRIPTION);
if (outViews.isEmpty())
if (BuildConfig.DEBUG)
throw new RuntimeException(
"You should call this function only when the toolbar already has views");
else
break;
outViews.get(0).setRotation(180f);
break;
}
_toolbar.setNavigationContentDescription(previousDesc);
}
//
return super.onCreateOptionsMenu(menu);
}
It seems this view doesn't have an ID
You're right, the navigation view is created programmatically and never sets an id. But you can still find it by using View.findViewsWithText.
View.findViewsWithText comes with two flags:
View.FIND_VIEWS_WITH_TEXT
View.FIND_VIEWS_WITH_CONTENT_DESCRIPTION
The navigation view's default content description is "Navigate up" or the resource id is abc_action_bar_up_description for AppCompat and action_bar_up_description for the framework's, but you can easily apply your own using Toolbar.setNavigationContentDescription.
Here's an example implementation:
final Toolbar toolbar = ...;
toolbar.setNavigationContentDescription("up");
setActionBar(toolbar);
final ArrayList<View> outViews = Lists.newArrayList();
toolbar.findViewsWithText(outViews, "up", View.FIND_VIEWS_WITH_CONTENT_DESCRIPTION);
outViews.get(0).setRotation(180f);
Results
I used the following hack to change the homeAsupIndicator programmatically.
int upId = Resources.getSystem().getIdentifier("up", "id", "android");
if (upId > 0) {
ImageView up = (ImageView) findViewById(upId);
up.setImageResource(R.drawable.ic_action_bar_menu);
up.setPadding(0, 0, 20, 0);
}
But this is not working on most new phones (HTC One, Galaxy S3, etc). Is there a way that can be changed uniformly across devices. I need it to be changed only on home screen. Other screens would have the default one. So cannot use the styles.xml
This is what i did to acheive the behavior. I inherited the base theme and created a new theme to use it as a theme for the specific activity.
<style name="CustomActivityTheme" parent="AppTheme">
<item name="android:homeAsUpIndicator">#drawable/custom_home_as_up_icon</item>
</style>
and in the android manifest i made the activity theme as the above.
<activity
android:name="com.example.CustomActivity"
android:theme="#style/CustomActivityTheme" >
</activity>
works great. Will update again when i check on all devices I have. Thanks #faylon for pointing in the right direction
The question was to change dynamically the Up Home Indicator, although this answer was accepting and it is about Themes and Styles. I found a way to do this programmatically, according to Adneal's answer which gives me the clue and specially the right way to do. I used the below snippet code and it works well on (tested) devices with APIs mentioned here.
For lower APIs, I use R.id.up which is not available on higher API. That's why, I retrieve this id by a little workaround which is getting the parent of home button (android.R.id.home) and its first child (android.R.id.up):
if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.ICE_CREAM_SANDWICH) {
// get the parent view of home (app icon) imageview
ViewGroup home = (ViewGroup) findViewById(android.R.id.home).getParent();
// get the first child (up imageview)
( (ImageView) home.getChildAt(0) )
// change the icon according to your needs
.setImageResource(R.drawable.custom_icon_up));
} else {
// get the up imageview directly with R.id.up
( (ImageView) findViewById(R.id.up) )
.setImageResource(R.drawable.custom_icon_up));
}
Note: If you don't use the SDK condition, you will get some NullPointerException.
API 18 has new methods ActionBar.setHomeAsUpIndicator() - unfortunately these aren't supported in the support library at this moment
http://developer.android.com/reference/android/app/ActionBar.html#setHomeAsUpIndicator(android.graphics.drawable.Drawable)
edit: these are now supported by the support library
http://developer.android.com/reference/android/support/v7/app/ActionBar.html#setHomeAsUpIndicator(android.graphics.drawable.Drawable)
All you need to do is to use this line of code:
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
This will change the icon with the up indicator. To disable it later, just call this function again and pass false as the param.
The solution by checking Resources.getSystem() doesn't work on all devices, A better solution to change the homeAsUpIndicator is to set it #null in style and change the logo resource programmatically.
Below is my code from style.xml
<style name="Theme.HomeScreen" parent="AppBaseTheme">
<item name="displayOptions">showHome|useLogo</item>
<item name="homeAsUpIndicator">#null</item>
<item name="android:homeAsUpIndicator">#null</item>
</style>
In code you can change the logo using setLogo() method.
getSupportActionBar().setLogo(R.drawable.abc_ic_ab_back_holo_light); //for ActionBarCompat
getActionBar().setLogo(R.drawable.abc_ic_ab_back_holo_light); //for default actionbar for post 3.0 devices
Also note that the Android API 18 has methods to edit the homeAsUpIndicator programatically, refer documentation.
You can achieve this in an easier way. Try to can change the homeAsUpIndicator attribute of actionBarStyle in your theme.xml and styles.xml.
If you want some padding, just add some white space in your image.
You can try this:
this.getSupportActionBar().setHomeAsUpIndicator( R.drawable.actionbar_indicator ); //for ActionBarCompat
this.getActionBar().setHomeAsUpIndicator( R.drawable.actionbar_indicator ); //for default actionbar for post 3.0 devices
If you need change the position of the icon, you must create a drawable file containing a "layer-list" like this:
actionbar_indicator.xml
<?xml version="1.0" encoding="utf-8"?>
<layer-list
xmlns:android="http://schemas.android.com/apk/res/android" >
<item
android:drawable="#drawable/indicator"
android:right="5dp"
android:left="10dp" />
</layer-list>
use getActionBar().setCustomView(int yourView); because ActionBar haven't method to change homeUp icon!
Adding to Fllo answer Change the actionbar homeAsUpIndicator Programamtically
I was able to use this hack on Android 4+ but could not understand why the up/home indicator was back to the default one when search widget was expanded. Looking at the view hierarchy, turns out that the up/home indicator + icon section of the action bar has 2 implementations and of course the first on is the one for when the search widget is not expanded. So here is the code I used to work around this and get the up/home indicator changed in both cases.
mSearchItem.setOnActionExpandListener(new MenuItem.OnActionExpandListener() {
#Override
public boolean onMenuItemActionExpand(MenuItem item) {
// https://stackoverflow.com/questions/17585892/change-the-actionbar-homeasupindicator-programamtically
int actionBarId = getResources().getIdentifier("android:id/action_bar", null, null);
View view = getActivity().getWindow().getDecorView().findViewById(actionBarId);
if (view == null
|| !(view instanceof ViewGroup)) {
return true;
}
final ViewGroup actionBarView = (ViewGroup)view;
// The second home view is only inflated after
// setOnActionExpandListener() is first called
actionBarView.post(new Runnable() {
#Override
public void run() {
//The 2 ActionBarView$HomeView views are always children of the same view group
//However, they are not always children of the ActionBarView itself
//(depends on OS version)
int upId = getResources().getIdentifier("android:id/up", null, null);
View upView = actionBarView.findViewById(upId);
ViewParent viewParent = upView.getParent();
if (viewParent == null) {
return;
}
viewParent = viewParent.getParent();
if (viewParent == null
|| !(viewParent instanceof ViewGroup)) {
return;
}
ViewGroup viewGroup = (ViewGroup) viewParent;
int childCount = viewGroup.getChildCount();
for (int i = 0; i < childCount; i++) {
View childView = viewGroup.getChildAt(i);
if (childView instanceof ViewGroup) {
ViewGroup homeView = (ViewGroup) childView;
upView = homeView.findViewById(upId);
if (upView != null
&& upView instanceof ImageView) {
Drawable upDrawable = getResources().getDrawable(R.drawable.ic_ab_back_holo_dark_am);
upDrawable.setColorFilter(accentColorInt, PorterDuff.Mode.MULTIPLY);
((ImageView) upView).setImageDrawable(upDrawable);
}
}
}
}
});
If someone uses the library support-v7 appcompat, you can directly call this method:
getSupportActionBar().setHomeAsUpIndicator(int redId)
In other case you can use this solution:
https://stackoverflow.com/a/23522910/944630
If you are using DrawerLayout with ActionBarDrawerToggle, then check out this answer.
this.getSupportActionBar().setDisplayUseLogoEnabled(true);
this.getSupportActionBar().setLogo(R.drawable.about_selected);
Also you can define the logo in manifest in attribute android:logo of and tags and set in theme that you want to use logo instead of app icon in the action bar.