Ответ 1
Введение
К сожалению, нет способа установить стиль текстового поля SearchView
, используя темы, стили и наследование в XML, как вы можете сделать с фоном элементов в раскрывающемся списке ActionBar. Это связано с тем, что selectableItemBackground
указан как стиль в 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-изображения в каталоге drawable-mdpi Android git хранилище. Нам интересно два изображения. Один для состояния, когда выбрано текстовое поле (называемое 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-патчах для состояния по умолчанию (см. Light vs Dark). Таким образом, вероятно, нет необходимости создавать локальные копии 9-патчей для выбранного состояния, как для темных, так и для светлых тем (предполагая, что вы хотите обрабатывать оба, и сделать их одинаковыми, как в теме Holo). Просто создайте одну локальную копию и используйте ее в селекторе, предназначенном для обеих тем.
Теперь вам нужно отредактировать загруженные девять патчей в соответствии с вашими потребностями (т.е. сменить синий цвет на красный). Вы можете посмотреть файл с помощью нарисовать 9-патч-инструмент, чтобы проверить, правильно ли он определен после редактирования.
Я редактировал файлы с помощью GIMP с помощью инструмента с одним пиксельным карандашом (довольно просто), но вы, вероятно, будете использовать инструмент твой собственный. Здесь мой настраиваемый 9-патч для сфокусированного состояния:
ПРИМЕЧАНИЕ.. Для простоты я использовал только изображения для плотности mdpi. Вам нужно будет создать 9 патчей для множества плотностей экрана, если вы хотите получить лучший результат на любом устройстве. Изображения для Holo SearchView
можно найти в mdpi, hdpi и xhdpi drawable.
Теперь нам нужно создать drawable селектор, чтобы отображалось правильное изображение в зависимости от состояния представления. Создайте файл 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>
Мы будем использовать созданный выше drawable для установки фона для представления 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 contructor можно найти строку, которая раздувает макет:
inflater.inflate(R.layout.search_view, this, true);
Теперь мы знаем, что макет SearchView
находится в файле с именем res/layout/search_view.xml
. Взгляд в search_view.xmlмы можем найти внутренний элемент LinearLayout
(с id 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
значение также установлено в этом файле.
Теперь было бы здорово, если бы этот атрибут был доступен через R.styleable, но, к сожалению, это не так. Для сравнения см. Другие атрибуты темы, которые присутствуют как в themes.xml, так и R.attr, например textAppearance или selectableItemBackground. Если searchViewTextField
присутствовал в R.attr
(и R.stylable
), мы могли бы просто использовать наш drawable селектор при определении темы для всего нашего приложения в 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
через код. Однако мы до сих пор не знаем, как это должно выглядеть. Короче говоря, мы ищем drawables, используемые в качестве значений по умолчанию: textfield_searchview_holo_dark.xml и textfield_searchview_holo_light.xml. Рассматривая содержимое, мы видим, что drawable - это selector
, который ссылается на два других чертежа (которые позже будут на 9 патчей) в зависимости от состояния представления. Вы можете найти объединенные 9-патч-черточки из (почти) всех версий Android на androiddrawables.com
Настройка
Мы признаем синюю линию в одном из 9-патчей, поэтому мы создаем локальную копию и меняем цвета по желанию.