Last active
May 22, 2020 22:48
-
-
Save jaredrummler/c408c9d897fd92d5d116 to your computer and use it in GitHub Desktop.
Customize the SearchView in an ActionBar for Android
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| /* | |
| * 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 | |
| // =========================================================== | |
| } |
Thankyou!
You are the freaking best! 👍
It seems, like mViews is always empty.
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
You saved my day thank you