Posterior a investigar con expertos en el tema, programadores de deferentes áreas y profesores hemos dado con la respuesta al dilema y la compartimos en este post.
Solución:
Intro
Desafortunadamente, no hay forma de configurar 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 ActionBar. Esto es porque selectableItemBackground
aparece como elegante en R.stylable
, mientras que searchViewTextField
(tema attribute que nos interesa) no lo es. Por lo tanto, no podemos acceder a él fácilmente desde los recursos XML (obtendrá una No resource found that matches the given name: attr 'android:searchViewTextField'
error).
Configurar el fondo del campo de texto de SearchView desde el código
Entonces, la única forma de sustituir adecuadamente el fondo de SearchView
El campo de texto es entrar en su interior, adquirir acceso a la vista que tiene un fondo establecido en función de searchViewTextField
y establecer el nuestro.
NOTA: La siguiente solución depende solo de la identificación (android:id/search_plate
) de elemento dentro SearchView
, por lo que es más independiente de la versión del SDK que el cruce de niños (p. ej., usando searchView.getChildAt(0)
para llegar a la vista correcta dentro SearchView
), pero no es a prueba de balas. Especialmente si algún fabricante decide reimplementar los componentes internos de SearchView
y el elemento con la identificación mencionada anteriormente no está presente, el código no funcionará.
En SDK, el fondo del campo de texto en SearchView
se declara a través de nueve parches, por lo que lo haremos de la misma manera. Puedes encontrar original png imágenes en el directorio drawable-mdpi del repositorio git de Android. Estamos interesados en dos imágenes. Uno para el estado cuando se selecciona el campo de texto (llamado textfield_search_selected_holo_light.9.png) y otro para donde no lo está (llamado textfield_search_default_holo_light.9.png).
Desafortunadamente, tendrá que crear copias locales de ambas imágenes, incluso si solo desea personalizar enfocado estado. Esto es porque textfield_search_default_holo_light
no está presente en R.drawable. Por lo tanto, no es de fácil acceso 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 al dibujable local.
NOTA: Estaba usando Luz holográfica tema como base, pero puedes hacer lo mismo con Holo oscuro. Parece que no hay una diferencia real en estado seleccionado 9 parches entre temas claros y oscuros. Sin embargo, hay una diferencia en los 9 parches para estado predeterminado (ver Luz vs Oscuridad). Por lo tanto, probablemente no sea necesario hacer copias locales de 9 parches para estado seleccionado, para ambos Oscuro y Luz temas (asumiendo que desea manejar ambos, y hacer que ambos se vean igual que en Tema Holo). Simplemente haga una copia local y utilícela en selector dibujable 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 usando la herramienta de dibujo de 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 9 personalizado para estado enfocado:
NOTA: Para simplificar, solo he usado imágenes para mdpi densidad. Tendrás que crear 9 parches para múltiples densidades de pantalla si desea el mejor resultado en cualquier dispositivo. Imágenes para HoloSearchView
se puede encontrar en mdpi, hdpi y xhdpi dibujables.
Ahora, necesitaremos crear un selector dibujable, de modo que se muestre la imagen adecuada según el estado de la vista. Crea un archivo res/drawable/texfield_searchview_holo_light.xml
con el siguiente contenido:
Usaremos el dibujable creado anteriormente para establecer el fondo para LinearLayout
vista que contiene el campo de texto dentro SearchView
– su identificación es android:id/search_plate
. Entonces, aquí se explica 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 usar al personalizar otras vistas.
Comprobando el diseño de la vista
He comprobado como SearchView
el diseño parece. En el constructor de SearchView se puede encontrar una línea que infla el diseño:
inflater.inflate(R.layout.search_view, this, true);
Ahora sabemos que SearchView
el diseño está en el archivo llamado res/layout/search_view.xml
. Buscando en search_view.xml podemos encontrar un interior LinearLayout
elemento (con id search_plate
) que tiene android.widget.SearchView$SearchAutoComplete
dentro de él (se parece al campo de texto de la vista de búsqueda):
Ahora, ahora que el fondo se establece en función de los temas actuales searchViewTextField
attribute.
Investigando attribute (¿se puede configurar fácilmente?)
Para comprobar como searchViewTextField
attribute está configurado, investigamos res / values / themes.xml. Hay un grupo de attributes relacionado con SearchView
en defecto Theme
:
¿Qué debería modificarse?
Ahora sabemos que tendremos que acceder search_plate
a través del código. Sin embargo, todavía no sabemos cómo debería verse. En resumen, buscamos elementos de diseño utilizados como valores en los temas predeterminados: textfield_searchview_holo_dark.xml y textfield_searchview_holo_light.xml. Mirando el contenido vemos que el dibujable es selector
que hacen referencia a otros dos elementos de diseño (que posteriormente serán 9 parches) según el estado de la vista. Puede encontrar elementos de diseño 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 como deseamos.
Es posible que las soluciones anteriores no funcionen si está utilizando la biblioteca appcompat. Puede que tenga que modificar el código para que funcione para la biblioteca 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);
Tu onCreateOptionsMenu
el método 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 está tu elemento de búsqueda menu_search
por supuesto
y aqui esta el searchviewredversion
(esta es la versión xhdpi): http://img836.imageshack.us/img836/5964/searchviewredversion.png
Puedes sustentar nuestra función exponiendo un comentario y dejando una valoración te lo agradecemos.