Изменение фонового рисунка виджета searchview - программирование

Изменение фонового рисунка виджета searchview

Я пытаюсь изменить drawable, который находится в виджетах виджета панели действий Android.

В настоящее время это выглядит так: enter image description here

но мне нужно изменить синий фон на красный цвет.

Я пробовал много вещей, чтобы не сворачивать собственный виджет поиска, но ничего не работает.

Может ли кто-нибудь указать мне в правильном направлении, чтобы изменить это?

4b9b3361

Ответ 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-патч для сфокусированного состояния:

enter image description here

ПРИМЕЧАНИЕ.. Для простоты я использовал только изображения для плотности 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);
    }

}

Конечный эффект

Вот скриншот окончательного результата:

enter image description here

Как я добрался до этого

Я думаю, что стоит догадаться, как я добрался до этого, чтобы этот подход можно было использовать при настройке других представлений.

Проверка макета представления

Я проверил, как выглядит макет 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.attrR.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-патчей, поэтому мы создаем локальную копию и меняем цвета по желанию.

Ответ 2

Вышеупомянутые решения могут не работать, если вы используете библиотеку appcompat. Возможно, вам придется изменить код, чтобы он работал в библиотеке appcompat.

Вот рабочее решение для библиотеки 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);
}

Ответ 3

Ваш метод onCreateOptionsMenu должен быть:

@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);
    }

где ваш элемент поиска menu_search off course

и вот searchviewredversion (эта версия - версия xhdpi): http://img836.imageshack.us/img836/5964/searchviewredversion.png

enter image description here

Ответ 4

Решение выше не работает с ActionBarSherlock 4.2 и поэтому не поддерживает обратную совместимость с Android 2.x. Вот рабочий код, который устанавливает фон SearchView и текст подсказки в ActionBarSherlock 4.2:

public static void styleSearchView(SearchView searchView, Context context) {
    View searchPlate = searchView.findViewById(R.id.abs__search_plate);
    searchPlate.setBackgroundResource(R.drawable.your_custom_drawable);
    AutoCompleteTextView searchText = (AutoCompleteTextView) searchView.findViewById(R.id.abs__search_src_text);
    searchText.setHintTextColor(context.getResources().getColor(R.color.your_custom_color));
}

Ответ 5

Я тоже устал делать это, и я использую v7. Приложение было разбито, когда я попытался захватить searchPlate через getIdentifier(), поэтому я сделал это следующим образом:

View searchPlate = searchView.findViewById(android.support.v7.appcompat.R.id.search_plate);

Ответ 6

Сначала создайте XML файл с именем search_widget_background.xml, который будет использоваться в качестве переносимого, то есть под рисоваемым каталогом.

<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
    android:shape="rectangle" >

    <solid android:color="@color/red" />

</shape>

Этот drawable будет использоваться в качестве фона для нашего виджета поиска. Я установил цвет в красный цвет, потому что это то, что вы просили, но вы можете установить его для любого цвета, определенного тегом @color. Вы можете даже изменить его далее, используя атрибуты, определенные для тега формы (сделайте закругленные углы, сделайте овальный фон и т.д.).

Следующий шаг - установить фон нашего виджета поиска на этот. Это может быть выполнено следующим образом:

    public boolean onCreateOptionsMenu(Menu menu) {

        SearchView searchView = (SearchView)menu.findItem(R.id.my_search_view).getActionView();
        Drawable d = getResources().getDrawable(R.drawable.search_widget_background);
        searchView.setBackground(d);
...
    }

Ответ 7

Я также столкнулся с такой же проблемой. Я использовал библиотеку appcompat v7 и определенный пользовательский стиль для нее.  В выпадающей папке поместите файл bottom_border.xml, который выглядит следующим образом:

<?xml version="1.0" encoding="utf-8"?>
<layer-list xmlns:android="http://schemas.android.com/apk/res/android" >
<item>
  <shape >
      <solid android:color="@color/blue_color" />
  </shape>
</item>
<item android:bottom="0.8dp"
  android:left="0.8dp"
  android:right="0.8dp">
  <shape >
      <solid android:color="@color/background_color" />
  </shape>
</item>

<!-- draw another block to cut-off the left and right bars -->
<item android:bottom="2.0dp">
  <shape >
      <solid android:color="@color/main_accent" />
  </shape>
 </item>
</layer-list>

В папках значений styles_myactionbartheme.xml:

<?xml version="1.0" encoding="utf-8"?>
<resources>
  <style name="AppnewTheme" parent="Theme.AppCompat.Light">
    <item name="android:windowBackground">@color/background</item>
    <item name="android:actionBarStyle">@style/ActionBar</item>
    <item name="android:actionBarWidgetTheme">@style/ActionBarWidget</item>
</style> 
<!-- Actionbar Theme -->
<style name="ActionBar" parent="Widget.AppCompat.Light.ActionBar.Solid.Inverse">
    <item name="android:background">@color/main_accent</item>
    <!-- <item name="android:icon">@drawable/abc_ic_ab_back_holo_light</item> -->
</style> 
<style name="ActionBarWidget" parent="Theme.AppCompat.Light">
    <!-- SearchView customization-->
     <!-- Changing the small search icon when the view is expanded -->
    <!-- <item name="searchViewSearchIcon">@drawable/ic_action_search</item> -->
     <!-- Changing the cross icon to erase typed text -->
  <!--   <item name="searchViewCloseIcon">@drawable/ic_action_remove</item> -->
     <!-- Styling the background of the text field, i.e. blue bracket -->
    <item name="searchViewTextField">@drawable/bottom_border</item>
     <!-- Styling the text view that displays the typed text query -->
    <item name="searchViewAutoCompleteTextView">@style/AutoCompleteTextView</item>        
</style>

  <style name="AutoCompleteTextView" parent="Widget.AppCompat.Light.AutoCompleteTextView">
    <item name="android:textColor">@color/text_color</item>
  <!--   <item name="android:textCursorDrawable">@null</item> -->
    <!-- <item name="android:textColorHighlight">@color/search_view_selected_text</item> -->
</style>
</resources>

Я определил файл custommenu.xml для отображения меню:

<menu xmlns:android="http://schemas.android.com/apk/res/android"
   xmlns:com.example.actionbartheme="http://schemas.android.com/apk/res-auto" >  

<item android:id="@+id/search"
      android:title="@string/search_title"
      android:icon="@drawable/search_buttonn" 
     com.example.actionbartheme:showAsAction="ifRoom|collapseActionView"   
                 com.example.actionbartheme:actionViewClass="android.support.v7.widget.SearchView"/>

Ваша активность должна расширять ActionBarActivity вместо Activity.

@Override
public boolean onCreateOptionsMenu(Menu menu) 
{
    // Inflate the menu; this adds items to the action bar if it is present.
    MenuInflater inflater = getMenuInflater();
    inflater.inflate(R.menu.custommenu, menu);
}

В файле манифеста:

<application
    android:allowBackup="true"
    android:icon="@drawable/ic_launcher"
    android:label="@string/app_name"
    android:theme="@style/AppnewTheme" >

Для получения дополнительной информации см. здесь:
Здесь http://www.jayway.com/2014/06/02/android-theming-the-actionbar/

Ответ 8

public boolean onCreateOptionsMenu(Menu menu) {
........

        // Set the search plate color
        int linlayId = getResources().getIdentifier("android:id/search_plate", null, null);
        View view = searchView.findViewById(linlayId);
        Drawable drawColor = getResources().getDrawable(R.drawable.searchcolor);
        view.setBackground( drawColor );
........
    }

, и это файл searchablecolor.xml

<?xml version="1.0" encoding="utf-8"?>
<layer-list xmlns:android="http://schemas.android.com/apk/res/android" >
  <item>
      <shape >
          <solid android:color="#ffffff" />
      </shape>
  </item>

  <!-- main color -->
  <item android:bottom="1.5dp"
      android:left="1.5dp"
      android:right="1.5dp">
      <shape >
          <solid android:color="#2c4d8e" />
      </shape>
  </item>

  <!-- draw another block to cut-off the left and right bars -->
  <item android:bottom="18.0dp">
      <shape >
          <solid android:color="#2c4d8e" />
      </shape>
  </item>
</layer-list>