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.
Related
I currently have an AppCompatActivity and I want to be able to switch its layout using one of the menu buttons I have set up.
I am able to do that currently using setContentView, however in order to then switch back to the original View displayed, I need to know which one is currently displayed.
How do I go about getting the current ID of the layout file being displayed?
This is what I have currently, the logic is okay but the code doesn't seem to work:
View currentLayout = findViewById(android.R.id.content);
int currentLayoutID = currentLayout.getId();
if (currentLayoutID == R.layout.two) {
setContentView(R.layout.one);
} else if (currentLayoutID == R.layout.one) {
setContentView(R.layout.two);
}
You can use findViewById to find a particular view that exists only in the one which is currently. If findViewById doesn't return null, that means you were viewing that particular layout.
You compare the Id of a view with the layout name:
int currentLayoutID = currentLayout.getId();
if (currentLayoutID == R.layout.two) {
I would introduce a simple class attribute which store the current chosen layout:
private static final int CUR_LAYOUT_ONE = 1;
private static final int CUR_LAYOUT_TWO = 2;
private int currentLayoutID;
// ....
if (currentLayoutID == CUR_LAYOUT_TWO) {
setContentView(R.layout.one);
currentLayoutID = CUR_LAYOUT_ONE;
} else if (currentLayoutID == R.layout.one) {
setContentView(R.layout.two);
currentLayoutID = CUR_LAYOUT_TWO;
}
Maybe you need some additional onSaveInstanceState()-behaviour. Depends on your use case.
if (currentLayoutID == R.layout.two) {
setContentView(R.layout.one);
} else if (currentLayoutID == R.layout.one) {
setContentView(R.layout.two);
}
You are comparing the id to the R.layout. Those are two different entries in the R file. You need to compare the the actual Ids you've given your views. Usually you set them in the xml file.
For instance R.id.layout1
Maybe you should consider using ViewSwitcher. This will be a lot faster then setContentView
http://developer.android.com/reference/android/widget/ViewSwitcher.html
You just define ViewSwitcher as the parent of your views (you can switch between 2 views only) in xml like this:
<ViewSwitcher
android:id="#+id/viewSwitcher"
android:layout_width="fill_parent"
android:layout_height="fill_parent">
and you programatically switch between views like this:
switcher.setDisplayedChild(1);
I'm using an activity with a webview and to keep it from refreshing whenever the device is rotated, I have android:configChanges="orientation|screenSize" in AndroidManifest.xml. The problem is that whenever the device is rotated, the changes I have made to the status bar dissapear. Does anyone know how to keep the webview from refreshing whenever rotated AND keep the changes I've made in the status bar?
This is the method that I use to make the changes to the statusbar
public static void changeActionBarFont(Activity activity) {
Typeface slab = Typeface.createFromAsset(activity.getAssets(),
"RobotoSlab.ttf");
int actionBarTitle = Resources.getSystem().getIdentifier(
"action_bar_title", "id", "android");
int actionBarSubTitle = Resources.getSystem().getIdentifier(
"action_bar_subtitle", "id", "android");
if (0 == actionBarTitle & 0 == actionBarSubTitle) {
actionBarTitle = com.actionbarsherlock.R.id.abs__action_bar_title;
actionBarSubTitle = com.actionbarsherlock.R.id.abs__action_bar_subtitle;
}
TextView title = (TextView) activity.getWindow().findViewById(
actionBarTitle);
TextView subtitle = (TextView) activity.getWindow().findViewById(
actionBarSubTitle);
if (title != null | subtitle != null) {
title.setTypeface(slab);
subtitle.setTypeface(slab);
subtitle.setTextColor(Color.parseColor("#FFFFFFFF"));
}
}
Edit: Removeing the configChanges from the AndroidManifest does in fact fix the problem with the ActionBar, but I need them to keep the webview from reloading whenever the device is rotated. Anyone have any ideas as to how I can keep them both?
It may not be what you want to hear right now, but it is better to try to recreate the layout in the new orientation, rather than just preventing the orientation change.
In your onCreate check whether there is a saved instance (as a result of the orientation change) e.g.
if (savedInstanceState == null) {
//recreate the current state
}
else {
//normal start
}
You might need to retain some values (either in Shared Prefs or onSavedInstanceState).
This approach is more difficult than locking the orientation, but it is a better approach in the long run and is well worth the investment (extra effort).
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.
I'm searching for a possibilitie to adjust the text color of the datepicker widget in an android honeycomb app. I knew that the widget inherent the global text-color which is white in my case, but i need a black text-color for the datepicker as the background here is light grey.
Anyone know how to fix this?
DONE IT
Did it in a Theme in the application styles.xml (basically set a style on all EditText fields)
I have this in /values-v11/ so it only affects >HC
<?xml version="1.0" encoding="utf-8"?>
<resources xmlns:android="http://schemas.android.com/apk/res/android">
<style name="Theme.SelectDate" parent="#android:style/Theme.Holo.NoActionBar">
<item name="android:editTextStyle">#style/Widget.EditText.Black</item>
</style>
<style name="Widget.EditText.Black" parent="#android:style/Widget.EditText">
<item name="android:textColor">#color/black</item>
</style>
</resources>
Then in my AndroidManifest, for the Activity that uses the DatePicker:
<activity
android:name=".ui.phone.SelectDateActivity"
android:label="Date Selection"
android:screenOrientation="portrait"
android:theme="#style/Theme.SelectDate" />
That's it!
My Working Out:
I came to this conclusion by checking the DatePicker source:
https://github.com/android/platform_frameworks_base/blob/master/core/res/res/layout/date_picker.xml
That showed me the DatePicker used NumberPicker
https://github.com/android/platform_frameworks_base/blob/master/core/res/res/layout/number_picker.xml
https://github.com/android/platform_frameworks_base/blob/master/core/res/res/layout/number_picker_with_selector_wheel.xml
The NumberPicker uses an EditText
You can therefore style an EditText
android : how to change the style of edit text?
And if you search in this file for "editText" you will see you can set a style on all edittext fields in one Activity!
https://github.com/android/platform_frameworks_base/blob/master/core/res/res/values/themes.xml
You override this item:
<item name="editTextStyle">#android:style/Widget.EditText</item>
I have found this solution: debugging DatePicker object, I get the object jerarqy. Maybe it's not an elegant solution but it works:
private void setNumberPickerProperties(DatePicker dp)
{
LinearLayout l = (LinearLayout)dp.getChildAt(0);
if(l!=null)
{
l = (LinearLayout)l.getChildAt(0);
if(l!=null)
{
for(int i=0;i<3;i++)
{
NumberPicker np = (NumberPicker)l.getChildAt(i);
if(np!=null)
{
EditText et = (EditText)np.getChildAt(1);
et.setTextColor(Color.BLACK);
}
}
}
}
}
Hi there :) There is an EditText widget somewhere within the datepicker widget. You just have to find it. You can do this by using some creative coding and start searching through the childrens of the datepicker widget using methods like getChildAt(index) and getChildCount() and then loop through it.
You can also do something like this, but i'm not sure that it will work on all devices, better loop through the datepickers children:
DatePicker picker;
ViewGroup childpicker;
childpicker = (ViewGroup) findViewById(Resources.getSystem().getIdentifier("month" /*rest is: day, year*/, "id", "android"));
EditText textview = (EditText) picker.findViewById(Resources.getSystem().getIdentifier("timepicker_input", "id", "android"));
textview.setTextColor(Color.GREEN);
I hope this helps :)
Hmm I did it like this:
private void hackDatePickerTextColorToBlack(){
setTextColorBlack(datePicker);
}
private static void setTextColorBlack(ViewGroup v) {
int count = v.getChildCount();
for (int i = 0; i < count; i++) {
View c = v.getChildAt(i);
if(c instanceof ViewGroup){
setTextColorBlack((ViewGroup) c);
} else
if(c instanceof TextView){
((TextView) c).setTextColor(Color.BLACK);
}
}
}
This changes the text color to black but careful with recursion this could take some time.
Also when the date picker is used the text goes back to white so that sucks!
FYI here's the source for DatePicker: https://github.com/android/platform_frameworks_base/blob/master/core/res/res/layout/date_picker.xml
The EditTexts are NumberPickers
I had a similar issue, although I was looking to change the text size, but that's a minor detail. I used the same process to pick apart the View hierarchy and change the font size. However, once a month (or day or year) was changed, the font changed back to the original value. Great for viewing, bad for editing. I took the next step and added a change listener. Now when the value gets changed, it pops back to the preferred font size:
public void setFontSize(final int size) {
LinearLayout l = (LinearLayout) mPicker.getChildAt(0);
if (l != null) {
l = (LinearLayout) l.getChildAt(0);
if (l != null) {
for (int i = 0; i < 3; i++) {
NumberPicker np = (NumberPicker) l.getChildAt(i);
for (int x = 0; x < np.getChildCount(); x++) {
View view = np.getChildAt(x);
if ((view != null) && (view instanceof TextView)) {
final TextView tv = (TextView) view;
tv.setTextSize(size);
tv.setOnEditorActionListener(new OnEditorActionListener() {
public boolean onEditorAction(TextView v,
int actionId, KeyEvent event) {
tv.setTextSize(size);
return false;
}
});
}
}
}
}
}
}
I have a field where the user can type a search query in the action bar of the application. This is declared in the action bar using a menu inflate in the Activity:
<menu
xmlns:android="http://schemas.android.com/apk/res/android"
>
<item
android:id="#+id/action_search"
android:showAsAction="ifRoom"
android:actionViewClass="android.widget.SearchView"
android:title="#string/search"
></item>
</menu>
I need to customize the appearance of the SearchView (for instance background and text color). So far I could not find a way to do it using XML (using styles or themes).
Is my only option to do it in the code when inflating the menu?
Edit #1: I have tried programmatically but I cannot get a simple way to set the text color. Plus when I do searchView.setBackgroundResource(...) The background is set on the global widget, (also when the SearchView is iconified).
Edit #2: Not much information on the Search Developer Reference either
Seibelj had an answer that is good if you want to change the icons. But you'll need to
do it for every API version. I was using ICS with ActionBarSherlock and it didn't do justice for me but it did push me in the correct direction.
Below I change the text color and hint color. I showed how you might go about changing the
icons too, though I have no interest in that for now (and you probably want to use the default icons anyways to be consistent)
#Override
public boolean onPrepareOptionsMenu(Menu menu) {
// Set up the search menu
SearchView searchView = (SearchView)menu.findItem(R.id.action_search).getActionView();
traverseView(searchView, 0);
return true;
}
private void traverseView(View view, int index) {
if (view instanceof SearchView) {
SearchView v = (SearchView) view;
for(int i = 0; i < v.getChildCount(); i++) {
traverseView(v.getChildAt(i), i);
}
} else if (view instanceof LinearLayout) {
LinearLayout ll = (LinearLayout) view;
for(int i = 0; i < ll.getChildCount(); i++) {
traverseView(ll.getChildAt(i), i);
}
} else if (view instanceof EditText) {
((EditText) view).setTextColor(Color.WHITE);
((EditText) view).setHintTextColor(R.color.blue_trans);
} else if (view instanceof TextView) {
((TextView) view).setTextColor(Color.WHITE);
} else if (view instanceof ImageView) {
// TODO dissect images and replace with custom images
} else {
Log.v("View Scout", "Undefined view type here...");
}
}
adding my take on things which is probably a little more efficient and safe across different android versions.
you can actually get a numeric ID value from a string ID name. using android's hierarchyviewer tool, you can actually find the string IDs of the things you are interested in, and then just use findViewById(...) to look them up.
the code below sets the hint and text color for the edit field itself. you could apply the same pattern for other aspects that you wish to style.
private static synchronized int getSearchSrcTextId(View view) {
if (searchSrcTextId == -1) {
searchSrcTextId = getId(view, "android:id/search_src_text");
}
return searchSrcTextId;
}
private static int getId(View view, String name) {
return view.getContext().getResources().getIdentifier(name, null, null);
}
#TargetApi(11)
private void style(View view) {
ImageView iv;
AutoCompleteTextView actv = (AutoCompleteTextView) view.findViewById(getSearchSrcTextId(view));
if (actv != null) {
actv.setHint(getDecoratedHint(actv,
searchView.getContext().getResources().getString(R.string.titleApplicationSearchHint),
R.drawable.ic_ab_search));
actv.setTextColor(view.getContext().getResources().getColor(R.color.ab_text));
actv.setHintTextColor(view.getContext().getResources().getColor(R.color.hint_text));
}
}
You can use the attribute android:actionLayout instead which lets you specify a layout to be inflated. Just have a layout with your SearchView and you won't have to modify anything really.
As to changing text style on the SearchView that is probably not possible as the SearchView is a ViewGroup. You should probably try changing text color via themes instead.
In case anyone wants to modify the views directly, here is how you can change the colors/fonts/images and customize the search box to your pleasure. It is wrapped in a try/catch in case there are differences between versions or distributions, so it won't crash the app if this fails.
// SearchView structure as we currently understand it:
// 0 => linearlayout
// 0 => textview (not sure what this does)
// 1 => image view (the search icon before it's pressed)
// 2 => linearlayout
// 0 => linearlayout
// 0 => ImageView (Search icon on the left of the search box)
// 1 => SearchView$SearchAutoComplete (Object that controls the text, subclass of TextView)
// 2 => ImageView (Cancel icon to the right of the text entry)
// 1 => linearlayout
// 0 => ImageView ('Go' icon to the right of cancel)
// 1 => ImageView (not sure what this does)
try {
LinearLayout ll = (LinearLayout) searchView.getChildAt(0);
LinearLayout ll2 = (LinearLayout) ll.getChildAt(2);
LinearLayout ll3 = (LinearLayout) ll2.getChildAt(0);
LinearLayout ll4 = (LinearLayout) ll2.getChildAt(1);
TextView search_text = (TextView) ll3.getChildAt(1);
search_text.setTextColor(R.color.search_text);
ImageView cancel_icon = (ImageView)ll3.getChildAt(2);
ImageView accept_icon = (ImageView)ll4.getChildAt(0);
cancel_icon.setBackgroundDrawable(d);
accept_icon.setBackgroundDrawable(d);
} catch (Throwable e) {
Log.e("SearchBoxConstructor", "Unable to set the custom look of the search box");
}
This example shows changing the text color and the background colors of the cancel/accept images. searchView is a SearchView object already instantiated with it's background color:
Drawable d = getResources().getDrawable(R.drawable.search_widget_background);
searchView.setBackgroundDrawable(d);
Here is the drawable code:
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle" >
<solid android:color="#color/white" />
</shape>
Obviously, this is hacky, but it will work for now.
From ICS this is doable using themes and styles. I'm using ActionBarSherlock which makes it applicable also for HC and below.
Add a style to define "android:textColorHint":
<style name="Theme.MyHolo.widget" parent="#style/Theme.Holo">
<item name="android:textColorHint">#color/text_hint_corp_dark</item>
</style>
Apply this as "actionBarWidgetTheme" to your theme:
<style name="Theme.MyApp" parent="#style/Theme.Holo.Light.DarkActionBar">
...
<item name="android:actionBarWidgetTheme">#style/Theme.MyHolo.widget</item>
</style>
Presto! Make sure that you use getSupportActionBar().getThemedContext() (or getSupportActionBar() for ActionBarSherlock) if any widgets are initiated where you might have other themes in effect.
How do you inflate the menu xml in your Activity? if you inflate the menu by using getMenuInflator() in your Activity, then the menu and also the searchView get the themed context, that have attached to the activity.
#Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater.inflate(R.menu.search_action_menu, menu);
}
if you check the source code of Activity.getMenuInflator() at API-15, you can see the themed context codes. Here it is.
*/
public MenuInflater getMenuInflater() {
// Make sure that action views can get an appropriate theme.
if (mMenuInflater == null) {
initActionBar();
if (mActionBar != null) {
mMenuInflater = new MenuInflater(mActionBar.getThemedContext());
} else {
mMenuInflater = new MenuInflater(this);
}
}
return mMenuInflater;
}