Вступ
На жаль, немає можливості встановити 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 у каталозі Dravable-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
, що може бути використане у показаному нижче селекторі, замість посилання на локальний малюнок.
ПРИМІТКА: Я використовував тему Holo Light як основу, але ви можете зробити те ж саме з Holo Dark . Здається, що немає жодної реальної різниці у вибраних станах 9-патчів між темами Light і Dark . Однак є різниця у 9-патчах за станом за замовчуванням (див. Світло проти Темного ). Тому, ймовірно, немає необхідності робити локальні копії 9-патчів для вибраного стану для темних і світлих тем (якщо припустити, що ви хочете обробити обидва та зробити так, щоб обидва виглядали так само, як у темі Holo ). Просто зробіть одну локальну копію та використовуйте їїперемикач для обох тем.
Тепер вам потрібно буде відредагувати завантажені дев'ять патчів відповідно до ваших потреб (тобто змінити синій колір на червоний). Ви можете переглянути файл за допомогою інструмента малювання 9-патчів, щоб перевірити, чи правильно він визначений після редагування.
Я редагував файли, використовуючи GIMP, інструментом для олівців з одним пікселем (досить легко), але ви, ймовірно, використовуєте власний інструмент. Ось мій індивідуальний 9-патч для зосередженого стану :
ПРИМІТКА. Для простоти я використовував лише зображення для щільності mdpi . Вам доведеться створити 9 патчів для різної щільності екрана, якщо ви хочете отримати найкращий результат на будь-якому пристрої. Зображення для Холо SearchView
можуть бути знайдені в MDPI , ІПЧР і 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
елемент (з 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
), ми можемо просто використовувати наш графічний селектор, визначаючи тему для всієї нашої програми в 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 . Дивлячись на вміст, ми бачимо, що тематичне зображення, selector
яке посилається на два інші малюнки (які, можливо, пізніше будуть 9-латними), базується на стані перегляду. На сайті androiddrawables.com ви можете знайти зведені 9 патчі з чернетки (майже) всієї версії Android
Налаштування
Ми розпізнаємо синю лінію в одному з 9-ти патчів , тому створюємо локальну її копію та змінюємо кольори за бажанням.