蜂巢 - 在操作栏中自定义SearchView

9

我有一个字段,用户可以在应用程序的操作栏中输入搜索查询。这是在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>

我需要自定义SearchView的外观(例如背景和文本颜色)。到目前为止,我无法找到使用XML(使用样式或主题)进行此操作的方法。
我的唯一选择是在填充菜单时在代码中进行吗?
编辑 #1:我已经尝试了编程,但是我无法找到一种简单的方法来设置文本颜色。而且当我执行searchView.setBackgroundResource(...)时,背景设置在全局小部件上(当SearchView被图标化时也是如此)。
编辑 #2:搜索开发者参考中没有太多信息。

你正在膨胀那个视图吗?如果是这样,我不知道如何使setBckRsrc()适用于全局小部件。可以在xml中完成或在膨胀时完成。我已经没有更多的想法了。 - Nikola Despotoski
6个回答

9

如果你想更改图标,Seibelj提供的答案是很好的。但你需要为每个API版本都进行更改。我使用带有ActionBarSherlock的ICS时,它对我并没有起到太大的作用,但它确实指导了我正确的方向。

接下来,我将更改文字颜色和提示颜色。我还展示了如何更改图标,尽管我现在对此没有兴趣(而且你可能想使用默认图标以保持一致性)

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

3
您的解决方案对我非常有效。对于ImageViews,我使用((ImageView) view).setColorFilter(Color.LTGRAY)来匹配其他ActionBar元素的样式,而不改变默认图标。 - Jose_GD

5

以下是我对事情的看法,可能更加高效和跨不同版本的安卓设备更安全。

你可以从字符串ID名称中实际上获取一个数字ID值。使用安卓的hierarchyviewer工具,你可以找到你感兴趣的东西的字符串IDs,然后只需使用findViewById(...)查找它们。

下面的代码为编辑框本身设置了提示和文字颜色。您可以将相同的模式应用于您希望样式化的其他方面。

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

3
你可以使用属性android:actionLayout代替,它允许您指定要填充的布局。只需使用包含SearchView的布局即可,无需实际修改任何内容。
至于在SearchView上更改文本样式,这可能是不可能的,因为SearchView是一个ViewGroup。您应该尝试通过主题来更改文本颜色。

1
你有没有想过 EditText 背景的主题属性可能是什么?对我来说,它似乎是一个标准的 EditText,但我需要能够仅更改它(是啊,有时在项目中有一位图形设计师真的很痛苦...):) - Vincent Mimoun-Prat
找不到与SearchView样式相关的内容(这就是您想要更改的内容吗)?您可以尝试通过代码查看SearchView内部的视图,然后进行更改。但这种方法有点hacky :) - alexanderblom
是的,我已经看过了,但我不喜欢它,因为一旦制造商能够自定义他们的用户界面,这个东西就会很快失效。 - Vincent Mimoun-Prat

2

如果有人想直接修改视图,以下是如何更改颜色/字体/图片并自定义搜索框以满足您的需求。它被包装在try/catch中,以防版本或分发之间存在差异,因此如果失败,它不会使应用程序崩溃。

        // 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");
        }

这个例子展示了如何改变取消/接受图片的文本颜色和背景颜色。searchView是一个已经实例化并设置了背景颜色的SearchView对象:

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

这里是可绘制代码:
<?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>

显然,这种方法有些粗糙,但目前可以使用。

不要忘记使用search_text.setHintTextColor(R.color.search_text); - Erik B

1
从ICS开始,可以使用主题和样式来实现这一点。我正在使用ActionBarSherlock,这使得它也适用于HC及以下版本。
  1. 添加一个样式来定义 "android:textColorHint":

    <style name="Theme.MyHolo.widget" parent="@style/Theme.Holo">
        <item name="android:textColorHint">@color/text_hint_corp_dark</item>
    </style>
    
  2. 将其应用为您的主题中的 "actionBarWidgetTheme":

    <style name="Theme.MyApp" parent="@style/Theme.Holo.Light.DarkActionBar">
        ...
        <item name="android:actionBarWidgetTheme">@style/Theme.MyHolo.widget</item>
    </style>
    
  3. 完成!请确保在任何小部件被初始化时使用 getSupportActionBar().getThemedContext()(或 ActionBarSherlock 中的 getSupportActionBar()),如果有其他主题生效。


0
你如何在Activity中填充菜单XML?如果你使用getMenuInflator()在Activity中填充菜单,那么菜单和搜索视图将获得与Activity相关联的主题上下文。
@Override
public boolean onCreateOptionsMenu(Menu menu) {
     getMenuInflater.inflate(R.menu.search_action_menu, menu);
}

如果您检查API-15中Activity.getMenuInflator()的源代码,您可以看到有关主题上下文的代码。以下是代码:

     */
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;
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接