Изменение фона для рисования виджета SearchView

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

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

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

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

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

9 ответов

Решение

вступление

К сожалению, нет возможности установить 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, который может быть использован в селекторе, показанном ниже, вместо ссылки на локальный объект.

ПРИМЕЧАНИЕ: я использовал тему Holo Light в качестве основы, но вы можете сделать то же самое с Holo Dark. Кажется, что нет никакой разницы в выбранных патчах состояния между темами Light и Dark. Тем не менее, есть разница в 9 патчей для состояния по умолчанию (см. Light vs Dark). Так что, вероятно, нет необходимости делать локальные копии 9-патчей для выбранного состояния, как для темных, так и для светлых тем (при условии, что вы хотите обработать оба и сделать так, чтобы они оба выглядели так же, как в Holo Theme). Просто сделайте одну локальную копию и используйте ее в селекторе, который можно рисовать для обеих тем.

Теперь вам нужно отредактировать загруженные девять патчей по своему усмотрению (т.е. изменить синий цвет на красный). Вы можете взглянуть на файл, используя инструмент draw 9-patch, чтобы проверить, правильно ли он определен после вашего редактирования.

Я редактировал файлы, используя GIMP, с помощью однопиксельного карандаша (довольно просто), но вы, вероятно, будете использовать свой собственный инструмент. Вот мой 9-патч для сфокусированного состояния:

ПРИМЕЧАНИЕ: для простоты я использовал только изображения для плотности mdpi. Вам нужно будет создать 9-патчи для разных плотностей экрана, если вы хотите получить лучший результат на любом устройстве. Изображения для Холо SearchView можно найти в MDPI, HDPI и XHDPI 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>

Мы будем использовать созданный выше способ рисования, чтобы установить фон для 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 значение также устанавливается в этом файле.

Теперь было бы здорово, если бы этот атрибут был доступен через 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 патчей) на основе состояния просмотра. Вы можете найти объединенные 9-патч-чертежи из (почти) всех версий Android на http://androiddrawables.com/widget.html

Пользовательская настройка

Мы распознаем синюю линию в одном из 9 патчей, поэтому создаем ее локальную копию и меняем цвета по желанию.

Вышеуказанные решения могут не работать, если вы используете библиотеку 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);
}

Ваш 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 конечно

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

Приведенное выше решение не работает с 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));
}

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

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

Обновить

Если вы используете AndroidX, вы можете сделать это следующим образом

    View searchPlate = svSearch. findViewById(androidx.appcompat.R.id.search_plate);
    if (searchPlate != null) {
        AutoCompleteTextView searchText = searchPlate.findViewById(androidx.appcompat.R.id.search_src_text);
        if (searchText != null){
            searchText.setTextSize(TypedValue.COMPLEX_UNIT_PX, getResources().getDimension(R.dimen.edittext_text_size));
            searchText.setMaxLines(1);
            searchText.setSingleLine(true);
            searchText.setTextColor(getResources().getColor(R.color.etTextColor));
            searchText.setHintTextColor(getResources().getColor(R.color.etHintColor));
            searchText.setBackground(null);
        }
    }

Я также столкнулся с той же проблемой. Я использовал библиотеку appcompat v7 и определил для нее собственный стиль. В папке drawable поместите файл 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/

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

<?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>

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

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

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

Я много копал об этом и, наконец, нашел это решение, и оно работает для меня!
Вы можете использовать это

Если вы используете appcompat, попробуйте следующее:

ImageView searchIconView = (ImageView) searchView.findViewById(android.support.v7.appcompat.R.id.search_button);
searchIconView.setImageResource(R.drawable.yourIcon);

Если вы используете androidx, попробуйте следующее:

ImageView searchIconView = (ImageView) searchView.findViewById(androidx.appcompat.R.id.search_button);
    searchIconView.setImageResource(R.drawable.yourIcon);

Это изменит значок просмотра по умолчанию.

Надеюсь, это поможет!

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>

Я объяснил в конце этого поста с изображениями, это относится к xamarin форм. Но я думаю, что вы можете понять это, потому что он основан на исходном коде searchview android

Как изменить изображение кнопки отмены поиска в формах xamarin

Если вы надуваете Searchview, например, "getMenuInflater(). Inflate(R.menu.search_menu, menu);". Затем вы можете настроить этот вид поиска с помощью style.xml, как показано ниже.

<style name="AppTheme" parent="Theme.AppCompat.DayNight.NoActionBar">
      <item name="searchViewStyle">@style/SearchView.ActionBar</item>
</style>

<style name="SearchView.ActionBar" parent="Widget.AppCompat.SearchView.ActionBar">
      <item name="queryBackground">@drawable/drw_search_view_bg</item>
      <item name="searchHintIcon">@null</item>
      <item name="submitBackground">@null</item>
      <item name="closeIcon">@drawable/vd_cancel</item>
      <item name="searchIcon">@drawable/vd_search</item>
</style>
Другие вопросы по тегам