Introdução
Infelizmente, não há como definir o SearchView
estilo do campo de texto usando temas, estilos e herança em XML, como você pode fazer com o segundo plano dos itens no menu suspenso ActionBar . Isto é porque selectableItemBackground
é listado como styleable em R.stylable
, ao passo que searchViewTextField
(atributo tema que estamos interessados em) não é. Portanto, não podemos acessá-lo facilmente a partir de recursos XML (você receberá um No resource found that matches the given name: attr 'android:searchViewTextField'
erro).
Configurando o SearchView segundo plano do campo de texto a partir do código
Portanto, a única maneira de substituir adequadamente o plano de fundo do SearchView
campo de texto é acessá-lo internamente, obter acesso à visualização que possui o plano de fundo com base searchViewTextField
e definir o nosso.
OBSERVAÇÃO: A solução abaixo depende apenas da id ( android:id/search_plate
) do elemento SearchView
, portanto, é mais independente da versão SDK do que a passagem das crianças (por exemplo, usar searchView.getChildAt(0)
para obter a visão correta dentro SearchView
), mas não é à prova de balas. Especialmente se algum fabricante decidir reimplementar SearchView
elementos internos e o ID acima mencionado não estiver presente - o código não funcionará.
No SDK, o plano de fundo do campo de texto SearchView
é declarado através de nove patches ; portanto, faremos da mesma maneira. Você pode encontrar imagens png originais no diretório drawable-mdpi do repositório git do Android . Estamos interessados em duas imagens. Um para o estado em que o campo de texto está selecionado (denominado textfield_search_selected_holo_light.9.png ) e outro para onde não está (chamado textfield_search_default_holo_light.9.png ).
Infelizmente, você precisará criar cópias locais das duas imagens, mesmo se desejar personalizar apenas o estado focado . Isso ocorre porque textfield_search_default_holo_light
não está presente no R..drawable . Portanto, não é de fácil acesso @android:drawable/textfield_search_default_holo_light
, o que poderia ser usado no seletor mostrado abaixo, em vez de fazer referência ao drawable local.
NOTA: Eu estava usando o tema Holo Light como base, mas você pode fazer o mesmo com o Holo Dark . Parece que não há diferença real nos 9 patches selecionados do estado entre os temas Claro e Escuro . No entanto, há uma diferença nos 9 patches para o estado padrão (consulte Claro vs Escuro ). Portanto, provavelmente não há necessidade de fazer cópias locais de 9 patches para o estado selecionado , para os temas Escuro e Claro (supondo que você queira lidar com ambos e fazer com que ambos pareçam os mesmos do Tema Holo ). Basta fazer uma cópia local e usá-la emselecionável para os dois temas.
Agora, você precisará editar nove patches baixados conforme sua necessidade (por exemplo, alterando a cor azul para vermelha). Você pode dar uma olhada no arquivo usando a ferramenta draw 9-patch para verificar se ele está definido corretamente após a sua edição.
Editei arquivos usando o GIMP com a ferramenta lápis de um pixel (bastante fácil), mas você provavelmente usará a ferramenta por conta própria. Aqui está o meu patch 9 personalizado para o estado focado :
NOTA: Para simplificar, usei apenas imagens para densidade mdpi . Você precisará criar 9 patches para várias densidades de tela se desejar o melhor resultado em qualquer dispositivo. As imagens para Holo SearchView
podem ser encontradas nos mdpi , hdpi e xhdpi drawable.
Agora, precisamos criar um seletor desenhável, para que a imagem apropriada seja exibida com base no estado da visualização. Crie um arquivo res/drawable/texfield_searchview_holo_light.xml
com o seguinte conteúdo:
<?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>
Usaremos o drawable criado acima para definir o plano de fundo da LinearLayout
visualização que contém o campo de texto SearchView
- seu ID é android:id/search_plate
. Então, veja como fazer isso rapidamente no código, ao criar o menu de opções:
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);
}
}
Efeito final
Aqui está a captura de tela do resultado final:
Como cheguei a isso
Acho que vale a pena mencionar como cheguei a isso, para que essa abordagem possa ser usada ao personalizar outras visualizações.
Verificando o layout da vista
Eu verifiquei como é o SearchView
layout. No contratador do SearchView, é possível encontrar uma linha que infla o layout:
inflater.inflate(R.layout.search_view, this, true);
Agora sabemos que o SearchView
layout está no arquivo nomeado res/layout/search_view.xml
. Olhando para search_view.xml , podemos encontrar um LinearLayout
elemento interno (com ID search_plate
) que contém android.widget.SearchView$SearchAutoComplete
(parece com o nosso campo de texto de exibição de pesquisa):
<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">
Agora, agora que o plano de fundo está definido com base no searchViewTextField
atributo do tema atual .
Atributo de investigação (é facilmente configurável?)
Para verificar como o searchViewTextField
atributo é definido, investigamos res / values / themes.xml . Há um grupo de atributos relacionados ao SearchView
padrão 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 o tema padrão, o valor é @drawable/textfield_searchview_holo_dark
. Para Theme.Light
valor também é definido nesse arquivo .
Agora, seria ótimo se esse atributo estivesse acessível através do R.styleable , mas, infelizmente, não é. Para comparação, consulte outros atributos do tema que estão presentes em themes.xml e R.attr, como textAppearance ou selectableItemBackground . Se searchViewTextField
estivesse presente em R.attr
(e R.stylable
), poderíamos simplesmente usar nosso seletor de desenho ao definir o tema para todo o aplicativo em XML. Por exemplo:
<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>
O que deve ser modificado?
Agora sabemos que teremos que acessar search_plate
através do código. No entanto, ainda não sabemos como deve ser. Em resumo, procuramos por elementos de desenho usados como valores em temas padrão: textfield_searchview_holo_dark.xml e textfield_searchview_holo_light.xml . Analisando o conteúdo, vemos que o drawable é o selector
que faz referência a outros dois drawables (que ocorrem com 9 patches posteriormente) com base no estado da visualização. Você pode encontrar drawables agregados de 9 patches em (quase) todas as versões do Android em androiddrawables.com
Customizando
Reconhecemos a linha azul em um dos 9 patches , então criamos uma cópia local e alteramos as cores conforme desejado.