Search code examples
androidandroid-viewandroid-drawablesearchviewandroid-styles

How can I style a SearchView according to its state?


I'm trying to style a SearchView to display it differently when it is focused by the user, as in Amazon's app:

Focused

SearchView, focused

Not focused

SearchView, not focused

I see from this article that starting with v21 one can use styleable attributes to customize the SearchView's display, like queryBackground:

<!-- Background for the section containing the search query -->
    <attr name="queryBackground" format="reference" />

I tried setting a drawable for this property via my app's style:

Style

<style name="AppTheme.SearchView" parent="Widget.AppCompat.SearchView">
    <item name="queryBackground">@drawable/shape_search</item>
</style>

Drawable

<?xml version="1.0" encoding="UTF-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
    <item android:state_focused="false">
        <shape xmlns:android="http://schemas.android.com/apk/res/android"
               android:padding="12dp"
               android:shape="rectangle">
            <solid android:color="#FFF"/>
            <stroke
                android:width="0.3dp"
                android:color="@color/colorAccent"/>
            <corners android:radius="5dip"/>
            <padding android:bottom="0dip" android:left="0dip" android:right="0dip" android:top="0dip"/>
        </shape>
    </item>
    <item android:state_focused="true">
        <shape xmlns:android="http://schemas.android.com/apk/res/android"
               android:padding="12dp"
               android:shape="rectangle">
            <solid android:color="#FFF"/>
            <stroke
                android:width="3dp"
                android:color="@color/colorAccent"/>
            <corners android:radius="5dip"/>
            <padding android:bottom="0dip" android:left="0dip" android:right="0dip" android:top="0dip"/>
        </shape>
    </item>
</selector>

However this does not work as expected: the first style is always selected, wether I am focusing the SearchView or not. I tried using other state selectors like state_active or even state_window_focused which mentions when a view's window has input focus, but in each case focusing the SearchView didn't change its display.

Is there a way to display this SearchView differently in those two states?


Solution

  • it's 05/06/2018 I think you had found the solution for you but I think my answer maybe helpful for other people I use kotlin, if you use java, it's the same

    In your view (activity, fragment,..):

     svSearch.setOnQueryTextFocusChangeListener(object : View.OnFocusChangeListener {
            override fun onFocusChange(v: View?, hasFocus: Boolean) {
                svSearch.isSelected =  hasFocus
                // isIconified() return true if search view lost focus, this line handle for user press back button case
                // as default when user press back button, the search view lost focus but view doesn't change state (collapse if width = wrap_content) 
                svSearch.isIconified = !hasFocus
            }
    
     })
    

    Selector:

    <selector xmlns:android="http://schemas.android.com/apk/res/android">
        <item android:state_selected="false">
           // something 
        </item>
        <item android:state_selected="true">
           // something 
        </item>
    </selector>