【问题标题】:Honeycomb - customize SearchView inside the action barHoneycomb - 在操作栏中自定义 SearchView
【发布时间】:2011-10-14 06:04:00
【问题描述】:

我有一个字段,用户可以在应用程序的操作栏中输入搜索查询。这是使用 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:Search Developer Reference 的信息也不多

【问题讨论】:

  • 你在夸大这种观点吗?如果你这样做,我不知道 setBckRsrc() 如何申请全局小部件。从 xml 中执行..或在充气时执行。我没有想法

标签: android android-3.0-honeycomb


【解决方案1】:

如果您想更改图标,Seibelj 有一个很好的答案。但是你需要 为每个 API 版本执行此操作。我将 ICS 与 ActionBarSherlock 一起使用,它对我来说并不公平,但它确实将我推向了正确的方向。

下面我更改了文本颜色和提示颜色。我展示了你可能会如何改变 图标也是如此,虽然我现在对此不感兴趣(而且您可能还是希望使用默认图标以保持一致)

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

【讨论】:

  • 您的解决方案非常适合我。对于我做的 ImageViews ((ImageView) view).setColorFilter(Color.LTGRAY) 来匹配其他 ActionBar 元素的样式,而不更改默认图标
【解决方案2】:

添加我对跨不同 android 版本可能更高效和安全的东西的看法。

您实际上可以从字符串 ID 名称中获取数字 ID 值。使用android的hierarchyviewer工具,其实可以找到你感兴趣的东西的字符串ID,然后用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 上的文本样式,这可能是不可能的,因为SearchViewViewGroup。您可能应该尝试通过主题更改文本颜色。

    【讨论】:

    • 您知道 EditText 的背景的主题属性可能是什么吗?在我看来,它是一个标准的 EditText,但我只需要能够更改那个(是的,有时在项目中拥有一个图形设计师是一种痛苦......):)
    • 找不到与仅 SearchView 的样式相关的任何内容(这就是您要更改的内容)?您可以尝试在代码中浏览 SearchView 中的视图,然后以这种方式更改内容。不过,那会有点 hacky :)
    • 是的,我已经看过了,但我不喜欢它,因为一旦制造商能够自定义他们的用户界面,这肯定会破坏......
    【解决方案4】:

    如果有人想直接修改视图,您可以通过以下方法更改颜色/字体/图像并根据自己的喜好自定义搜索框。它包含在 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>
    

    很明显,这很 hacky,但它现在可以工作。

    【讨论】:

    • 别忘了 search_text.setHintTextColor(R.color.search_text);
    【解决方案5】:

    在 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())。

    【讨论】:

      【解决方案6】:

      如何在 Activity 中扩展菜单 xml?如果您在 Activity 中使用 getMenuInflator() 为菜单充气,则菜单和 searchView 都会获得附加到 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;
      }
      

      【讨论】: