Using RTL direction in closeButton of android.support.v7.widget.SearchView - android

I'm trying to change direction of SearchView in toolbar, and this is my try
layout.xml
android:layoutDirection="rtl"
menu.xml
<item android:id="#+id/action_search"
android:title="#string/search_hint"
android:icon="#mipmap/ic_search_icon"
app:showAsAction="ifRoom|collapseActionView"
app:actionViewClass="android.support.v7.widget.SearchView" />
Java code:
MenuItem searchItem = menu.findItem(R.id.action_search);
SearchView mSearchView = (SearchView) MenuItemCompat.getActionView(searchItem);
getSupportActionBar().setCustomView(MenuItemCompat.getActionView(searchItem));
mSearchView.setInputType(InputType.TYPE_CLASS_TEXT);
mSearchView.setQueryHint(getString(R.string.search_hint));
mSearchView.setGravity(Gravity.RIGHT);
mSearchView.setTextDirection(View.TEXT_DIRECTION_RTL);
mSearchView.setTextAlignment(View.TEXT_ALIGNMENT_GRAVITY);
mSearchView.setLayoutDirection(View.LAYOUT_DIRECTION_RTL);
mSearchView.setLayoutParams(new ActionBar.LayoutParams(Gravity.RIGHT));
And this is the result, I success added the SearchView to toolbar and is RTL now. But the issue is position of "X" (closeButton) is wrong, the position must be at left.

add this for change x direction:
View xIcon = ((ViewGroup) mSearchView.getChildAt(0)).getChildAt(2);
xIcon.setLayoutDirection(View.LAYOUT_DIRECTION_RTL);

To Support Rtl in your App. you have to set android:supportsRtl="true" in your manifest.xml.
And Most Important point keep in Mind
Change all of your app's "Left/Right" layout properties to Start/End.
In you case you are setting.
mSearchView.setGravity(Gravity.RIGHT);
so change it to
mSearchView.setGravity(Gravity.END);
and also change here this
mSearchView.setLayoutParams(new ActionBar.LayoutParams(Gravity.RIGHT));
to
mSearchView.setLayoutParams(new ActionBar.LayoutParams(Gravity.END));

You can use this method to move closeButton to right in RTL locales:
private static void handleCloseButtonRtlIssue(SearchView searchView) {
((LinearLayout) ((LinearLayout) searchView.getChildAt(0)).getChildAt(2)).getChildAt(1).setLayoutDirection(View.LAYOUT_DIRECTION_LTR);
}

the problem is that when you change layoutDirection to rtl, toolbar itself will become rtl. but layoutDirection for other layouts inside toobar will not change. and editText with close button are in a nested layout.
so you have to find parent layout and change direction for that. if you see inside SearchView layout file. you'll find that exit button is inside a layout with search_plate id
so in onCreateOptionsMenu after setup SearchView do this
kotlin
mSearchView.findViewById<View>(R.id.search_plate)?.let {
it.layoutDirection = View.LAYOUT_DIRECTION_RTL
}
java
((View) mSearchView.findViewById(R.id.search_plate))
.setLayoutDirection(View.LAYOUT_DIRECTION_RTL)
Update
or you can use this kotlin extention for other rtl problem as well.
fun ViewGroup.rtl() {
val stack = Stack<View>()
stack.add(this)
while (stack.isNotEmpty()) {
stack.pop().apply {
layoutDirection = View.LAYOUT_DIRECTION_RTL
textDirection = View.TEXT_DIRECTION_RTL
(this as? ViewGroup)?.children?.forEach { stack.add(it) }
}
}
}
use it like this
view.rtl() //and view become rtl :)

Related

Correct implementation of SearchView in android toolbar

I have a problem with searchview implementation in android toolbar.
The empty space padding is too big.
I don't want to hide other actions, but these actions are
overlapped by SearchView.
SearchView's underline is not visible
How do i fix issues mentioned above ?
menu.xml
<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto">
<item
android:id="#+id/action_search"
android:title="#string/car_num"
android:icon="#drawable/ic_search_white_24dp"
app:actionViewClass="android.support.v7.widget.SearchView"
app:showAsAction="always" />
<item
android:id="#+id/action_add_client"
android:icon="#drawable/ic_account_multiple_plus"
android:title="#string/action_add_client"
app:showAsAction="always" />
</menu>
fragment
#Override
public void onCreateOptionsMenu(final Menu menu, MenuInflater inflater) {
inflater.inflate(R.menu.menu_fragment_reg_vehicles, menu);
final MenuItem item = menu.findItem(R.id.action_search);
searchView = (SearchView) MenuItemCompat.getActionView(item);
searchView.setQueryHint("Search");
searchView.setMaxWidth(Integer.MAX_VALUE);
searchView.setIconifiedByDefault(false);
searchView.setOnQueryTextListener(this);
searchView.setOnCloseListener(new SearchView.OnCloseListener() {
#Override
public boolean onClose() {
setItemsVisibility(menu, item, true);
return false;
}
});
searchView.setOnSearchClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
setItemsVisibility(menu, item, false);
searchView.requestFocus();
}
});
}
Regarding your posted code, this is the output:
As you can see, there is two left margins: the widget's container and the magnify icon. This is why you have an empty space bigger than an another window with a title. And the menu items are pushed outside the toolbar which, I think, it's the default SearchView ActionView when it's not a CollapseActionView so it fills the parent.
From the source of SearchView widget and its layout abc_search_view.xml, I tried to remove the extra margins and avoid pushing the other items outside the toolbar.
But after many manipulations, my guess is you have to use a custom widget and/or a custom layout. Or to play with setIconifiedByDefault(true) which removes the magnify icon and its extra margin and to use setMaxWidth(MAX_SIZE) where MAX_SIZE is calculated dynamically by Integer.MAX_VALUE - (SIZE_OF_A_MENU_ITEM * NB_OF_MENU_ITEMS)... But it requires a lot of work for nothing. So using a custom layout could be the solution.
However, there is a possible way to keep the appcompat widget, some little workarounds. First, to avoid puhsing out the other items, you can use the CollapseActionView.
<item
...
app:actionViewClass="android.support.v7.widget.SearchView"
app:showAsAction="always|collapseActionView"/>
And to maintain your requirements, you have to expand it when you initialize it:
final SearchView searchView =
(SearchView) MenuItemCompat.getActionView(item);
MenuItemCompat.expandActionView(item);
Be aware that you have to use setOnActionExpandListener() in order to close the window if you don't want to collapse the item. This suggestion will give you this result:
Still the extra margins, right? Therefore, you have to retrieve the container and the magnify icon by their ids (which you can find in abc_search_view.xml... but let's save some time: they are R.id.search_edit_frame and R.id.search_mag_icon). You can remove their margins by using this method:
private void changeSearchViewElements(View view) {
if (view == null)
return;
if (view.getId() == R.id.search_edit_frame
|| view.getId() == R.id.search_mag_icon) {
LinearLayout.LayoutParams p =
(LinearLayout.LayoutParams) view.getLayoutParams();
p.leftMargin = 0; // set no left margin
view.setLayoutParams(p);
}
if (view instanceof ViewGroup) {
ViewGroup viewGroup = (ViewGroup) view;
for (int i = 0; i < viewGroup.getChildCount(); i++) {
changeSearchViewElements(viewGroup.getChildAt(i));
}
}
}
By calling it in a thread:
final SearchView searchView =
(SearchView) MenuItemCompat.getActionView(item);
...
searchView.post(new Runnable() {
#Override
public void run() {
changeSearchViewElements(searchView);
}
});
Here's the output:
Finally, to get the line under the field, there is a possible workaround as using a 9-patch drawable and set it as a background. You can easily find how-to on Google. So the condition will be:
private void changeSearchViewElements(View view) {
...
if (view.getId() == R.id.search_edit_frame
|| view.getId() == R.id.search_mag_icon) {
LinearLayout.LayoutParams p =
(LinearLayout.LayoutParams) view.getLayoutParams();
p.leftMargin = 0; // set no left margin
view.setLayoutParams(p);
} else if (view.getId() == R.id.search_src_text) {
AutoCompleteTextView searchEdit = (AutoCompleteTextView) view;
searchEdit.setBackgroundResource(R.drawable.rect_underline_white);
}
...
}
From the OP's comment below, the underline's field can also be done with the following statement:
searchView.findViewById(android.support.v7.appcompat.R.id.se‌​arch_src_text)
.setBa‌​ckgroundResource(R.d‌​rawable.abc_textfiel‌​d_search_default_mtr‌​l_alpha);
After these workarounds, as I said, it might be easier to use a custom layout. But if you want to keep the default SearchView widget, this might help.

How to remove white underline in a SearchView widget in Toolbar Android

I am using the Toolbar search widget in my project. Everything works fine but expect the thing which I am completely stuck up with removing the underline below the search field in my toolbar. I have tried many solutions and nothing works out. Below are some of the solutions that I tried.
Requirement is to remove white underline in the image
Ist Solution:
//Removing underline
int searchPlateId = searchView.getContext().getResources().getIdentifier("android:id/search_plate", null, null);
View searchPlate = searchView.findViewById(searchPlateId);
if (searchPlate!=null) {
searchPlate.setBackgroundColor (Color.TRANSPARENT);
int searchTextId = searchPlate.getContext ().getResources ().getIdentifier ("android:id/search_src_text", null, null);
}
IInd Solution:
EditText searchEdit = ((EditText)searchView.findViewById(android.support.v7.appcompat.R.id.search_src_text));
searchEdit.setBackgroundColor(Color.TRANSPARENT);
The above code works to change the background of EditText but still underline is displaying below the close icon in SearchBar.
Complete code that I am using for SearchBar widget as follows:
#Override
public void onCreateOptionsMenu(Menu menu, MenuInflater infl) {
super.onCreateOptionsMenu(menu, infl);
MenuInflater inflater = getActivity().getMenuInflater();
inflater.inflate(R.menu.action_search, menu);
final SearchView searchView = (SearchView) MenuItemCompat
.getActionView(menu.findItem(R.id.search));
SearchManager searchManager = (SearchManager) getActivity ().getSystemService (getActivity ().SEARCH_SERVICE);
searchView.setSearchableInfo (searchManager.getSearchableInfo (getActivity ().getComponentName ()));
//changing edittext color
EditText searchEdit = ((EditText)searchView.findViewById(android.support.v7.appcompat.R.id.search_src_text));
searchEdit.setTextColor(Color.WHITE);
}
action_search.xml
<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:compat="http://schemas.android.com/apk/res-auto">
<item android:id="#+id/search"
android:title="Search"
android:icon="#drawable/abc_ic_search_api_mtrl_alpha"
compat:showAsAction="ifRoom|collapseActionView"
compat:actionViewClass="android.support.v7.widget.SearchView" />
</menu>
possible duplicate of this
If you are using SearchView then use for API below 21
android:queryBackground="#android:color/transparent"
you can use below code if you are using API 21 or more
app:queryBackground="#android:color/transparent"
Once try as follows
View v = searchView.findViewById(android.support.v7.appcompat.R.id.search_plate);
v.setBackgroundColor(Color.parseColor("here give actionbar color code"));
Hope this will helps you.
Just add this line if you are using a v7 or androidx widget
app:queryBackground="#android:color/transparent"
Or you can do this through styles:
<style name="SearchViewMy" parent="Widget.AppCompat.Light.SearchView">
<item name="submitBackground">#color/primaryColor</item>
<item name="queryBackground">#color/primaryColor</item>
</style>
queryBackground is attribute for the query background. If you support voice search you may want to remove the line also under that mic button. Thats what submitBackground attribute is for.
Then of course apply the style to your theme.
<style name="Theme.App" parent="Theme.AppCompat.Light.NoActionBar.FullScreen">
<item name="searchViewStyle">#style/SearchViewMy</item>
</style>
For AndroidX I used this based on other answers here,
searchView.findViewById(androidx.appcompat.R.id.search_plate)
.setBackgroundColor(Color.TRANSPARENT)
if you want to remove the underline from SearchView, then just copy paste the below code to your SearchView. it works
android:queryBackground="#null"
like this,
<SearchView
android:id="#+id/searchView"
android:layout_width="match_parent"
android:layout_height="100dp"
android:queryBackground="#null"
/>
You can try using the below code, works like a charm for me.
View v = searchView.findViewById(android.support.v7.appcompat.R.id.search_plate);
v.setBackgroundColor(ContextCompat.getColor(context,android.R.color.transparent));
The below piece of code works for me.
val searchView = menu?.findItem(R.id.action_search)?.actionView as SearchView
searchView.findViewById<View>(androidx.appcompat.R.id.search_plate).background = null
For androidx and kotlin:
menuInflater.inflate(R.menu.conversation_list_screen_menu, menu)
val searchItem = menu.findItem(R.id.action_search)
searchView = searchItem.actionView as SearchView
searchView?.findViewById<View>(androidx.appcompat.R.id.search_plate)?.setBackgroundColor(Color.TRANSPARENT)
The code for changing the background color of SearchView edit text is below
public static void setSearchViewEditTextBackgroundColor(Context context, SearchView searchView, int backgroundColor){
int searchPlateId = context.getResources().getIdentifier("android:id/search_plate", null, null);
ViewGroup viewGroup = (ViewGroup) searchView.findViewById(searchPlateId);
viewGroup.setBackgroundColor(ComponentUtils.getColor(context, backgroundColor));
}
If your action bar background color is white then call the above method as follow.
setSearchViewEditTextBackgroundColor(this, searchView, R.color.white);
Now the underline from SearchView edit text will disappear.
First you should get the bottom line simply like this:
searchPlate = (View) findViewById(R.id.search_plate);
Then you should set background color to transparent like this:
searchPlate.setBackgroundColor(Color.TRANSPARENT);
This works perfectly for androidx.appcompat.widget.SearchView!

Change SearchView little magnifier icon

I want to change the little magnifier icon that looks like an EditText's drawableLeft on a SearchView.
I have tried the following:
This link shows the layout xml file for the whole Search Widget. So using this method (similar to reflection) I changed every icon excepting the little magnifier one:
int submitButtonId = searchView.getContext().getResources().getIdentifier("android:id/search_go_btn", null, null);
ImageView imageView = (ImageView) searchView.findViewById(submitButtonId);
imageView.setImageResource(submitIcon);
I tried changing both android:id/search_mag_icon and android:id/search_button, but the little magnifier inside the EditText is still gray (I just want a white one).
Still not beating, I proceed to make some hypothesis:
Since it didn't work it must be both ImageViews (corresponding to android:id/search_mag_icon and android:id/search_button) Then it must mean the icon is either a drawablePadding background or set up programatically.
"There is no android:drawableLeft nor android:drawableRight in the layout file so the first option is wrong...
Ergo, I proceed to confirm if it is indeed a background. NOPE, the background just covers the blue lines.
So, if the little magnifier is not an ImageView nor a drawableLeft/Right nor a background, It must have been set programmatically (Look for the nested class SearchAutoComplete, BUT NO!!!
So, how do I change this little magnifier icon? I have literally tried everything
Well this question took me about half an hour to write cause I wanted to rule out things I had already done, but I found the answer 5 mins after posting it: http://nlopez.io/how-to-style-the-actionbar-searchview-programmatically/
PS: yep, reflection all the way
In case someone is having this issue, What worked for me was:
searchView.setIconifiedByDefault(false); //This is what does the trick. Removing the magnifier icon.
ImageView searchHintIcon = (ImageView) searchView.findViewById(R.id.search_mag_icon);
searchHintIcon.setImageResource(R.drawable.ic_search_black);
Here is the whole method:
#Override
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
inflater.inflate(R.menu.home_search, menu);
// Associate searchable configuration with the SearchView
SearchManager searchManager = (SearchManager) getActivity().getSystemService(Context.SEARCH_SERVICE);
searchView = (SearchView) menu.findItem(R.id.search_action).getActionView();
//If, this one returns null, use second option.
SearchableInfo searchableInfo = searchManager.getSearchableInfo(getActivity().getComponentName());
if (searchableInfo == null) {
searchableInfo = searchManager.getSearchableInfo(new ComponentName(getApplicationContext(), SearchActivity.class));
}
searchView.setSearchableInfo(searchableInfo);
searchView.setIconifiedByDefault(false);
try {
EditText searchEditText = (EditText) searchView.findViewById(android.support.v7.appcompat.R.id.search_src_text);
searchEditText.setTextColor(getResources().getColor(R.color.black));
searchEditText.setHintTextColor(getResources().getColor(R.color.black));
ImageView searchHintIcon = (ImageView) searchView.findViewById(R.id.search_mag_icon);
searchHintIcon.setImageResource(R.drawable.ic_search_black);
Field f = TextView.class.getDeclaredField("mCursorDrawableRes");
f.setAccessible(true);
f.set(searchEditText, 0);
} catch (Exception e) {
e.printStackTrace();
}
}

Changing the cursor color in SearchView without ActionBarSherlock

I am attempting to change the color of the blinking cursor on the SearchView widget in ICS+. I have tried the following:
Adding <item name="android:textCursorDrawable">#null</item> to my
theme
Adding a style for AutoCompleteTextViews to my theme and setting the textCursorAttribute of that style to #null
Setting android:textCursorDrawable="#null" directly on the SearchView
I read the answer here (Custom cursor color in SearchView), but there is not a non-ABS style for searchAutoCompleteTextView, so could not try this. I also looked for a Java method to set the text cursor drawable, but could not find one - I am modifying other aspects of the SearchView in Java and would be able to do so with the cursor if there were a method available.
I have customized the SearchView pretty extensively, but this one last change is keeping it from looking right - the cursor is white on a white background, so it is not easily visible. Any other ideas of things I can try?
Based on the comments and answers above I made an example of how this could look using reflection. This solves the problem in my app. Hope it saves someone else some time.
#Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.entity_list_actions, menu);
final SearchView searchView = (SearchView) menu.findItem(R.id.search).getActionView();
final int textViewID = searchView.getContext().getResources().getIdentifier("android:id/search_src_text",null, null);
final AutoCompleteTextView searchTextView = (AutoCompleteTextView) searchView.findViewById(textViewID);
try {
Field mCursorDrawableRes = TextView.class.getDeclaredField("mCursorDrawableRes");
mCursorDrawableRes.setAccessible(true);
mCursorDrawableRes.set(searchTextView, 0); //This sets the cursor resource ID to 0 or #null which will make it visible on white background
} catch (Exception e) {}
return super.onCreateOptionsMenu(menu);
}
That 0 could be any other resource ID like R.drawable.my_cursor
<style name="CustomTheme" parent="android:Theme.Holo.Light">
...
<item name="android:autoCompleteTextViewStyle">#style/SearchViewStyle</item>
...
</style>
<style name="SearchViewStyle" parent="#android:style/Widget.Holo.Light.AutoCompleteTextView">
<item name="android:textCursorDrawable">#drawable/action_mode_close</item>
</style>
As per earlier comment:
If you dig into the Android source code, you'll find that mCursorDrawableRes only gets set once in the 3-param constructor. Unfortunately that means there is no easy way to change it at runtime. Looks like your options may be limited to using reflection, or moving your custom SearchView into the android.widget package in order to access the package protected member.
This changes the text color and works also on Android 8:
#Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.main_menu_search, menu);
MenuItem searchItem = menu.findItem(R.id.action_search);
SearchView searchView = (SearchView) MenuItemCompat.getActionView(searchItem);
SearchView.SearchAutoComplete theTextArea = (SearchView.SearchAutoComplete) searchView
.findViewById(R.id.search_src_text);
theTextArea.setTextColor(getResources().getColor(R.color.yourColor));
...

How to change the default icon on the SearchView, to be use in the action bar on Android?

I'm having a bit of trouble customizing the search icon in the SearchView. On my point of view, the icon can be changed in the Item attributes, right? Just check the code bellow..
Can someone tell me what I'm doing wrong?
This is the menu I'm using, with my custom search icon icn_lupa. But when I run the app, I always get the default search icon...
<menu xmlns:android="http://schemas.android.com/apk/res/android">
<item android:id="#+id/menu_search"
android:title="#string/menu_search"
android:icon="#drawable/icn_lupa"
android:showAsAction="always"
android:actionViewClass="android.widget.SearchView" />
</menu>
I've found another way to change the search icon which goes in the same line as Diego Pino's answer but straight in onPrepareOptionsMenu.
In your menu.xml (same as before)
<menu xmlns:android="http://schemas.android.com/apk/res/android">
<item android:id="#+id/action_search"
android:icon="#drawable/ic_action_fav"
android:title="#string/action_websearch"
android:showAsAction="always|never"
android:actionViewClass="android.widget.SearchView" />
</menu>
In your activity:
#Override
public boolean onPrepareOptionsMenu(Menu menu) {
MenuItem searchViewMenuItem = menu.findItem(R.id.action_search);
mSearchView = (SearchView) searchViewMenuItem.getActionView();
int searchImgId = getResources().getIdentifier("android:id/search_button", null, null);
ImageView v = (ImageView) mSearchView.findViewById(searchImgId);
v.setImageResource(R.drawable.your_new_icon);
mSearchView.setOnQueryTextListener(this);
return super.onPrepareOptionsMenu(menu);
}
I followed the example for changing the edittext in this example.
You should be able to do this for all icons/backgrounds in your SearchView, to find the right ID you can check here.
UPDATE November 2017:
Since this answer android has been updated with the possibility of changing the search icon through the XML.
If you target anything below android v21 you can use:
<android.support.v7.widget.SearchView
android:layout_width="wrap_content"
android:layout_height="match_parent"
app:searchIcon="#drawable/ic_search_white_24dp"
app:closeIcon="#drawable/ic_clear_white_24dp" />
Or v21 and later:
<SearchView
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:searchIcon="#drawable/ic_search_white_24dp"
android:closeIcon="#drawable/ic_clear_white_24dp" />
And there are even more options:
closeIcon
commitIcon
goIcon
searchHintIcon
searchIcon
voiceIcon
Nice answer from #just_user
For my case, since I am using the appcompat v7 library for the SearchView + ActionBar, i modified his solution a bit to make it compatible to my project, it should work so as long as you did not modify anything when you added appcompat v7 as library
XML:
<menu xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:metrodeal="http://schemas.android.com/apk/res-auto" >
<item
android:id="#+id/main_menu_action_search"
android:orderInCategory="100"
android:title="#string/search"
metrodeal:showAsAction="always"
metrodeal:actionViewClass="android.support.v7.widget.SearchView"
android:icon="#drawable/search_btn"/>
</menu>
Java code:
#Override
public void onPrepareOptionsMenu(Menu menu) {
MenuItem searchViewMenuItem = menu.findItem(R.id.main_menu_action_search);
SearchView mSearchView = (SearchView) MenuItemCompat.getActionView(searchViewMenuItem);
int searchImgId = android.support.v7.appcompat.R.id.search_button; // I used the explicit layout ID of searchview's ImageView
ImageView v = (ImageView) mSearchView.findViewById(searchImgId);
v.setImageResource(R.drawable.search_btn);
super.onPrepareOptionsMenu(menu);
}
Excuse for the very big icon (I have not resized the icon just yet), but it should work as it is.
I was struggling with this too but then I accidentaly used 'collapseActionView' and that fixed it!
My menu.xml looks like this now:
<menu xmlns:android="http://schemas.android.com/apk/res/android">
<item android:id="#+id/menu_search"
android:title="#string/menu_search"
android:showAsAction="always|withText|collapseActionView"
android:actionViewClass="android.widget.SearchView"
android:icon="#android:drawable/ic_menu_search" />
</menu>
The downside of this is that on tablets the SearchView will appear on the left side of the ActionBar instead of where the searchicon is, but I don't mind that.
I defined a style to do it .
here is my xml:
<android.support.v7.widget.SearchView
android:id="#+id/sv_search"
android:icon="#android:drawable/ic_menu_search"
android:layout_width="fill_parent"
**style="#style/CitySearchView"**
android:layout_height="wrap_content"/>
and this is my style:
<style name="CitySearchView" parent="Base.Widget.AppCompat.SearchView">
<item name="searchIcon">#drawable/ic_more_search</item>
</style>
That it!
After finish that,just take a look at Base.Widget.AppCompat.SearchView.
<style name="Base.Widget.AppCompat.SearchView" parent="android:Widget">
<item name="layout">#layout/abc_search_view</item>
<item name="queryBackground">#drawable/abc_textfield_search_material</item>
<item name="submitBackground">#drawable/abc_textfield_search_material</item>
<item name="closeIcon">#drawable/abc_ic_clear_mtrl_alpha</item>
<item name="searchIcon">#drawable/abc_ic_search_api_mtrl_alpha</item>
<item name="goIcon">#drawable/abc_ic_go_search_api_mtrl_alpha</item>
<item name="voiceIcon">#drawable/abc_ic_voice_search_api_mtrl_alpha</item>
<item name="commitIcon">#drawable/abc_ic_commit_search_api_mtrl_alpha</item>
<item name="suggestionRowLayout">#layout/abc_search_dropdown_item_icons_2line</item>
</style>
every item can be override by define a new style .
Hope it helps!
There's a way to do this. The trick is to recover the ImageView using its identifier and setting a new image with setImageResource(). This solution is inspired on Changing the background drawable of the searchview widget.
private SearchView searchbox;
private void customizeSearchbox() {
setSearchHintIcon(R.drawable.new_search_icon);
}
private void setSearchHintIcon(int resourceId) {
ImageView searchHintIcon = (ImageView) findViewById(searchbox,
"android:id/search_mag_icon");
searchHintIcon.setImageResource(resourceId);
}
private View findViewById(View v, String id) {
return v.findViewById(v.getContext().getResources().
getIdentifier(id, null, null));
}
SearchView searchView = (SearchView) findViewById(R.id.address_search);
try {
Field searchField = SearchView.class
.getDeclaredField("mSearchButton");
searchField.setAccessible(true);
ImageView searchBtn = (ImageView) searchField.get(searchView);
searchBtn.setImageResource(R.drawable.search_glass);
} catch (NoSuchFieldException e) {
} catch (IllegalAccessException e) {
}
After some research I found the solution here. The trick is that the icon is not in an ImageView but in the Spannable object.
// Accessing the SearchAutoComplete
int queryTextViewId = getResources().getIdentifier("android:id/search_src_text", null, null);
View autoComplete = searchView.findViewById(queryTextViewId);
Class<?> clazz = Class.forName("android.widget.SearchView$SearchAutoComplete");
SpannableStringBuilder stopHint = new SpannableStringBuilder(" ");
stopHint.append(getString(R.string.your_new_text));
// Add the icon as an spannable
Drawable searchIcon = getResources().getDrawable(R.drawable.ic_action_search);
Method textSizeMethod = clazz.getMethod("getTextSize");
Float rawTextSize = (Float)textSizeMethod.invoke(autoComplete);
int textSize = (int) (rawTextSize * 1.25);
searchIcon.setBounds(0, 0, textSize, textSize);
stopHint.setSpan(new ImageSpan(searchIcon), 1, 2, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
// Set the new hint text
Method setHintMethod = clazz.getMethod("setHint", CharSequence.class);
setHintMethod.invoke(autoComplete, stopHint);
In menu xml:
<item
android:id="#+id/menu_filter"
android:actionLayout="#layout/menu_filter"
android:icon="#drawable/ic_menu_filter"
android:orderInCategory="10"
android:showAsAction="always"
android:title="#string/menu_filter"/>
and create the layout/menu_filter:
<?xml version="1.0" encoding="utf-8"?>
<SearchView
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:searchIcon="#drawable/ic_menu_filter"/>
then in activity's onCreateOptionsMenu or onPrepareOptionsMenu:
SearchView searchView = (SearchView) menu.findItem(R.id.menu_filter).getActionView();
searchView.setOnQueryTextListener(this);
It looks like the actionViewClass overides the icon and it doesn't look like you can change it from this class.
You got two solutions:
Live with it and I think it's the best option in terms of user experience and platform conformity.
Define your own actionViewClass
<SearchView
android:searchIcon="#drawable/ic_action_search"
..../>
use the searchIcon xml tag
This works with Material Design (MaterialComponents theme) and BottomAppBar.
If you are using androidx library, for example:
<item
android:id="#+id/sv"
android:title="#string/search"
app:actionViewClass="androidx.appcompat.widget.SearchView"
app:showAsAction="always" />
You can create a method and invoke it from wherever you want:
/**
* Set SearchView Icon
* #param i Drawable icon
*/
private void setSVIcon(int i) {
ImageView iv = searchView.findViewById(androidx.appcompat.R.id.search_button);
iv.setImageDrawable(ResourcesCompat.getDrawable(getResources(), i, null));
}
Usage example:
#Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(m, menu);
MenuItem mn = menu.findItem(R.id.sv);
if (mn != null) {
searchview = (SearchView) mn.getActionView();
setSVIcon(R.drawable.ic_sr);
}
}
Update hint of AutocompleteTextView for updating search icon in the expanded mode, copied from android source,
#Override
public boolean onPrepareOptionsMenu(Menu menu) {
mSearchMenuItem = menu.findItem(R.id.action_search);
SearchView searchView = (SearchView) mSearchMenuItem.getActionView();
int searchImgId = getResources().getIdentifier("android:id/search_button", null, null);
ImageView v = (ImageView) searchView.findViewById(searchImgId);
v.setImageResource(R.drawable.search_or);
int searchTextViewId = searchView.getContext().getResources().getIdentifier("android:id/search_src_text", null, null);
AutoCompleteTextView searchTextView = (AutoCompleteTextView) searchView.findViewById(searchTextViewId);
searchTextView.setHintTextColor(getResources().getColor(R.color.hint_color_white));
searchTextView.setTextColor(getResources().getColor(android.R.color.white));
searchTextView.setTextSize(18.0f);
SpannableStringBuilder ssb = new SpannableStringBuilder(" "); // for the icon
ssb.append(hintText);
Drawable searchIcon = getResources().getDrawable(R.drawable.search_or);
int textSize = (int) (searchTextView.getTextSize() * 1.25);
searchIcon.setBounds(0, 0, textSize, textSize);
ssb.setSpan(new ImageSpan(searchIcon), 1, 2, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
searchTextView.setHint(ssb);
return super.onPrepareOptionsMenu(menu);
}
From API 21 you can change it in xml:
android:searchIcon="#drawable/loupe"
android:closeIcon="#drawable/x_white"
for api level < 21, i did this:
int searchImgId = getResources().getIdentifier("android:id/search_mag_icon", null, null);
ImageView ivIcon = (ImageView) searchView.findViewById(searchImgId);
if(ivIcon!=null)
ivIcon.setImageResource(R.drawable.ic_search);
from this
to this
There are three magnifying glass icons. two of them are shown when IconizedByDefault is true(one which is shown before pressing and one is shown in the "hint") and one is shown all the time when IconizedByDefault is false. all the fields are private so the way to get them is by their xml id. (most of the code is mentioned separately in other answers in this post already)
when IconizedByDefault is true change the icon in the hint (which is seen only after pressing the icon) by :
mSearchSrcTextView = (SearchAutoComplete)findViewById(R.id.search_src_text);
then do the same as in the android source code:
final int textSize = (int) (mSearchSrcTextView.getTextSize() * 1.25);
newSearchIconDrawable.setBounds(0, 0, textSize, textSize);
final SpannableStringBuilder ssb = new SpannableStringBuilder(" ");
ssb.setSpan(new ImageSpan(newSearchIconDrawable), 1, 2, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
ssb.append(hintText);
mSearchHintIcon was replaced with newSearchIconDrawable which is your new search icon.
Then set the hint with
mSearchSrcTextView.setHint(ssb);
The other 2 icons are in an ImageView, which can be found by their Id.
for the icon when searchview is closed (when iconizedByDefault is true) do:
mSearchButton = (ImageView) findViewById(R.id.search_button);
and for the one that always appears (if iconizedByDefault is false)
mCollapsedIcon = (ImageView) findViewById(R.id.search_mag_icon);
Desperate solution using Kotlin
val s = (searchView.getAllChildren().firstOrNull() as? LinearLayout)?.getAllChildren()?.filter { it is AppCompatImageView }?.firstOrNull() as? AppCompatImageView
s?.setImageResource(R.drawable.search)
getAllChildren:
fun ViewGroup.getAllChildren() : ArrayList<View> {
val views = ArrayList<View>()
for (i in 0..(childCount-1)) {
views.add(getChildAt(i))
}
return views
}
Hope it helps someone.
My solution:
Use two menu xml files. In one of the xmls the menu item has an actionView and in the other one no. Initially inflate the collapsed menu and when the menu item is clicked, invalidate the menu and inflate the expanded menu xml and make sure you call setIconified(false);
#Override
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater)
{
if(!mShowSearchView)
{
inflater.inflate(R.menu.menu_collapsed, menu);
}
else
{
inflater.inflate(R.menu.menu_expanded, menu);
MenuItem searchItem = menu.findItem(R.id.action_search);
SearchView searchView = (SearchView) MenuItemCompat.getActionView(searchItem);
searchView.setIconified(false);
searchView.setOnCloseListener(new OnCloseListener()
{
#Override
public boolean onClose()
{
mShowSearchView = false;
ActivityCompat.invalidateOptionsMenu(getActivity());
return false;
}
});
}
super.onCreateOptionsMenu(menu, inflater);
}
#Override
public boolean onOptionsItemSelected(MenuItem item)
{
if (item.getItemId() == R.id.action_filter)
{
menu.showMenu();
}
else if (item.getItemId() == R.id.action_search)
{
mShowSearchView = true;
ActivityCompat.invalidateOptionsMenu(getActivity());
}
return super.onOptionsItemSelected(item);
}
Just name your icon the same name as the icon that is used by the search view. When it compiles it takes the resource in the project over the icon in the library.
I use the AppCompat library. Yes, specifying android:icon="#drawable/search_icon_png" doesnt work.
So i looked into the source code of #style/Theme.AppCompat and found the icon that android uses.
<item name="searchViewSearchIcon">#drawable/abc_ic_search</item>
So if you rename your search icon inside your drawables to abc_ic_search.png, this icon is rendered as its found in your app drawable first, rather than the appcompat drawable folder.
Works for me :)
Using this approach you can customize the close and clear icons for the search widget as well.

Categories

Resources