android styles android-actionbar searchview background-drawable

android - Cambiar el fondo dibujable del widget searchview



styles android-actionbar (8)

Estoy tratando de cambiar el dibujante que se encuentra en el widget de vista de búsqueda de barra de acción de Android.

Actualmente se ve así:

pero necesito cambiar el fondo azul dibujable a un color rojo.

He intentado hacer muchas cosas sin rodar mi propio widget de búsqueda, pero parece que nada funciona.

¿Puede alguien señalarme en la dirección correcta para cambiar esto?


Introducción

Lamentablemente, no hay forma de establecer el estilo de campo de texto de SearchView usando temas, estilos y herencia en XML, como puede hacer con el fondo de los elementos en el menú desplegable ActionBar . Esto se debe a que selectableItemBackground aparece como styleable en R.stylable , mientras que searchViewTextField (atributo de tema que nos interesa) no lo es. Por lo tanto, no podemos acceder fácilmente desde recursos XML (obtendrá un No resource found that matches the given name: attr ''android:searchViewTextField'' error No resource found that matches the given name: attr ''android:searchViewTextField'' ).

Establecer el fondo del campo de texto de SearchView desde el código

Por lo tanto, la única forma de sustituir correctamente el fondo del campo de texto de SearchView es entrar en sus elementos internos, obtener acceso a ver que tiene un conjunto de trasfondos basado en searchViewTextField y establecer el nuestro.

NOTA: La siguiente solución depende solo del id ( android:id/search_plate ) del elemento dentro de SearchView , por lo que es más independiente de la versión SDK que el recorrido de niños (por ejemplo, usando searchView.getChildAt(0) para llegar a la vista correcta en SearchView ), pero no es a prueba de balas Especialmente si algún fabricante decide volver a implementar las partes internas de SearchView y el elemento con el ID mencionado anteriormente no está presente, el código no funcionará.

En SDK, el fondo para el campo de texto en SearchView se declara a través de nine-patches , por lo que lo haremos de la misma manera. Puedes encontrar imágenes png originales en el directorio drawable-mdpi del repositorio Android git . Estamos interesados ​​en dos imágenes. Uno para estado cuando se selecciona el campo de texto (llamado textfield_search_selected_holo_light.9.png ) y otro para donde no está (named textfield_search_default_holo_light.9.png ).

Desafortunadamente, tendrá que crear copias locales de ambas imágenes, incluso si desea personalizar solo el estado enfocado . Esto es porque textfield_search_default_holo_light no está presente en R.drawable . Por lo tanto, no es fácilmente accesible a través de @android:drawable/textfield_search_default_holo_light , que podría usarse en el selector que se muestra a continuación, en lugar de hacer referencia a dibujable local.

NOTA: Estaba usando el tema Holo Light como base, pero puedes hacer lo mismo con Holo Dark . Parece que no hay diferencia real en los parches de estado seleccionados 9 entre los temas Light y Dark . Sin embargo, hay una diferencia en 9 parches para el estado predeterminado (consulte Light vs Dark ). Por lo tanto, probablemente no haya necesidad de hacer copias locales de 9 parches para estado seleccionado , tanto para temas oscuros como claros (suponiendo que quiera manejar ambos, y que ambos tengan el mismo aspecto que en Holo Theme ). Simplemente haga una copia local y úsela en el selector dibujable para ambos temas.

Ahora, tendrá que editar nueve parches descargados según sus necesidades (es decir, cambiar el color azul por el rojo). Puede echar un vistazo al archivo usando la herramienta dibujar 9 parches para verificar si está correctamente definido después de su edición.

He editado archivos usando GIMP con una herramienta de lápiz de un píxel (bastante fácil) pero es probable que use la herramienta propia. Aquí está mi parche personalizado de 9 para el estado enfocado :

NOTA: Para simplificar, he usado solo imágenes para la densidad de mdpi . Tendrá que crear 9 parches para múltiples densidades de pantalla si quiere el mejor resultado en cualquier dispositivo. Las imágenes para Holo SearchView se pueden encontrar en textfield_search_selected_holo_light.9.png , hdpi y Light .

Ahora, necesitaremos crear un selector dibujable, para que se muestre la imagen adecuada según el estado de visualización. Crea el archivo res/drawable/texfield_searchview_holo_light.xml con el siguiente contenido:

<?xml version="1.0" encoding="utf-8"?> <selector xmlns:android="http://schemas.android.com/apk/res/android"> <item android:state_focused="true" android:drawable="@drawable/textfield_search_selected_holo_light" /> <item android:drawable="@drawable/textfield_search_default_holo_light" /> </selector>

Utilizaremos el LinearLayout creado anteriormente para establecer el fondo de la vista LinearLayout que contiene el campo de texto dentro de SearchView , su id es android:id/search_plate . Así que aquí está cómo hacer esto rápidamente en el código, al crear menú de opciones:

public class MainActivity extends Activity { @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); } @Override public boolean onCreateOptionsMenu(Menu menu) { getMenuInflater().inflate(R.menu.activity_main, menu); // Getting SearchView from XML layout by id defined there - my_search_view in this case SearchView searchView = (SearchView) menu.findItem(R.id.my_search_view).getActionView(); // Getting id for ''search_plate'' - the id is part of generate R file, // so we have to get id on runtime. int searchPlateId = searchView.getContext().getResources().getIdentifier("android:id/search_plate", null, null); // Getting the ''search_plate'' LinearLayout. View searchPlate = searchView.findViewById(searchPlateId); // Setting background of ''search_plate'' to earlier defined drawable. searchPlate.setBackgroundResource(R.drawable.textfield_searchview_holo_light); return super.onCreateOptionsMenu(menu); } }

Efecto final

Aquí está la captura de pantalla del resultado final:

Cómo llegué a esto

Creo que vale la pena saber cómo llegué a esto, para que este enfoque se pueda usar al personalizar otras vistas.

Comprobando el diseño de la vista

Comprobé cómo se ve el diseño de SearchView . En SearchView contructor uno puede encontrar una línea que infla el diseño:

inflater.inflate(R.layout.search_view, this, true);

Ahora sabemos que el diseño de SearchView está en un archivo llamado res/layout/search_view.xml . Al search_view.xml en search_view.xml , podemos encontrar un elemento LinearLayout interno (con id search_plate ) que tiene android.widget.SearchView$SearchAutoComplete dentro de él (se parece a nuestro campo de texto de la vista de búsqueda):

<LinearLayout android:id="@+id/search_plate" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_weight="1" android:layout_gravity="center_vertical" android:orientation="horizontal" android:background="?android:attr/searchViewTextField">

Ahora, ahora que el fondo se establece en función del atributo searchViewTextField del tema actual.

Atributo de investigación (¿se puede establecer fácilmente?)

Para verificar cómo se searchViewTextField atributo searchViewTextField , investigamos res/values/themes.xml . Hay un grupo de atributos relacionados con SearchView en el Theme predeterminado:

<style name="Theme"> <!-- (...other attributes present here...) --> <!-- SearchView attributes --> <item name="searchDropdownBackground">@android:drawable/spinner_dropdown_background</item> <item name="searchViewTextField">@drawable/textfield_searchview_holo_dark</item> <item name="searchViewTextFieldRight">@drawable/textfield_searchview_right_holo_dark</item> <item name="searchViewCloseIcon">@android:drawable/ic_clear</item> <item name="searchViewSearchIcon">@android:drawable/ic_search</item> <item name="searchViewGoIcon">@android:drawable/ic_go</item> <item name="searchViewVoiceIcon">@android:drawable/ic_voice_search</item> <item name="searchViewEditQuery">@android:drawable/ic_commit_search_api_holo_dark</item> <item name="searchViewEditQueryBackground">?attr/selectableItemBackground</item>

Vemos que para el tema predeterminado, el valor es @drawable/textfield_searchview_holo_dark . Para Theme.Light value también se establece en ese archivo .

Ahora, sería genial si este atributo fuera accesible a través de R.styleable , pero desafortunadamente no lo es. Para comparar, vea otros atributos de tema que están presentes en themes.xml y R.attr como textAppearance o selectableItemBackground . Si searchViewTextField estuviera presente en R.attr (y R.stylable ) podríamos simplemente usar nuestro selector dibujable al definir el tema para toda nuestra aplicación en XML. Por ejemplo:

<resources xmlns:android="http://schemas.android.com/apk/res/android"> <style name="AppTheme" parent="android:Theme.Light"> <item name="android:searchViewTextField">@drawable/textfield_searchview_holo_light</item> </style> </resources>

¿Qué debería ser modificado?

Ahora sabemos que tendremos que acceder a search_plate través del código. Sin embargo, todavía no sabemos cómo debería verse. En resumen, buscamos los elementos dibujables utilizados como valores en los temas predeterminados: textfield_searchview_holo_dark.xml y textfield_searchview_holo_light.xml . Al mirar el contenido, vemos que el dibujable es un selector que hace referencia a otros dos objetos dibujables (que luego son 9 parches) en función del estado de la vista. Puede encontrar agregados de 9 parche de Drawables de (casi) todas las versiones de Android en androiddrawables.com

Personalizando

Reconocemos la línea azul en uno de los 9 parches , por lo que creamos una copia local y cambiamos los colores según lo deseado.


La solución anterior no funciona con ActionBarSherlock 4.2 y, por lo tanto, no es compatible con Android 2.x. Aquí está el código de trabajo que configura el fondo de SearchView y el texto de sugerencia en ActionBarSherlock 4.2:

public static void styleSearchView(SearchView searchView, Context context) { View searchPlate = searchView.findViewById(R.id.abs__search_plate); searchPlate.setBackgroundResource(R.drawable.your_custom_drawable); AutoCompleteTextView searchText = (AutoCompleteTextView) searchView.findViewById(R.id.abs__search_src_text); searchText.setHintTextColor(context.getResources().getColor(R.color.your_custom_color)); }


Las soluciones anteriores pueden no funcionar si está utilizando la biblioteca appcompat. Es posible que deba modificar el código para que funcione en la biblioteca de appcompat.

Aquí está la solución de trabajo para la biblioteca appcompat.

@Override public boolean onCreateOptionsMenu(Menu menu) { getMenuInflater().inflate(R.menu.main_menu, menu); SearchManager searchManager = (SearchManager) getSystemService(Context.SEARCH_SERVICE); MenuItem searchMenuItem = menu.findItem(R.id.action_search); SearchView searchView = (SearchView) MenuItemCompat.getActionView(searchMenuItem); searchView.setSearchableInfo(searchManager.getSearchableInfo(getComponentName())); SearchView.SearchAutoComplete searchAutoComplete = (SearchView.SearchAutoComplete)searchView.findViewById(android.support.v7.appcompat.R.id.search_src_text); searchAutoComplete.setHintTextColor(Color.WHITE); searchAutoComplete.setTextColor(Color.WHITE); View searchplate = (View)searchView.findViewById(android.support.v7.appcompat.R.id.search_plate); searchplate.setBackgroundResource(R.drawable.texfield_searchview_holo_light); ImageView searchCloseIcon = (ImageView)searchView.findViewById(android.support.v7.appcompat.R.id.search_close_btn); searchCloseIcon.setImageResource(R.drawable.abc_ic_clear_normal); ImageView voiceIcon = (ImageView)searchView.findViewById(android.support.v7.appcompat.R.id.search_voice_btn); voiceIcon.setImageResource(R.drawable.abc_ic_voice_search); ImageView searchIcon = (ImageView)searchView.findViewById(android.support.v7.appcompat.R.id.search_mag_icon); searchIcon.setImageResource(R.drawable.abc_ic_search); return super.onCreateOptionsMenu(menu); }


Me cansé de hacer esto también y estoy usando v7. La aplicación se bloqueó cuando intenté capturar la página de searchPlate través de getIdentifier() así que lo hice de esta manera:

View searchPlate = searchView.findViewById(android.support.v7.appcompat.R.id.search_plate);


Primero, creemos un archivo XML llamado search_widget_background.xml, para usarlo como un archivo dibujable, es decir, debajo del directorio dibujable.

<?xml version="1.0" encoding="utf-8"?> <shape xmlns:android="http://schemas.android.com/apk/res/android" android:shape="rectangle" > <solid android:color="@color/red" /> </shape>

Este dibujo se usará como fondo para nuestro widget de búsqueda. Configuré el color en rojo porque eso es lo que pediste, pero puedes configurarlo en cualquier color definido por la etiqueta @color. Incluso puede modificarlo más utilizando los atributos definidos para la etiqueta de forma (hacer esquinas redondeadas, hacer un fondo ovalado, etc.).

El siguiente paso es establecer el fondo de nuestro widget de búsqueda a este. Esto se puede lograr de la siguiente manera:

public boolean onCreateOptionsMenu(Menu menu) { SearchView searchView = (SearchView)menu.findItem(R.id.my_search_view).getActionView(); Drawable d = getResources().getDrawable(R.drawable.search_widget_background); searchView.setBackground(d); ... }


Su método onCreateOptionsMenu debe ser:

@Override public boolean onCreateOptionsMenu(Menu menu) { getMenuInflater().inflate(R.menu.option, menu); SearchView searchView = (SearchView) menu.findItem(R.id.menu_search).getActionView(); int linlayId = getResources().getIdentifier("android:id/search_plate", null, null); ViewGroup v = (ViewGroup) searchView.findViewById(linlayId); v.setBackgroundResource(R.drawable.searchviewredversion); return super.onCreateOptionsMenu(menu); }

donde su elemento de búsqueda es menu_search fuera del curso

y aquí está el searchviewredversion (esta es la versión xhdpi): http://img836.imageshack.us/img836/5964/searchviewredversion.png


También me enfrenté al mismo problema. Usé la biblioteca de appcompat v7 y definí el estilo personalizado para ella. En la carpeta dibujable, coloque el archivo bottom_border.xml que se ve así:

<?xml version="1.0" encoding="utf-8"?> <layer-list xmlns:android="http://schemas.android.com/apk/res/android" > <item> <shape > <solid android:color="@color/blue_color" /> </shape> </item> <item android:bottom="0.8dp" android:left="0.8dp" android:right="0.8dp"> <shape > <solid android:color="@color/background_color" /> </shape> </item> <!-- draw another block to cut-off the left and right bars --> <item android:bottom="2.0dp"> <shape > <solid android:color="@color/main_accent" /> </shape> </item> </layer-list>

En la carpeta de valores styles_myactionbartheme.xml:

<?xml version="1.0" encoding="utf-8"?> <resources> <style name="AppnewTheme" parent="Theme.AppCompat.Light"> <item name="android:windowBackground">@color/background</item> <item name="android:actionBarStyle">@style/ActionBar</item> <item name="android:actionBarWidgetTheme">@style/ActionBarWidget</item> </style> <!-- Actionbar Theme --> <style name="ActionBar" parent="Widget.AppCompat.Light.ActionBar.Solid.Inverse"> <item name="android:background">@color/main_accent</item> <!-- <item name="android:icon">@drawable/abc_ic_ab_back_holo_light</item> --> </style> <style name="ActionBarWidget" parent="Theme.AppCompat.Light"> <!-- SearchView customization--> <!-- Changing the small search icon when the view is expanded --> <!-- <item name="searchViewSearchIcon">@drawable/ic_action_search</item> --> <!-- Changing the cross icon to erase typed text --> <!-- <item name="searchViewCloseIcon">@drawable/ic_action_remove</item> --> <!-- Styling the background of the text field, i.e. blue bracket --> <item name="searchViewTextField">@drawable/bottom_border</item> <!-- Styling the text view that displays the typed text query --> <item name="searchViewAutoCompleteTextView">@style/AutoCompleteTextView</item> </style> <style name="AutoCompleteTextView" parent="Widget.AppCompat.Light.AutoCompleteTextView"> <item name="android:textColor">@color/text_color</item> <!-- <item name="android:textCursorDrawable">@null</item> --> <!-- <item name="android:textColorHighlight">@color/search_view_selected_text</item> --> </style> </resources>

Definí el archivo custommenu.xml para mostrar el menú:

<menu xmlns:android="http://schemas.android.com/apk/res/android" xmlns:com.example.actionbartheme="http://schemas.android.com/apk/res-auto" > <item android:id="@+id/search" android:title="@string/search_title" android:icon="@drawable/search_buttonn" com.example.actionbartheme:showAsAction="ifRoom|collapseActionView" com.example.actionbartheme:actionViewClass="android.support.v7.widget.SearchView"/>

Su actividad debe extender ActionBarActivity en lugar de Activity.

@Override public boolean onCreateOptionsMenu(Menu menu) { // Inflate the menu; this adds items to the action bar if it is present. MenuInflater inflater = getMenuInflater(); inflater.inflate(R.menu.custommenu, menu); }

En archivo manifiesto:

<application android:allowBackup="true" android:icon="@drawable/ic_launcher" android:label="@string/app_name" android:theme="@style/AppnewTheme" >

Para más información vea aquí:
Aquí http://www.jayway.com/2014/06/02/android-theming-the-actionbar/


public boolean onCreateOptionsMenu(Menu menu) { ........ // Set the search plate color int linlayId = getResources().getIdentifier("android:id/search_plate", null, null); View view = searchView.findViewById(linlayId); Drawable drawColor = getResources().getDrawable(R.drawable.searchcolor); view.setBackground( drawColor ); ........ }

y este es el archivo searchablecolor.xml

<?xml version="1.0" encoding="utf-8"?> <layer-list xmlns:android="http://schemas.android.com/apk/res/android" > <item> <shape > <solid android:color="#ffffff" /> </shape> </item> <!-- main color --> <item android:bottom="1.5dp" android:left="1.5dp" android:right="1.5dp"> <shape > <solid android:color="#2c4d8e" /> </shape> </item> <!-- draw another block to cut-off the left and right bars --> <item android:bottom="18.0dp"> <shape > <solid android:color="#2c4d8e" /> </shape> </item> </layer-list>