I’m trying to change search suggestions to “light theme”. I’m using appcompat-v7:22.2.0 library and read about new feature for customizing search view widget (android.support.v
I know I'm late, but I think it will be helpful for those, who are still searching for this issue. Suggested solution works if use the Toolbar
. First you need to override theme of Toolbar
in your styles like belov:
<style name="AppTheme.Toolbar" parent="Base.ThemeOverlay.AppCompat.Dark.ActionBar">
<item name="searchViewStyle">@style/CustomSearchStyle</item>
</style>
<style name="CustomSearchStyle" parent="Base.Widget.AppCompat.SearchView.ActionBar">
<item name="suggestionRowLayout">@layout/custom_search_layout</item>
</style>
I used Dark
theme, but I thinkg with Light
this solution also will work. As you can see, I had overridden searchViewStyle
of Toolbar's theme and suggestionRowLayout
of SearchView
, where I put my own layout:
<?xml version="1.0" encoding="utf-8"?>
<!--
/*
* Copyright (C) 2014 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-->
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="58dip"
android:background="@color/white"
style="@style/RtlOverlay.Widget.AppCompat.Search.DropDown">
<!-- Icons come first in the layout, since their placement doesn't depend on
the placement of the text views. -->
<ImageView
android:id="@android:id/icon1"
android:layout_width="48dip"
android:layout_height="48dip"
android:scaleType="centerInside"
android:layout_alignParentTop="true"
android:layout_alignParentBottom="true"
android:tint="@color/black"
android:visibility="invisible"
style="@style/RtlOverlay.Widget.AppCompat.Search.DropDown.Icon1" />
<ImageView
android:id="@+id/edit_query"
android:layout_width="48dip"
android:layout_height="48dip"
android:scaleType="centerInside"
android:layout_alignParentTop="true"
android:layout_alignParentBottom="true"
android:background="?attr/selectableItemBackground"
android:visibility="gone"
style="@style/RtlOverlay.Widget.AppCompat.Search.DropDown.Query" />
<ImageView
android:id="@android:id/icon2"
android:layout_width="48dip"
android:layout_height="48dip"
android:scaleType="centerInside"
android:layout_alignWithParentIfMissing="true"
android:layout_alignParentTop="true"
android:layout_alignParentBottom="true"
android:visibility="gone"
style="@style/RtlOverlay.Widget.AppCompat.Search.DropDown.Icon2" />
<!-- The subtitle comes before the title, since the height of the title depends on whether the
subtitle is visible or gone. -->
<TextView android:id="@android:id/text2"
style="?android:attr/dropDownItemStyle"
android:singleLine="true"
android:layout_width="match_parent"
android:textColor="@color/black"
android:textSize="16sp"
tools:text="id/text2"
android:layout_height="29dip"
android:paddingBottom="4dip"
android:gravity="top"
android:layout_alignWithParentIfMissing="true"
android:layout_alignParentBottom="true"
android:visibility="gone"
/>
<!-- The title is placed above the subtitle, if there is one. If there is no
subtitle, it fills the parent. -->
<TextView android:id="@android:id/text1"
style="?android:attr/dropDownItemStyle"
android:singleLine="true"
android:textColor="@color/black"
tools:text="id/text1"
android:textStyle="bold"
android:textSize="18sp"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_centerVertical="true"
android:layout_above="@android:id/text2" />
</RelativeLayout>
This layout I took from original theme and added some changes to it to get what I need.
NOTE: Unfortunately I didn't find the way how to change the standard recent icon, so I left it, because it was not critical for me.
So, to change the background color of the suggestion item, just add it to root RelativeLayout
- in my case I changed it to white. You can put you own color.
I checked that for suggestions use only ImageView
with id @android:id/icon1
and TextView
with id @android:id/text1
so I added changes to these two. Because of in Dark
theme default recent icon is white, I added android:tint="@color/black"
. TextView
you can configure, like you want.
And the latest thing we need is to apply theme to our Toolbar
:
<android.support.v7.widget.Toolbar
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/toolbar"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
android:minHeight="?attr/actionBarSize"
android:theme="@style/AppTheme.Toolbar"
app:titleTextColor="@color/white"
app:navigationIcon="?attr/homeAsUpIndicator"
app:theme="@style/AppTheme.Toolbar"
app:popupTheme="@style/ThemeOverlay.AppCompat.Light"
tools:elevation="4dp">
Here is a result of what I got:
This is how I am using my own search suggestions...
This is my CountriesFragment
file that just show all country name in suggestions.
The trick here is that I am providing custom View to Suggestion list to show.
public class CountriesFragment extends Fragment {
private boolean mSearchCheck;
private SimpleCursorAdapter mAdapter;
public static final String TEXT_FRAGMENT = "TEXT_FRAGMENT";
public static final String CITY_NAME = "cityName";
private LayoutInflater mInflater;
private ViewGroup mainContainer;
private static final String[] COUNTRIES = {
"Afghanistan", "Albania", "Algeria", "American Samoa", "Andorra", "Angola", "Anguilla", "Antarctica",
"Antigua and Barbuda", "Argentina", "Armenia", "Aruba", "Australia", "Austria", "Azerbaijan", "Bahamas", "Bahrain", "Bangladesh", "Barbados",
"Belarus", "Belgium", "Belize", "Benin", "Bermuda", "Bhutan", "Bolivia", "Bosnia and Herzegowina", "Botswana", "Bouvet Island", "Brazil",
"British Indian Ocean Territory", "Brunei Darussalam", "Bulgaria", "Burkina Faso", "Burundi", "Cambodia", "Cameroon", "Canada", "Cape Verde",
"Cayman Islands", "Central African Republic", "Chad", "Chile", "China", "Christmas Island", "Cocos (Keeling) Islands", "Colombia", "Comoros",
"Congo", "Congo, the Democratic Republic of the", "Cook Islands", "Costa Rica", "Cote d'Ivoire", "Croatia (Hrvatska)", "Cuba", "Cyprus",
"Czech Republic", "Denmark", "Djibouti", "Dominica", "Dominican Republic", "East Timor", "Ecuador", "Egypt", "El Salvador", "Equatorial Guinea",
"Eritrea", "Estonia", "Ethiopia", "Falkland Islands (Malvinas)", "Faroe Islands", "Fiji", "Finland", "France", "France Metropolitan", "French Guiana",
"French Polynesia", "French Southern Territories", "Gabon", "Gambia", "Georgia", "Germany", "Ghana", "Gibraltar", "Greece", "Greenland", "Grenada",
"Guadeloupe", "Guam", "Guatemala", "Guinea", "Guinea-Bissau", "Guyana", "Haiti", "Heard and Mc Donald Islands", "Holy See (Vatican City State)",
"Honduras", "Hong Kong", "Hungary", "Iceland", "India", "Indonesia", "Iran (Islamic Republic of)", "Iraq", "Ireland", "Israel", "Italy", "Jamaica",
"Japan", "Jordan", "Kazakhstan", "Kenya", "Kiribati", "Korea, Democratic People's Republic of", "Korea, Republic of", "Kuwait", "Kyrgyzstan",
"Lao, People's Democratic Republic", "Latvia", "Lebanon", "Lesotho", "Liberia", "Libyan Arab Jamahiriya", "Liechtenstein", "Lithuania", "Luxembourg",
"Macau", "Macedonia, The Former Yugoslav Republic of", "Madagascar", "Malawi", "Malaysia", "Maldives", "Mali", "Malta", "Marshall Islands", "Martinique",
"Mauritania", "Mauritius", "Mayotte", "Mexico", "Micronesia, Federated States of", "Moldova, Republic of", "Monaco", "Mongolia", "Montserrat", "Morocco",
"Mozambique", "Myanmar", "Namibia", "Nauru", "Nepal", "Netherlands", "Netherlands Antilles", "New Caledonia", "New Zealand", "Nicaragua", "Niger", "Nigeria",
"Niue", "Norfolk Island", "Northern Mariana Islands", "Norway", "Oman", "Pakistan", "Palau", "Panama", "Papua New Guinea", "Paraguay", "Peru", "Philippines",
"Pitcairn", "Poland", "Portugal", "Puerto Rico", "Qatar", "Reunion", "Romania", "Russian Federation", "Rwanda", "Saint Kitts and Nevis", "Saint Lucia",
"Saint Vincent and the Grenadines", "Samoa", "San Marino", "Sao Tome and Principe", "Saudi Arabia", "Senegal", "Seychelles", "Sierra Leone", "Singapore",
"Slovakia (Slovak Republic)", "Slovenia", "Solomon Islands", "Somalia", "South Africa", "South Georgia and the South Sandwich Islands", "Spain", "Sri Lanka",
"St. Helena", "St. Pierre and Miquelon", "Sudan", "Suriname", "Svalbard and Jan Mayen Islands", "Swaziland", "Sweden", "Switzerland", "Syrian Arab Republic",
"Taiwan, Province of China", "Tajikistan", "Tanzania, United Republic of", "Thailand", "Togo", "Tokelau", "Tonga", "Trinidad and Tobago", "Tunisia",
"Turkey", "Turkmenistan", "Turks and Caicos Islands", "Tuvalu", "Uganda", "Ukraine", "United Arab Emirates", "United Kingdom", "United States",
"United States Minor Outlying Islands", "Uruguay", "Uzbekistan", "Vanuatu", "Venezuela", "Vietnam", "Virgin Islands (British)", "Virgin Islands (U.S.)",
"Wallis and Futuna Islands", "Western Sahara", "Yemen", "Yugoslavia", "Zambia", "Zimbabwe"
};
public static CountriesFragment newInstance(String text) {
CountriesFragment mFragment = new CountriesFragment();
Bundle mBundle = new Bundle();
mBundle.putString(TEXT_FRAGMENT, text);
mFragment.setArguments(mBundle);
return mFragment;
}
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
loadHints();
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View rootView = inflater.inflate(R.layout.fragment_countries, container, false);
mInflater = inflater;
mainContainer = (ViewGroup) rootView.findViewById(R.id.container);
//rootView.setLayoutParams(new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT));
return rootView;
}
@Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
setHasOptionsMenu(true);
}
@Override
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
super.onCreateOptionsMenu(menu, inflater);
inflater.inflate(R.menu.menu, menu);
SearchView searchView = (SearchView) MenuItemCompat.getActionView(menu.findItem(R.id.menu_search));
searchView.setQueryHint(this.getString(R.string.search));
((EditText) searchView.findViewById(android.support.v7.appcompat.R.id.search_src_text))
.setHintTextColor(getResources().getColor(R.color.nliveo_white));
searchView.setSuggestionsAdapter(mAdapter);
searchView.setOnQueryTextListener(onQuerySearchView);
searchView.setOnSuggestionListener(onQuerySuggestion);
menu.findItem(R.id.menu_add).setVisible(true);
menu.findItem(R.id.menu_search).setVisible(true);
mSearchCheck = false;
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case R.id.menu_add:
addCountry();
break;
case R.id.menu_search:
mSearchCheck = true;
break;
}
return true;
}
private void addCountry() {
final ViewGroup newView = (ViewGroup) mInflater.inflate(R.layout.country_row, mainContainer, false);
final TextView countryName = (TextView) newView.findViewById(android.R.id.text1);
countryName.setText(COUNTRIES[(int) (Math.random() * COUNTRIES.length)]);
final Animation fadeIn = AnimationUtils.loadAnimation(getActivity(), R.anim.fade_in);
final Animation fadeOut = AnimationUtils.loadAnimation(getActivity(), R.anim.fade_out);
fadeIn.setFillAfter(false);
fadeOut.setFillAfter(false);
final ImageButton closeButton = (ImageButton) newView.findViewById(R.id.delete_button);
closeButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
newView.startAnimation(fadeOut);
new Handler().postDelayed(new Runnable() {
@Override
public void run() {
mainContainer.removeView(newView);
}
}, fadeOut.getDuration());
}
});
mainContainer.addView(newView, 0);
newView.startAnimation(fadeIn);
}
private SearchView.OnQueryTextListener onQuerySearchView = new SearchView.OnQueryTextListener() {
@Override
public boolean onQueryTextSubmit(String query) {
mSearchCheck = false;
return false;
}
@Override
public boolean onQueryTextChange(String query) {
if (mSearchCheck) {
// implement your search here
giveSuggestions(query);
}
return false;
}
};
private void giveSuggestions(String query) {
final MatrixCursor cursor = new MatrixCursor(new String[]{BaseColumns._ID, CITY_NAME});
for (int i = 0; i < COUNTRIES.length; i++) {
if (COUNTRIES[i].toLowerCase().contains(query.toLowerCase()))
cursor.addRow(new Object[]{i, COUNTRIES[i]});
}
mAdapter.changeCursor(cursor);
}
private SearchView.OnSuggestionListener onQuerySuggestion = new SearchView.OnSuggestionListener() {
@Override
public boolean onSuggestionSelect(int position) {
return false;
}
@Override
public boolean onSuggestionClick(int position) {
return false;
}
};
private void loadHints() {
final String[] from = new String[]{CITY_NAME};
final int[] to = new int[]{android.R.id.text1};
mAdapter = new SimpleCursorAdapter(getActivity(),
R.layout.hint_row,
null,
from,
to,
CursorAdapter.FLAG_REGISTER_CONTENT_OBSERVER);
}
}
here is the hint_row.xml
<?xml version="1.0" encoding="utf-8"?>
<TextView xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@android:id/text1"
android:layout_width="match_parent"
android:layout_height="48dp"
android:textAppearance="?android:attr/textAppearanceListItemSmall"
android:gravity="center_vertical"
android:background="@color/nliveo_green_colorPrimaryDark"
android:textColor="@color/nliveo_white"
android:paddingLeft="15dp"
android:paddingRight="15dp"
android:minHeight="?android:attr/listPreferredItemHeightSmall"
android:elevation="3dp"
android:alpha="0.7" />
Simple menu file having SearchView. menu.xml
<menu xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto">
<item
android:id="@+id/menu_search"
app:actionViewClass="android.support.v7.widget.SearchView"
android:icon="@mipmap/ic_search_white_24dp"
app:showAsAction="ifRoom|collapseActionView"
android:title="@string/search"/>
<item
android:id="@+id/menu_add"
android:icon="@mipmap/ic_add_white_24dp"
app:showAsAction="ifRoom"
android:title="@string/add"/>
</menu>
I am getting this beautiful suggestions...
Suggestions is a dynamic list created by system and is not an activity. So you cannot apply light theme to it.
Instead you can customize suggestions to give it feel like a light theme by using style.
use this hint_row.xml
<?xml version="1.0" encoding="utf-8"?>
<TextView xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@android:id/text1"
style="@style/suggestionsTheme"
android:layout_width="match_parent"
android:layout_height="48dp"
android:gravity="center_vertical"
android:text="demo"
android:paddingLeft="15dp"
android:paddingRight="15dp" />
And apply this style
<style name="suggestionsTheme" parent="TextAppearance.AppCompat.Light.SearchResult.Subtitle" >
<item name="android:background">@android:color/white</item>
<item name="android:textColor">@android:color/black</item>
Now I am getting this
You can give more style according to your need