Skip to content

Instantly share code, notes, and snippets.

@jaredrummler
Last active May 22, 2020 22:48
Show Gist options
  • Select an option

  • Save jaredrummler/c408c9d897fd92d5d116 to your computer and use it in GitHub Desktop.

Select an option

Save jaredrummler/c408c9d897fd92d5d116 to your computer and use it in GitHub Desktop.
Customize the SearchView in an ActionBar for Android
/*
* Copyright (C) 2014 Jared Rummler <jared@jrummyapps.com>
*
* 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.
*/
package com.jrummyapps.ui;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import android.graphics.Typeface;
import android.graphics.drawable.Drawable;
import android.os.Build;
import android.text.InputType;
import android.text.Spannable;
import android.text.SpannableStringBuilder;
import android.text.style.ImageSpan;
import android.view.Menu;
import android.view.View;
import android.widget.AutoCompleteTextView;
import android.widget.ImageView;
import android.widget.SearchView;
import android.widget.TextView;
/**
* Customize {@link android.widget.SearchView}</p>
*
* This should be used in {@link android.app.Activity#onCreateOptionsMenu(Menu)} after inflating the
* menu which has the action view class set as android.widget.SearchView</p>
*
* Some example usage:</p>
*
* <pre>
* <code>
* new SearchViewCustomizer(menu, R.id.menu_search).setBackgroundColor(Color.TRANSPARENT)
* .setEditTextColor(ColorUtils.WHITE).setEditTextHintColor(Color.LTGRAY)
* .setEditTextInputType(InputType.TYPE_TEXT_FLAG_NO_SUGGESTIONS)
* .setEditTextTypeface(robotoLight).setSearchHintDrawable(searchIcon, "filename")
* .setEditTextCursorResId(R.drawable.white_cursor)
* .setCloseDrawable(closeDrawable)
* .setEditTextBackground(R.drawable.material_edit_text);
* </code>
* </pre>
*
* @author Jared Rummler <jared@jaredrummler.com>
* @version 1.0
* @since Oct 24, 2014
*/
public class SearchViewCustomizer {
// ===========================================================
// Constants
// ===========================================================
// ===========================================================
// Static Fields
// ===========================================================
// ===========================================================
// Static Initializers
// ===========================================================
// ===========================================================
// Static Methods
// ===========================================================
// ===========================================================
// Fields
// ===========================================================
private final SearchView mSearchView;
private final int mSearchPlateId;
private final int mSearchSrcTextId;
private final int mSearchCloseBtnId;
// ===========================================================
// Initializers
// ===========================================================
// ===========================================================
// Constructors
// ===========================================================
public SearchViewCustomizer(Menu menu, int id) {
this((SearchView) menu.findItem(id).getActionView());
}
public SearchViewCustomizer(SearchView searchView) {
mSearchView = searchView;
mSearchSrcTextId = searchView.getContext().getResources()
.getIdentifier("android:id/search_src_text", null, null);
mSearchPlateId = searchView.getContext().getResources()
.getIdentifier("android:id/search_plate", null, null);
mSearchCloseBtnId = searchView.getContext().getResources()
.getIdentifier("android:id/search_close_btn", null, null);
}
// ===========================================================
// Getter & Setter
// ===========================================================
// ===========================================================
// Methods for/from SuperClass/Interfaces
// ===========================================================
// ===========================================================
// Methods
// ===========================================================
/**
* Set the background of the search plate.
*
* @param resid
* The identifier of the resource.
* @return
*/
public SearchViewCustomizer setBackgroundResource(int resid) {
if (mSearchPlateId != 0) {
View searchPlate = findById(mSearchPlateId);
searchPlate.setBackgroundResource(resid);
}
return this;
}
/**
* Set the background of the search plate
*
* @param color
* The color of the background
* @return
*/
public SearchViewCustomizer setBackgroundColor(int color) {
if (mSearchPlateId != 0) {
View searchPlate = findById(mSearchPlateId);
searchPlate.setBackgroundColor(color);
}
return this;
}
/**
* Set the background of the search plate
*
* @param background
* The Drawable to use as the background, or null to remove the background
* @return
*/
@SuppressWarnings("deprecation")
public SearchViewCustomizer setBackgroundDrawable(Drawable background) {
if (mSearchPlateId != 0) {
View searchPlate = findById(mSearchPlateId);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
searchPlate.setBackground(background);
} else {
searchPlate.setBackgroundDrawable(background);
}
}
return this;
}
/**
* Set the text color for the EditText
*
* @param color
* @return
*/
public SearchViewCustomizer setEditTextColor(int color) {
if (mSearchSrcTextId != 0) {
AutoCompleteTextView searchEditText = findById(mSearchSrcTextId);
searchEditText.setTextColor(color);
}
return this;
}
/**
* Sets the color of the hint text for all the states (disabled, focussed, selected...)
*
* @param color
* @return
*/
public SearchViewCustomizer setEditTextHintColor(int color) {
if (mSearchSrcTextId != 0) {
AutoCompleteTextView searchEditText = findById(mSearchSrcTextId);
searchEditText.setHintTextColor(color);
}
return this;
}
/**
* Set the background for the EditText displayed in the SearchView
*
* @param resId
* The identifier of the resource.
* @return
*/
public SearchViewCustomizer setEditTextBackground(int resId) {
if (mSearchSrcTextId != 0) {
AutoCompleteTextView searchEditText = findById(mSearchSrcTextId);
searchEditText.setBackgroundResource(resId);
}
return this;
}
/**
* Set any input types on the EditText, such as {@link InputType#TYPE_TEXT_FLAG_NO_SUGGESTIONS}
*
* @param type
* @return
*/
public SearchViewCustomizer setEditTextInputType(int type) {
if (mSearchSrcTextId != 0) {
AutoCompleteTextView searchEditText = findById(mSearchSrcTextId);
searchEditText.setInputType(type);
}
return this;
}
/**
* Apply a custom typeface to the search field EditText
*
* @param tf
* @return
*/
public SearchViewCustomizer setEditTextTypeface(Typeface tf) {
if (mSearchSrcTextId != 0) {
AutoCompleteTextView searchEditText = findById(mSearchSrcTextId);
searchEditText.setTypeface(tf);
}
return this;
}
/**
* Set the search icon that appears before the hint text.
*
* @param drawable
* The drawable to use for the hint.
* @param hint
* The text for the hint.
* @return
*/
public SearchViewCustomizer setSearchHintDrawable(Drawable drawable, String hint) {
if (mSearchSrcTextId != 0) {
AutoCompleteTextView searchEditText = findById(mSearchSrcTextId);
try {
// http://nlopez.io/how-to-style-the-actionbar-searchview-programmatically/
Class<?> clazz = Class.forName("android.widget.SearchView$SearchAutoComplete");
// Add the icon as an spannable
Method textSizeMethod = clazz.getMethod("getTextSize");
Float rawTextSize = (Float) textSizeMethod.invoke(searchEditText);
int textSize = (int) (rawTextSize * 1.25);
drawable.setBounds(0, 0, textSize, textSize);
// Create hint text
SpannableStringBuilder stopHint = new SpannableStringBuilder(" ");
stopHint.append(hint);
stopHint.setSpan(new ImageSpan(drawable), 1, 2, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
// Set the new hint text
Method setHintMethod = clazz.getMethod("setHint", CharSequence.class);
setHintMethod.invoke(searchEditText, stopHint);
} catch (Exception ignored) {
}
}
return this;
}
/**
* Set the cursor that will be used in the EditText.
*
* @param resId
* The resource id for your custom cursor.
* @return
*/
public SearchViewCustomizer setEditTextCursorResId(int resId) {
if (mSearchSrcTextId != 0) {
AutoCompleteTextView searchEditText = findById(mSearchSrcTextId);
try {
// https://github.com/android/platform_frameworks_base/blob/kitkat-release/core/java/android/widget/TextView.java#L562-564
Field f = TextView.class.getDeclaredField("mCursorDrawableRes");
f.setAccessible(true);
f.set(searchEditText, resId);
} catch (Exception ignored) {
}
}
return this;
}
/**
* Set the cancel drawable.
*
* @param drawable
* The drawable to set
* @return
*/
public SearchViewCustomizer setCloseDrawable(Drawable drawable) {
if (mSearchCloseBtnId != 0) {
ImageView searchCloseBtn = findById(mSearchCloseBtnId);
searchCloseBtn.setImageDrawable(drawable);
}
return this;
}
/**
*
* @return The {@link AutoCompleteTextView} that is used in the {@link SearchView} or
* {@code null} if we failed to find it.
*/
public AutoCompleteTextView getAutoCompleteTextView() {
if (mSearchSrcTextId == 0) return null;
return findById(mSearchSrcTextId);
}
/**
*
* @return The {@link ImageView} that is used as the close button in the {@link SearchView} or
* {@code null} if we failed to find it.
*/
public ImageView getCloseButton() {
if (mSearchCloseBtnId == 0) return null;
return findById(mSearchCloseBtnId);
}
/**
*
* @return The search plate that holds most of the views in the {@link SearchView} or
* {@code null} if we failed to find it.
*/
public View getSearchPlate() {
if (mSearchPlateId == 0) return null;
return findById(mSearchPlateId);
}
@SuppressWarnings("unchecked")
private <T extends View> T findById(int id) {
return (T) mSearchView.findViewById(id);
}
// ===========================================================
// Inner and Anonymous Classes and/or Interfaces
// ===========================================================
}
@abdallaadelessa
Copy link
Copy Markdown

You saved my day thank you

@MFamStory
Copy link
Copy Markdown

Thankyou!

@nelsonalfo
Copy link
Copy Markdown

You are the freaking best! 👍

@mc1100
Copy link
Copy Markdown

mc1100 commented Jun 21, 2018

It seems, like mViews is always empty.

@ijkmoises
Copy link
Copy Markdown

ijkmoises commented May 22, 2020

didn't work with androidx.appcompat.widget.SearchView :(

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment