Introducción
Desafortunadamente, no hay forma de establecer el SearchView
estilo de campo de texto usando temas, estilos y herencia en XML, como puede hacer con el fondo de los elementos en el menú desplegable de ActionBar . Esto se debe a que selectableItemBackground
está catalogado como styleable en R.stylable
, mientras que searchViewTextField
(atributo tema que nos interesa) no lo es. Por lo tanto, no podemos acceder fácilmente desde los recursos XML (obtendrá un No resource found that matches the given name: attr 'android:searchViewTextField'
error).
Establecer el fondo del campo de texto SearchView desde el código
Por lo tanto, la única forma de sustituir adecuadamente el fondo del SearchView
campo de texto es entrar en sus componentes internos, obtener acceso a la vista que tiene un fondo establecido searchViewTextField
y establecer el nuestro.
NOTA: La solución a continuación depende solo de la identificación ( android:id/search_plate
) del elemento interno SearchView
, por lo que es más independiente de la versión del SDK que el recorrido secundario (por ejemplo, searchView.getChildAt(0)
para obtener la vista correcta interna SearchView
), pero no es a prueba de balas. Especialmente si algún fabricante decide volver a implementar SearchView
elementos internos y el elemento con la identificación mencionada anteriormente no está presente, el código no funcionará.
En SDK, el fondo para el campo de texto SearchView
se declara a través de nueve parches , por lo que lo haremos de la misma manera. Puede encontrar imágenes png originales en el directorio drawable-mdpi del repositorio git de Android . Estamos interesados en dos imágenes. Uno para el estado cuando el campo de texto está seleccionado (llamado textfield_search_selected_holo_light.9.png ) y otro para donde no está (llamado 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 se debe a textfield_search_default_holo_light
que no está presente en R.drawable . Por lo tanto, no se puede acceder fácilmente a través de él @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 al dibujo local.
NOTA: Estaba usando el tema Holo Light como base, pero puedes hacer lo mismo con Holo Dark . Parece que no hay una diferencia real en el estado seleccionado de 9 parches entre los temas claros y oscuros . Sin embargo, hay una diferencia en 9 parches para el estado predeterminado (ver Claro vs Oscuro ). Por lo tanto, probablemente no sea necesario hacer copias locales de 9 parches para el estado seleccionado , tanto para temas oscuros como claros (suponiendo que desee manejar ambos, y hacer que ambos se vean igual que en Holo Theme ). Simplemente haga una copia local y úsela enselector extraíble para ambos temas.
Ahora, deberá editar los nueve parches descargados según sus necesidades (es decir, cambiar el color azul a rojo). Puede echar un vistazo al archivo con la herramienta de dibujar 9 parches para verificar si está correctamente definido después de su edición.
He editado archivos usando GIMP con la herramienta de lápiz de un píxel (bastante fácil) pero probablemente usará la herramienta propia. Aquí está mi parche personalizado de 9 para el estado enfocado :
NOTA: Para simplificar, solo he usado imágenes para densidad mdpi . Tendrá que crear 9 parches para múltiples densidades de pantalla si desea el mejor resultado en cualquier dispositivo. Las imágenes para Holo SearchView
se pueden encontrar en mdpi , hdpi y xhdpi dibujables .
Ahora, necesitaremos crear un selector dibujable, para que se muestre la imagen adecuada según el estado de la vista. Crear 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 dibujo creado anteriormente para establecer el fondo para la LinearLayout
vista que contiene el campo de texto dentro SearchView
; su id es android:id/search_plate
. Así que aquí está cómo hacer esto rápidamente en el código, al crear el 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:
Como llegué a esto
Creo que vale la pena mencionar cómo llegué a esto, para que este enfoque se pueda utilizar al personalizar otras vistas.
Verificando el diseño de la vista
He comprobado cómo se SearchView
ve el diseño. En SearchView contructor se puede encontrar una línea que infla el diseño:
inflater.inflate(R.layout.search_view, this, true);
Ahora sabemos que el SearchView
diseño está en el archivo llamado res/layout/search_view.xml
. Mirando en search_view.xml podemos encontrar un LinearLayout
elemento interno (con id search_plate
) que tiene android.widget.SearchView$SearchAutoComplete
dentro (se parece al campo de texto de nuestra 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 searchViewTextField
atributo del tema actual .
Atributo de investigación (¿es fácilmente configurable?)
Para verificar cómo searchViewTextField
se establece el atributo, investigamos res / values / themes.xml . Hay un grupo de atributos relacionados por SearchView
defecto Theme
:
<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
. El Theme.Light
valor 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. A modo de comparación, ver otros temáticos atributos que están presentes tanto 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é se debe modificar?
Ahora sabemos que tendremos que acceder a search_plate
través del código. Sin embargo, todavía no sabemos cómo debería ser. En resumen, buscamos elementos dibujables utilizados como valores en los temas predeterminados: textfield_searchview_holo_dark.xml y textfield_searchview_holo_light.xml . Al observar el contenido, vemos que el elemento dibujable es el selector
que hace referencia a otros dos elementos dibujables (que resultan ser 9 parches más adelante) según el estado de visualización. Puede encontrar elementos dibujables agregados de 9 parches de (casi) todas las versiones de Android en androiddrawables.com
Personalización
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 desee.