вступление
К сожалению, нет способа установить SearchView
стиль текстового поля с использованием тем, стилей и наследования в XML, как это можно сделать с фоном элементов в раскрывающемся списке ActionBar . Это происходит потому , что selectableItemBackground
перечислено как styleable дюйма R.stylable
, в то время как searchViewTextField
(атрибут темы , что мы заинтересованы в) нет. Таким образом, мы не можем легко получить к нему доступ из ресурсов XML (вы получитеNo resource found that matches the given name: attr 'android:searchViewTextField'
об ошибке).
Установка фона текстового поля SearchView из кода
Итак, единственный способ правильно заменить фон SearchView
текстового поля - это проникнуть внутрь его, получить доступ к представлению, для которого задан фон, searchViewTextField
и установить собственный.
ПРИМЕЧАНИЕ. Приведенное ниже решение зависит только от id ( android:id/search_plate
) элемента внутри SearchView
, поэтому оно более не зависит от версии SDK, чем обход дочерних элементов (например, использование searchView.getChildAt(0)
для перехода к нужному виду внутри SearchView
), но оно не является пуленепробиваемым. Особенно, если какой-то производитель решит доработать внутренностиSearchView
а элемент с указанным выше идентификатором отсутствует - код не будет работать.
В SDK фон для текстового поля SearchView
объявлен с помощью девяти патчей , поэтому мы сделаем это так же. Вы можете найти оригинальный PNG изображение в вытяжке-MDPI каталоге репозитория Android мерзавца . Нас интересуют два изображения. Один для состояния, когда выбрано текстовое поле (с именем textfield_search_selected_holo_light.9.png ), а другой для того, где его нет (с именем textfield_search_default_holo_light.9.png ).
К сожалению, вам придется создавать локальные копии обоих изображений, даже если вы хотите настроить только сфокусированное состояние. Это потому, что textfield_search_default_holo_light
его нет в R.drawable . Таким образом, к нему нелегко получить доступ @android:drawable/textfield_search_default_holo_light
, который можно использовать в селекторе, показанном ниже, вместо ссылки на локальный drawable.
ПРИМЕЧАНИЕ. Я использовал тему Holo Light в качестве основы, но вы можете сделать то же самое с Holo Dark . Кажется, что нет никакой реальной разницы в выбранных 9-патчах состояния между темами Light и Dark . Однако есть разница в 9 патчах для состояния по умолчанию (см. « Свет против темноты» ). Так что, вероятно, нет необходимости делать локальные копии 9-патчей для выбранного состояния как для темной, так и для светлой тем (при условии, что вы хотите обрабатывать обе темы и сделать их так же, как в голографической теме ). Просто сделайте одну локальную копию и используйте ее вселектор для обеих тем.
Теперь вам нужно отредактировать загруженные девять патчей в соответствии с вашими потребностями (т.е. изменить синий цвет на красный). Вы можете взглянуть на файл с помощью инструмента draw 9-patch, чтобы проверить, правильно ли он определен после вашего редактирования.
Я редактировал файлы с помощью GIMP с помощью однопиксельного карандаша (довольно легко), но вы, вероятно, воспользуетесь своим собственным инструментом. Вот мой настроенный 9-патч для сфокусированного состояния :
ПРИМЕЧАНИЕ. Для простоты я использовал только изображения для плотности mdpi . Вам нужно будет создать 9 патчей для экрана с разной плотностью, если вы хотите добиться наилучшего результата на любом устройстве. Изображения для Holo SearchView
можно найти в форматах mdpi , hdpi и xhdpi с возможностью рисования .
Теперь нам нужно создать настраиваемый селектор, чтобы правильное изображение отображалось в зависимости от состояния просмотра. Создайте файл res/drawable/texfield_searchview_holo_light.xml
со следующим содержанием:
<?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>
Мы будем использовать созданный выше объект для рисования, чтобы установить фон для LinearLayout
представления, содержащего текстовое поле внутри SearchView
- его идентификатор android:id/search_plate
. Вот как это быстро сделать в коде при создании меню параметров:
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);
}
}
Окончательный эффект
Вот скриншот окончательного результата:
Как я до этого добрался
Думаю, стоит рассказать, как я к этому пришел, чтобы этот подход можно было использовать при настройке других представлений.
Проверка макета просмотра
Я проверил, как SearchView
выглядит макет. В конструкторе SearchView можно найти строку, раздувающую макет:
inflater.inflate(R.layout.search_view, this, true);
Теперь мы знаем, что SearchView
макет находится в файле с именем res/layout/search_view.xml
. Заглянув в search_view.xml, мы можем найти внутренний LinearLayout
элемент (с идентификатором search_plate
), который находится android.widget.SearchView$SearchAutoComplete
внутри него (похоже на наше текстовое поле просмотра поиска):
<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">
Теперь, когда фон установлен на основе searchViewTextField
атрибута текущей темы .
Изучение атрибута (легко ли его настроить?)
Чтобы проверить, как установлен searchViewTextField
атрибут, мы исследуем файл res / values / themes.xml . По SearchView
умолчанию есть группа атрибутов, связанных с 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>
Мы видим, что для темы по умолчанию значение равно @drawable/textfield_searchview_holo_dark
. В этом файле также задаетсяTheme.Light
значение For .
Было бы здорово, если бы этот атрибут был доступен через R.styleable , но, к сожалению, это не так. Для сравнения, увидеть другие тематические атрибуты , которые присутствуют как в themes.xml и R.attr как textAppearance или selectableItemBackground . Если бы searchViewTextField
он присутствовал в R.attr
(и R.stylable
), мы могли бы просто использовать наш настраиваемый селектор при определении темы для всего нашего приложения в XML. Например:
<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>
Что нужно изменить?
Теперь мы знаем, что нам нужно будет получить доступ search_plate
через код. Однако мы до сих пор не знаем, как это должно выглядеть. Короче говоря, мы ищем чертежи, используемые в качестве значений в темах по умолчанию: textfield_searchview_holo_dark.xml и textfield_searchview_holo_light.xml . Глядя на контент, мы видим, что drawable - это объект, selector
который ссылается на два других чертежа (которые позже будут иметь 9 патчей) в зависимости от состояния представления. Вы можете найти агрегированные чертежи с 9 патчами (почти) для всех версий Android на androiddrawables.com
Пользовательская настройка
Мы узнаем синюю линию в одном из 9 участков , поэтому мы создаем ее локальную копию и меняем цвета по желанию.