Honeycomb - customize SearchView inside the action

2019-06-16 03:06发布

I have a field where the user can type a search query in the action bar of the application. This is declared in the action bar using a menu inflate in the Activity:

<menu
    xmlns:android="http://schemas.android.com/apk/res/android"
>
    <item
        android:id="@+id/action_search"
        android:showAsAction="ifRoom"
        android:actionViewClass="android.widget.SearchView"
        android:title="@string/search"
    ></item>
</menu>

I need to customize the appearance of the SearchView (for instance background and text color). So far I could not find a way to do it using XML (using styles or themes).

Is my only option to do it in the code when inflating the menu?


Edit #1: I have tried programmatically but I cannot get a simple way to set the text color. Plus when I do searchView.setBackgroundResource(...) The background is set on the global widget, (also when the SearchView is iconified).

Edit #2: Not much information on the Search Developer Reference either

6条回答
ゆ 、 Hurt°
2楼-- · 2019-06-16 03:36

How do you inflate the menu xml in your Activity? if you inflate the menu by using getMenuInflator() in your Activity, then the menu and also the searchView get the themed context, that have attached to the activity.

@Override
public boolean onCreateOptionsMenu(Menu menu) {
     getMenuInflater.inflate(R.menu.search_action_menu, menu);
}

if you check the source code of Activity.getMenuInflator() at API-15, you can see the themed context codes. Here it is.

     */
public MenuInflater getMenuInflater() {
    // Make sure that action views can get an appropriate theme.
    if (mMenuInflater == null) {
        initActionBar();
        if (mActionBar != null) {
            mMenuInflater = new MenuInflater(mActionBar.getThemedContext());
        } else {
            mMenuInflater = new MenuInflater(this);
        }
    }
    return mMenuInflater;
}
查看更多
兄弟一词,经得起流年.
3楼-- · 2019-06-16 03:40

adding my take on things which is probably a little more efficient and safe across different android versions.

you can actually get a numeric ID value from a string ID name. using android's hierarchyviewer tool, you can actually find the string IDs of the things you are interested in, and then just use findViewById(...) to look them up.

the code below sets the hint and text color for the edit field itself. you could apply the same pattern for other aspects that you wish to style.

private static synchronized int getSearchSrcTextId(View view) {
    if (searchSrcTextId == -1) {
        searchSrcTextId = getId(view, "android:id/search_src_text");
    }
    return searchSrcTextId;
}

private static int getId(View view, String name) {
    return view.getContext().getResources().getIdentifier(name, null, null);
}

@TargetApi(11)
private void style(View view) {
    ImageView iv;

    AutoCompleteTextView actv = (AutoCompleteTextView) view.findViewById(getSearchSrcTextId(view));
    if (actv != null) {
        actv.setHint(getDecoratedHint(actv,
            searchView.getContext().getResources().getString(R.string.titleApplicationSearchHint),
            R.drawable.ic_ab_search));
        actv.setTextColor(view.getContext().getResources().getColor(R.color.ab_text));
        actv.setHintTextColor(view.getContext().getResources().getColor(R.color.hint_text));
    }
}
查看更多
ゆ 、 Hurt°
4楼-- · 2019-06-16 03:41

In case anyone wants to modify the views directly, here is how you can change the colors/fonts/images and customize the search box to your pleasure. It is wrapped in a try/catch in case there are differences between versions or distributions, so it won't crash the app if this fails.

        // SearchView structure as we currently understand it:
        // 0 => linearlayout
        //      0 => textview (not sure what this does)
        //      1 => image view (the search icon before it's pressed)
        //      2 => linearlayout
        //           0 => linearlayout
        //               0 => ImageView (Search icon on the left of the search box)
        //               1 => SearchView$SearchAutoComplete (Object that controls the text, subclass of TextView)
        //               2 => ImageView (Cancel icon to the right of the text entry)
        //           1 => linearlayout
        //               0 => ImageView ('Go' icon to the right of cancel)
        //               1 => ImageView (not sure what this does)
        try {
            LinearLayout ll = (LinearLayout) searchView.getChildAt(0);
            LinearLayout ll2 = (LinearLayout) ll.getChildAt(2);
            LinearLayout ll3 = (LinearLayout) ll2.getChildAt(0);
            LinearLayout ll4 = (LinearLayout) ll2.getChildAt(1);
            TextView search_text = (TextView) ll3.getChildAt(1);
            search_text.setTextColor(R.color.search_text);
            ImageView cancel_icon = (ImageView)ll3.getChildAt(2);
            ImageView accept_icon = (ImageView)ll4.getChildAt(0);
            cancel_icon.setBackgroundDrawable(d);
            accept_icon.setBackgroundDrawable(d);
        } catch (Throwable e) {
            Log.e("SearchBoxConstructor", "Unable to set the custom look of the search box");
        }

This example shows changing the text color and the background colors of the cancel/accept images. searchView is a SearchView object already instantiated with it's background color:

Drawable d = getResources().getDrawable(R.drawable.search_widget_background);
searchView.setBackgroundDrawable(d);

Here is the drawable code:

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

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

</shape>

Obviously, this is hacky, but it will work for now.

查看更多
相关推荐>>
5楼-- · 2019-06-16 03:52

From ICS this is doable using themes and styles. I'm using ActionBarSherlock which makes it applicable also for HC and below.

  1. Add a style to define "android:textColorHint":

    <style name="Theme.MyHolo.widget" parent="@style/Theme.Holo">
        <item name="android:textColorHint">@color/text_hint_corp_dark</item>
    </style>
    
  2. Apply this as "actionBarWidgetTheme" to your theme:

    <style name="Theme.MyApp" parent="@style/Theme.Holo.Light.DarkActionBar">
        ...
        <item name="android:actionBarWidgetTheme">@style/Theme.MyHolo.widget</item>
    </style>
    
  3. Presto! Make sure that you use getSupportActionBar().getThemedContext() (or getSupportActionBar() for ActionBarSherlock) if any widgets are initiated where you might have other themes in effect.

查看更多
贪生不怕死
6楼-- · 2019-06-16 03:57

You can use the attribute android:actionLayout instead which lets you specify a layout to be inflated. Just have a layout with your SearchView and you won't have to modify anything really.

As to changing text style on the SearchView that is probably not possible as the SearchView is a ViewGroup. You should probably try changing text color via themes instead.

查看更多
Viruses.
7楼-- · 2019-06-16 03:57

Seibelj had an answer that is good if you want to change the icons. But you'll need to do it for every API version. I was using ICS with ActionBarSherlock and it didn't do justice for me but it did push me in the correct direction.

Below I change the text color and hint color. I showed how you might go about changing the icons too, though I have no interest in that for now (and you probably want to use the default icons anyways to be consistent)

@Override
public boolean onPrepareOptionsMenu(Menu menu) {
    // Set up the search menu
    SearchView searchView = (SearchView)menu.findItem(R.id.action_search).getActionView();
    traverseView(searchView, 0);

    return true;
}

private void traverseView(View view, int index) {
    if (view instanceof SearchView) {
        SearchView v = (SearchView) view;
        for(int i = 0; i < v.getChildCount(); i++) {
            traverseView(v.getChildAt(i), i);
        }
    } else if (view instanceof LinearLayout) {
        LinearLayout ll = (LinearLayout) view;
        for(int i = 0; i < ll.getChildCount(); i++) {
            traverseView(ll.getChildAt(i), i);
        }
    } else if (view instanceof EditText) {
        ((EditText) view).setTextColor(Color.WHITE);
        ((EditText) view).setHintTextColor(R.color.blue_trans);
    } else if (view instanceof TextView) {
        ((TextView) view).setTextColor(Color.WHITE);
    } else if (view instanceof ImageView) {
        // TODO dissect images and replace with custom images
    } else {
        Log.v("View Scout", "Undefined view type here...");
    }
}
查看更多
登录 后发表回答