Okay, a quick background : I've been developing a simple music player app and to enhance the user experience (especially on newer devices) I decided to implement a tinted StatusBar using the fabled SystemBarTint library.
Imported the .JAR, followed the usage directions, modified the application theme and voila! My app looks fancier than an 10-years old show bike. But wait, there's more!
As you can see, the ListView is now covered by the ActionBar and its tabs. I did my homework and found this workaround -- which works, sort of.
My ListView is no longer covered by the ActionBar but it's still covered by the tabs!
How do I sort this one out?
This is my BaseActivity onCreate method which activates the SystemBarTint library :
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
SystemBarTintManager tintManager = new SystemBarTintManager(this);
tintManager.setStatusBarTintEnabled(true);
tintManager.setTintColor(getResources().getColor(R.color.wowza_orange));
}
..and this is the workaround, supplied in my Fragment (which houses the ListView) :
#Override
public void onViewCreated(View view, Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
musicList.setClipToPadding(false); // musicList is my ListView instance.
setInsets(getActivity(), (View) musicList);
}
public static void setInsets(Activity context, View view) {
SystemBarTintManager tintManager = new SystemBarTintManager(context);
SystemBarTintManager.SystemBarConfig config = tintManager.getConfig();
view.setPadding(0, config.getPixelInsetTop(true),
config.getPixelInsetRight(), config.getPixelInsetBottom());
}
Thanks in advance!
Its a little late, but I was facing the same problem. My solution is add this method:
private int getActionBarHeight() {
int actionBarHeight =0;
final TypedValue tv = new TypedValue();
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) {
if (context.getTheme().resolveAttribute(android.R.attr.actionBarSize, tv, true))
actionBarHeight = TypedValue.complexToDimensionPixelSize(tv.data, getResources().getDisplayMetrics());
} else if (context.getTheme().resolveAttribute(R.attr.actionBarSize, tv, true))
actionBarHeight = TypedValue.complexToDimensionPixelSize(tv.data, getResources().getDisplayMetrics());
return actionBarHeight;
}
and replace:
view.setPadding(0, config.getPixelInsetTop(true),
config.getPixelInsetRight(), config.getPixelInsetBottom());
with:
view.setPadding(0, config.getPixelInsetTop(true) + getActionBarHeight(),
config.getPixelInsetRight(), config.getPixelInsetBottom());
Related
I try to make android toolbar transition from recyclerview item name to toolbar title (text). I create it like Alex Lockwood recommendation. In appcompat-v7:22 all works fine, when I update to appcompat-v7:23 transition does't work.
Does somebody know whats happen with appcompat-v7:23?
My code (with appcompat-v7:22 all works fine):
private void startDataActivity(Activity activity, View toolbar,
Category category) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
View decor = activity.getWindow().getDecorView();
View statusBar = decor.findViewById(android.R.id.statusBarBackground);
View navBar = decor.findViewById(android.R.id.navigationBarBackground);
List<Pair> participants = new ArrayList<>(3);
participants.add(new Pair<>(toolbar, activity.getString(R.string.transition_toolbar)));
addNonNullViewToTransitionParticipants(statusBar, participants);
addNonNullViewToTransitionParticipants(navBar, participants);
ActivityOptions sceneTransitionAnimation = ActivityOptions
.makeSceneTransitionAnimation(activity,
participants.toArray(new Pair[participants.size()]));
final Bundle transitionBundle = sceneTransitionAnimation.toBundle();
activity.startActivity(ShowCategoryActivity.getStartIntent(activity,
category.getId()), transitionBundle);
} else {
activity.startActivity(ShowCategoryActivity.getStartIntent(activity,
category.getId()));
}
}
With the previous versions of AppCompat it was easy to get the ActionBar's title TextView and modify it.
There is the method I was using:
private TextView getActionBarTitleView() {
int id = getResources().getIdentifier("action_bar_title", "id", "android");
return (TextView) findViewById(id);
}
And then to change the alpha's value of the title:
getActionBarTitleView().setAlpha(ratio*255);
Now for some reasons, "action_bar_title" with the lastest AppCompat version isn't working anymore. When I tried to use my method, it returned me "null". Tried to use other id's of the ActionBar but I didn't find the good one.
I saw 1 post on StackOverflow from Ahmed Nawara and the only way he found for the moment was to do an Iteration over the Toolbar's children views and whenever a TexView is found, compare it's text value with the toolbar.getTitle() to make sure that's the TexView we're looking at.
If someone could help me to integrate this solution in my case because I don't know how to do it actually.
I guess you got your method from Flavien Laurent's post on making the ActionBar not boring. If you take a closer look, he detailled another technique to set the ActionBar title's alpha inspired by Cyril Mottier.
It uses a custom AlphaForegroundColorSpan class that extends ForegroundColorSpan :
public class AlphaForegroundColorSpan extends ForegroundColorSpan
{
private float mAlpha;
public AlphaForegroundColorSpan(int color)
{
super(color);
}
public AlphaForegroundColorSpan(Parcel src)
{
super(src);
mAlpha = src.readFloat();
}
public void writeToParcel(Parcel dest, int flags)
{
super.writeToParcel(dest, flags);
dest.writeFloat(mAlpha);
}
#Override
public void updateDrawState(TextPaint ds)
{
ds.setColor(getAlphaColor());
}
public void setAlpha(float alpha)
{
mAlpha = alpha;
}
public float getAlpha()
{
return mAlpha;
}
private int getAlphaColor()
{
int foregroundColor = getForegroundColor();
return Color.argb((int) (mAlpha * 255), Color.red(foregroundColor), Color.green(foregroundColor), Color.blue(foregroundColor));
}
}
Then, using a SpannableString, you just set the alpha to the AlphaForegroundColorSpan, and then set this AlphaForegroundColorSpan to the SpannableString :
public void onCreate(Bundle savedInstanceState)
{
...
spannableString = new SpannableString("ActionBar title");
alphaForegroundColorSpan = new AlphaForegroundColorSpan(0xffffffff);
...
}
private void setActionBarTitle(int newAlpha)
{
alphaForegroundColorSpan.setAlpha(newAlpha);
spannableString.setSpan(alphaForegroundColorSpan, 0, spannableString.length(), Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
getSupportActionBar().setTitle(spannableString);
}
Hope it helps. If it's not clear enough, give another look to Flavient Laurent's post!
With AppCompat you should use the new toolbar including the toolbar.xml in the activity layout and importing android.support.v7.widget.Toolbar.
In your activity, OnCreate you will have:
mtoolbar = (Toolbar) findViewById(R.id.toolbar);
setSupportActionBar(mtoolbar);
getActionBarTitleView().setAlpha(ratio*255);
at this point you are almost done and you can use reflection to access to the view (remember to import java.lang.reflect.field;) and your function will be:
private TextView getActionBarTitleView() {
TextView yourTextView = null;
try {
Field f = mToolBar.getClass().getDeclaredField("mTitleTextView");
f.setAccessible(true);
yourTextView = (TextView) f.get(mToolBar);
} catch (NoSuchFieldException e) {
} catch (IllegalAccessException e) {
}
return yourTextView;
}
How do I change the color of the split actionbar in code, and not in xml? My user can pick the color of the actionbar, and I would like it so they could also change the color of the split action bar (the actionbar that appears at the bottom of the screen).
I'm implementing splitActionBar using android:uiOptions="splitActionBarWhenNarrow" in android manifest
so far I'm trying this, but it's not working
final int splitBarId = getResources().getIdentifier("split_action_bar", "id", "android");
final View splitActionBar = findViewById(splitBarId);
if (splitActionBar != null) {
splitActionBar.setBackgroundDrawable(new ColorDrawable(Color.parseColor(actionbar_colors)));
}
}
Use this to change the split actionbar color
getActionBar().setSplitBackgroundDrawable(new ColorDrawable(Color.parseColor("#33B5E5")));
Or use this if you're using support actionbar
getSupportActionBar().setSplitBackgroundDrawable(new ColorDrawable(Color.parseColor("#33B5E5")));
Source: http://scriptedpapers.com/2014/09/25/android-implement-spilit-action-bar-change-its-background-color/
The framework doesn't provide a way to change it programmatically; however, you can use Resources.getIdentifier to find the View and adjust the background Drawable from there.
The internal id is split_action_bar.
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
...
final int splitBarId = getResources().getIdentifier("split_action_bar", "id", "android");
final View splitActionBar = findViewById(splitBarId);
if (splitActionBar != null) {
// Adjust the background drawable
}
}
Update
Evidently there's ActionBar.setSplitBackgroundDrawable. Definitely use that callback rather than Resources.getIdentifier.
Here's a screenshot of the results:
This should work
ActionBar mActionBar = getActionBar();
mActionBar.setBackgroundDrawable(new ColorDrawable(0xff00DDED));
mActionBar.setDisplayShowTitleEnabled(false);
mActionBar.setDisplayShowTitleEnabled(true);
Action Bar compatibility has been added into support library, revision 18. It now has ActionBarActivity class for creating activities with Action Bar on older versions of Android.
Is there any way to add Action Bar from support library into PreferenceActivity?
Previously I used ActionBarSherlock and it has SherlockPreferenceActivity.
EDIT: In appcompat-v7 22.1.0 Google added the AppCompatDelegate abstract class as a delegate you can use to extend AppCompat's support to any activity.
Use it like this:
...
import android.support.v7.app.ActionBar;
import android.support.v7.app.AppCompatDelegate;
import android.support.v7.widget.Toolbar;
...
public class SettingsActivity extends PreferenceActivity {
private AppCompatDelegate mDelegate;
#Override
protected void onCreate(Bundle savedInstanceState) {
getDelegate().installViewFactory();
getDelegate().onCreate(savedInstanceState);
super.onCreate(savedInstanceState);
}
#Override
protected void onPostCreate(Bundle savedInstanceState) {
super.onPostCreate(savedInstanceState);
getDelegate().onPostCreate(savedInstanceState);
}
public ActionBar getSupportActionBar() {
return getDelegate().getSupportActionBar();
}
public void setSupportActionBar(#Nullable Toolbar toolbar) {
getDelegate().setSupportActionBar(toolbar);
}
#Override
public MenuInflater getMenuInflater() {
return getDelegate().getMenuInflater();
}
#Override
public void setContentView(#LayoutRes int layoutResID) {
getDelegate().setContentView(layoutResID);
}
#Override
public void setContentView(View view) {
getDelegate().setContentView(view);
}
#Override
public void setContentView(View view, ViewGroup.LayoutParams params) {
getDelegate().setContentView(view, params);
}
#Override
public void addContentView(View view, ViewGroup.LayoutParams params) {
getDelegate().addContentView(view, params);
}
#Override
protected void onPostResume() {
super.onPostResume();
getDelegate().onPostResume();
}
#Override
protected void onTitleChanged(CharSequence title, int color) {
super.onTitleChanged(title, color);
getDelegate().setTitle(title);
}
#Override
public void onConfigurationChanged(Configuration newConfig) {
super.onConfigurationChanged(newConfig);
getDelegate().onConfigurationChanged(newConfig);
}
#Override
protected void onStop() {
super.onStop();
getDelegate().onStop();
}
#Override
protected void onDestroy() {
super.onDestroy();
getDelegate().onDestroy();
}
public void invalidateOptionsMenu() {
getDelegate().invalidateOptionsMenu();
}
private AppCompatDelegate getDelegate() {
if (mDelegate == null) {
mDelegate = AppCompatDelegate.create(this, null);
}
return mDelegate;
}
}
No more hacking. Code taken from AppCompatPreferenceActivity.java.
There is currently no way to achieve with AppCompat. I've opened a bug internally.
I have managed to create a workaround similar to what the Google Play Store uses. Link to Original Answer
Please find the GitHub Repo: Here
Very Similar to your own code but added xml to allow for set title:
Continuing to use PreferenceActivity:
settings_toolbar.xml :
<?xml version="1.0" encoding="utf-8"?>
<android.support.v7.widget.Toolbar
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="#+id/toolbar"
app:theme="#style/ThemeOverlay.AppCompat.Dark.ActionBar"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:minHeight="?attr/actionBarSize"
app:navigationContentDescription="#string/abc_action_bar_up_description"
android:background="?attr/colorPrimary"
app:navigationIcon="?attr/homeAsUpIndicator"
app:title="#string/action_settings"
/>
SettingsActivity.java :
public class SettingsActivity extends PreferenceActivity {
#Override
protected void onPostCreate(Bundle savedInstanceState) {
super.onPostCreate(savedInstanceState);
LinearLayout root = (LinearLayout)findViewById(android.R.id.list).getParent().getParent().getParent();
Toolbar bar = (Toolbar) LayoutInflater.from(this).inflate(R.layout.settings_toolbar, root, false);
root.addView(bar, 0); // insert at top
bar.setNavigationOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
finish();
}
});
}
}
Result :
UPDATE (Gingerbread Compatibility) :
As pointed out here, Gingerbread Devices are returning NullPointerException on this line:
LinearLayout root = (LinearLayout)findViewById(android.R.id.list).getParent().getParent().getParent();
FIX:
SettingsActivity.java :
public class SettingsActivity extends PreferenceActivity {
#Override
protected void onPostCreate(Bundle savedInstanceState) {
super.onPostCreate(savedInstanceState);
Toolbar bar;
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.ICE_CREAM_SANDWICH) {
LinearLayout root = (LinearLayout) findViewById(android.R.id.list).getParent().getParent().getParent();
bar = (Toolbar) LayoutInflater.from(this).inflate(R.layout.settings_toolbar, root, false);
root.addView(bar, 0); // insert at top
} else {
ViewGroup root = (ViewGroup) findViewById(android.R.id.content);
ListView content = (ListView) root.getChildAt(0);
root.removeAllViews();
bar = (Toolbar) LayoutInflater.from(this).inflate(R.layout.settings_toolbar, root, false);
int height;
TypedValue tv = new TypedValue();
if (getTheme().resolveAttribute(R.attr.actionBarSize, tv, true)) {
height = TypedValue.complexToDimensionPixelSize(tv.data, getResources().getDisplayMetrics());
}else{
height = bar.getHeight();
}
content.setPadding(0, height, 0, 0);
root.addView(content);
root.addView(bar);
}
bar.setNavigationOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
finish();
}
});
}
}
Any issues with the above let me know!
UPDATE 2: TINTING WORKAROUND
As pointed out in many dev notes PreferenceActivity does not support tinting of elements, however by utilising a few internal classes you CAN achieve this. That is until these classes are removed. (Works using appCompat support-v7 v21.0.3).
Add the following imports:
import android.support.v7.internal.widget.TintCheckBox;
import android.support.v7.internal.widget.TintCheckedTextView;
import android.support.v7.internal.widget.TintEditText;
import android.support.v7.internal.widget.TintRadioButton;
import android.support.v7.internal.widget.TintSpinner;
Then override the onCreateView method:
#Override
public View onCreateView(String name, Context context, AttributeSet attrs) {
// Allow super to try and create a view first
final View result = super.onCreateView(name, context, attrs);
if (result != null) {
return result;
}
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) {
// If we're running pre-L, we need to 'inject' our tint aware Views in place of the
// standard framework versions
switch (name) {
case "EditText":
return new TintEditText(this, attrs);
case "Spinner":
return new TintSpinner(this, attrs);
case "CheckBox":
return new TintCheckBox(this, attrs);
case "RadioButton":
return new TintRadioButton(this, attrs);
case "CheckedTextView":
return new TintCheckedTextView(this, attrs);
}
}
return null;
}
Result:
AppCompat 22.1
AppCompat 22.1 introduced new tinted elements, meaning that there is no longer a need to utilise the internal classes to achieve the same effect as the last update. Instead follow this (still overriding onCreateView):
#Override
public View onCreateView(String name, Context context, AttributeSet attrs) {
// Allow super to try and create a view first
final View result = super.onCreateView(name, context, attrs);
if (result != null) {
return result;
}
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) {
// If we're running pre-L, we need to 'inject' our tint aware Views in place of the
// standard framework versions
switch (name) {
case "EditText":
return new AppCompatEditText(this, attrs);
case "Spinner":
return new AppCompatSpinner(this, attrs);
case "CheckBox":
return new AppCompatCheckBox(this, attrs);
case "RadioButton":
return new AppCompatRadioButton(this, attrs);
case "CheckedTextView":
return new AppCompatCheckedTextView(this, attrs);
}
}
return null;
}
NESTED PREFERENCE SCREENS
A lot of people are experiencing issues with including the Toolbar in nested <PreferenceScreen />s however, I have found a solution!! - After a lot of trial and error!
Add the following to your SettingsActivity:
#SuppressWarnings("deprecation")
#Override
public boolean onPreferenceTreeClick(PreferenceScreen preferenceScreen, Preference preference) {
super.onPreferenceTreeClick(preferenceScreen, preference);
// If the user has clicked on a preference screen, set up the screen
if (preference instanceof PreferenceScreen) {
setUpNestedScreen((PreferenceScreen) preference);
}
return false;
}
public void setUpNestedScreen(PreferenceScreen preferenceScreen) {
final Dialog dialog = preferenceScreen.getDialog();
Toolbar bar;
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.ICE_CREAM_SANDWICH) {
LinearLayout root = (LinearLayout) dialog.findViewById(android.R.id.list).getParent();
bar = (Toolbar) LayoutInflater.from(this).inflate(R.layout.settings_toolbar, root, false);
root.addView(bar, 0); // insert at top
} else {
ViewGroup root = (ViewGroup) dialog.findViewById(android.R.id.content);
ListView content = (ListView) root.getChildAt(0);
root.removeAllViews();
bar = (Toolbar) LayoutInflater.from(this).inflate(R.layout.settings_toolbar, root, false);
int height;
TypedValue tv = new TypedValue();
if (getTheme().resolveAttribute(R.attr.actionBarSize, tv, true)) {
height = TypedValue.complexToDimensionPixelSize(tv.data, getResources().getDisplayMetrics());
}else{
height = bar.getHeight();
}
content.setPadding(0, height, 0, 0);
root.addView(content);
root.addView(bar);
}
bar.setTitle(preferenceScreen.getTitle());
bar.setNavigationOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
dialog.dismiss();
}
});
}
The reason that PreferenceScreen's are such a pain is because they are based as a wrapper dialog, so we need to capture the dialog layout to add the toolbar to it.
Toolbar Shadow
By design importing the Toolbar does not allow for elevation and shadowing in pre-v21 devices, so if you would like to have elevation on your Toolbar you need to wrap it in a AppBarLayout:
`settings_toolbar.xml :
<android.support.design.widget.AppBarLayout
android:layout_width="match_parent"
android:layout_height="wrap_content">
<android.support.v7.widget.Toolbar
.../>
</android.support.design.widget.AppBarLayout>
Not forgetting to add the add the Design Support library as a dependency in build.gradle file:
compile 'com.android.support:support-v4:22.2.0'
compile 'com.android.support:appcompat-v7:22.2.0'
compile 'com.android.support:design:22.2.0'
Android 6.0
I have investigated the reported overlapping issue and I cannot reproduce the issue.
The full code in use as above produces the following:
If I am missing something please let me know via this repo and I will investigate.
Found a PreferenceFragment implementation based on support-v4 Fragment:
https://github.com/kolavar/android-support-v4-preferencefragment
Edit: I just tested it and its working great!
Integrating PreferenceActivity with ABC is not possible, at least for me. I tried the two possibilities I could find but none worked:
Option 1:
ActionBarPreferenceActivity extends PreferenceActivity. When you do this you get restricted by ActionBarActivityDelegate.createDelegate(ActionBarActivity activity). Also you need to implement ActionBar.Callbacks which is not accessible
Option 2:
ActionBarPreferenceActivity extends ActionBarActivity. This approach requires rewriting a whole new PreferenceActivity, PreferenceManager and may be PreferenceFragment which means you need access to hidden classes like com.android.internal.util.XmlUtils
The solution to this can only come from Google devs implementing an ActionBarWrapper that can be added to any activity.
If you really need a preference activity, my advice for now is ActionBarSherlock.
However, I managed to implement it here.
Problem Background:
The OP wants to know how can we put MenuItems in the ActionBar of PreferenceActivity for pre-Honeycomb because Android's support library has a bug which doesn't allow this to happen.
My Solution:
I've found a much cleaner way, than already proposed, to achieve the target (and found it in the Android Docs):
android:parentActivityName
The class name of the logical parent of the
activity. The name here must match the class name given to the
corresponding element's android:name attribute.
The system reads this attribute to determine which activity should be
started when the use presses the Up button in the action bar. The
system can also use this information to synthesize a back stack of
activities with TaskStackBuilder.
To support API levels 4 - 16, you can also declare the parent activity
with a element that specifies a value for
"android.support.PARENT_ACTIVITY". For example:
<activity
android:name="com.example.app.ChildActivity"
android:label="#string/title_child_activity"
android:parentActivityName="com.example.myfirstapp.MainActivity" >
<!-- Parent activity meta-data to support API level 4+ -->
<meta-data
android:name="android.support.PARENT_ACTIVITY"
android:value="com.example.app.MainActivity" />
</activity>
Now do what you would normally do in your onOptionsItemSelected(). Since it's a part of Android Docs, it has no side-affects.
Happy coding. :)
Update:
This solution no longer works if you're targeting Lollipop. If you're using AppCompat, this answer is what you should be looking for.
I was able to get android.app.Actionbar by using getActionBar(). It returned a null value at first... then I went to the manifest and changed the theme to:
android:theme="#style/Theme.AppCompat"
Then I was able to have the actionbar again. I'm assuming this will only work for certain build levels. So you might want to do a check for the build number or check if the value returned is null.
It'll be fine for me because the app I'm working on is for ICS/4.0+.
Now the official answer for this problem has been released. It is the v7/v14 Preference Support library.
See How to use the v7/v14 Preference Support library? for the discussion how to use it.
I'm using ABS vers. 4 and I need to simply change the default "Done" text that is displayed besides the action mode close icon, but I really can't figure out how to do it.
I think that text needs to be customizable for at least two good reasons:
"Done" is not appropriate for all contexts (e.g. "Cancel" could be more appropriate, and I've seen some apps, such as the "My Files" app on Galaxy Tab, use it)
"Done" needs to be localized according to the user's language
Is it possible to do customize that text? If so can anyone tell me how to do it?
Thanks in advance.
EDIT
I've found a temporary workaround, that I post in the following:
private TextView getActionModeCloseTextView() {
// ABS 4.0 defines action mode close button text only for "large" layouts
if ((getResources().getConfiguration().screenLayout &
Configuration.SCREENLAYOUT_SIZE_MASK) ==
Configuration.SCREENLAYOUT_SIZE_LARGE)
{
// retrieves the LinearLayout containing the action mode close button text
LinearLayout action_mode_close_button =
(LinearLayout) getActivity().findViewById(R.id.abs__action_mode_close_button);
// if found, returns its last child
// (in ABS 4.0 there is no other way to refer to it,
// since it doesn't have an id nor a tag)
if (action_mode_close_button != null) return (TextView)
action_mode_close_button.getChildAt(action_mode_close_button.getChildCount() - 1);
}
return null;
}
That's the method I came up with. Please NOTE that it does heavily rely upon the structure of the abs__action_mode_close_item.xml of ABS 4.0.
This works for my scenario, but, as you can see, it cannot be considered sufficiently satisfying to promote it to a real "answer", that's why I only edited my previous post.
Hope that helps someone else, but I also hope that someone could share a better and cleaner solution.
You can use a theme to override the default icon:
<item name="actionModeCloseDrawable">#drawable/navigation_back</item>
<item name="android:actionModeCloseDrawable">#drawable/navigation_back</item>
I edited the code from PacificSky to be able to customize the color and font size of the close button, both in pre ICS and >ICS.
I created a method named customizeActionModeCloseButton
private void customizeActionModeCloseButton() {
int buttonId = Resources.getSystem().getIdentifier("action_mode_close_button", "id", "android");
View v = getGSActivity().findViewById(buttonId);
if (v == null) {
buttonId = R.id.abs__action_mode_close_button;
v = getGSActivity().findViewById(buttonId);
}
if (v == null)
return;
LinearLayout ll = (LinearLayout) v;
if (ll.getChildCount() > 1 && ll.getChildAt(1) != null) {
TextView tv = (TextView) ll.getChildAt(1);
tv.setText(R.string.close_action_mode);
tv.setTextColor(getResources().getColor(R.color.white));
tv.setTextSize(18);
}
}
and I call it just after calling startActionMode()
public boolean onItemLongClick(AdapterView<?> parent, View view, int position, long id) {
actionMode = getActivity().startActionMode(this);
customizeActionModeCloseButton();
return true;
}
It's been a while, but here's a slightly less hacky solution - putting it out there for posterity.
For Android versions < ICS
Put the following line in your application's strings.xml:
<string name="abs__action_mode_done">Cancel</string>
This overrides the TextView's (defined in ActionBarSherlock/res/layout-large/abs__action_mode_close_item.xml) android:text attribute.
For Android versions ICS and above
The native ActionBar functionality is used on ICS and up. You need to find and override the string associated with the done button, using the following code:
int buttonId = Resources.getSystem().getIdentifier("action_mode_close_button", "id", "android");
if (buttonId != 0)
{
View v = findViewById(buttonId);
if (v != null)
{
LinearLayout ll = (LinearLayout)v;
View child = ll.getChildAt(1);
if (child != null)
{
TextView tv = (TextView)child;
tv.setText(R.string.cancel);
}
}
}
Thanks for PacificSky's answer. It's useful for my case.
Something needs to be explained here is that findViewById(buttonId) might return null in some cases such as called in onCreateActionMode() function, because the LinearLayout for ActionMode close button not yet initialized at that time I guess.
I want to hide the action mode close button, so i just sendEmptyMessageDelayed in onCreateActionMode() and call PacificSky's 200ms later. It works for me.
Here is my approach with Java code:
private void customizeActionModeCloseButton(String title, int iconID) {
int buttonId = Resources.getSystem().getIdentifier("action_mode_close_button", "id", "android");
View v = findViewById(buttonId);
if (v == null) {
buttonId = R.id.abs__action_mode_close_button;
v = findViewById(buttonId);
}
if (v == null)
return;
LinearLayout ll = (LinearLayout) v;
if (ll.getChildCount() > 1 && ll.getChildAt(1) != null) {
//custom icon
ImageView img = (ImageView) ll.getChildAt(0);
img.setImageResource(iconID);
//custom text
TextView tv = (TextView) ll.getChildAt(1);
tv.setText(title);
tv.setTextColor(Color.WHITE);
}
}
com.actionbarsherlock.view.ActionMode contains method:
setTitle
It is used to change text near Close Icon in the ActionBar.
ActionMode is available in your com.actionbarsherlock.view.ActionMode.Callback interface implementation methods, like onCreateActionMode.
What you can do - is save incoming ActionMode reference and use it later to change title as your like. Or, if it is not dynamic - you can setup at with your constant in onCreateActionMode.