工具栏搜索建议主题化

10

我试图将搜索建议更改为“浅色主题”。 我正在使用appcompat-v7:22.2.0库,并阅读有关自定义搜索视图小部件(android.support.v7.widget.SearchView)的新功能

首次尝试部分

工具栏

<android.support.v7.widget.Toolbar xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:background="?attr/colorPrimary"
    android:minHeight="?attr/actionBarSize"
    app:popupTheme="@style/ThemeOverlay.AppCompat.Light"
    app:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar" />

主题

<style name="Main.Theme" parent="Theme.AppCompat.Light.NoActionBar">
    <item name="colorPrimary">@color/red</item>
    <item name="colorPrimaryDark">@color/red_dark</item>
    <item name="searchViewStyle">@style/Main.Theme.SearchView</item>
</style>

SearchView 主题

<style name="Main.Theme.SearchView" parent="Widget.AppCompat.Light.SearchView">
    <item name="voiceIcon">@mipmap/test_icon</item>
</style>

这样我就无法影响搜索视图。为了测试它,我正在更改搜索视图中的语音图标,但它不会从默认值更改。

第二次尝试部分

第二次尝试是覆盖工具栏中的覆盖主题:

覆盖主题

<style name="Main.Theme.Overlay" parent="ThemeOverlay.AppCompat.Dark.ActionBar">
    <item name="searchViewStyle">@style/Main.Theme.SearchView</item>
</style>

我这样做得到了一些反馈,但失去了“材料设计”,尤其是我有一个“旧”的提示图标并且它被下划线所覆盖。 我的最终目标是更改搜索建议行的背景:

建议行布局

<item name="suggestionRowLayout">@layout/my_custom_layout</item>

我觉得我离完成这个还很远,你能帮帮我吗?


你找到解决方法了吗?我也遇到了同样的问题。为工具栏设置app:theme="@style/ThemeOverlay.AppCompat.ActionBar"会使建议弹出窗口变成浅色背景,但这并不能达到目的。 - Sreekanth
@Sreekanth:在工具栏中,你应该使用app:theme="@style/Main.Theme.Overlay"而不是app:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar" - Mehul Joisar
1
"Main.Theme.Overlay" 会是什么? - Sreekanth
@Sreekanth:这里没有解决方案,你呢? - Jumpa
3个回答

4

以下是我如何使用自己的搜索建议...

这是我的CountriesFragment文件,它只显示建议中所有国家名称。

关键在于我提供了自定义视图来显示建议列表。

public class CountriesFragment extends Fragment {

    private boolean mSearchCheck;
    private SimpleCursorAdapter mAdapter;
    public static final String TEXT_FRAGMENT = "TEXT_FRAGMENT";
    public static final String CITY_NAME = "cityName";
    private LayoutInflater mInflater;
    private ViewGroup mainContainer;

    private static final String[] COUNTRIES = {
            "Afghanistan", "Albania", "Algeria", "American Samoa", "Andorra", "Angola", "Anguilla", "Antarctica",
            "Antigua and Barbuda", "Argentina", "Armenia", "Aruba", "Australia", "Austria", "Azerbaijan", "Bahamas", "Bahrain", "Bangladesh", "Barbados",
            "Belarus", "Belgium", "Belize", "Benin", "Bermuda", "Bhutan", "Bolivia", "Bosnia and Herzegowina", "Botswana", "Bouvet Island", "Brazil",
            "British Indian Ocean Territory", "Brunei Darussalam", "Bulgaria", "Burkina Faso", "Burundi", "Cambodia", "Cameroon", "Canada", "Cape Verde",
            "Cayman Islands", "Central African Republic", "Chad", "Chile", "China", "Christmas Island", "Cocos (Keeling) Islands", "Colombia", "Comoros",
            "Congo", "Congo, the Democratic Republic of the", "Cook Islands", "Costa Rica", "Cote d'Ivoire", "Croatia (Hrvatska)", "Cuba", "Cyprus",
            "Czech Republic", "Denmark", "Djibouti", "Dominica", "Dominican Republic", "East Timor", "Ecuador", "Egypt", "El Salvador", "Equatorial Guinea",
            "Eritrea", "Estonia", "Ethiopia", "Falkland Islands (Malvinas)", "Faroe Islands", "Fiji", "Finland", "France", "France Metropolitan", "French Guiana",
            "French Polynesia", "French Southern Territories", "Gabon", "Gambia", "Georgia", "Germany", "Ghana", "Gibraltar", "Greece", "Greenland", "Grenada",
            "Guadeloupe", "Guam", "Guatemala", "Guinea", "Guinea-Bissau", "Guyana", "Haiti", "Heard and Mc Donald Islands", "Holy See (Vatican City State)",
            "Honduras", "Hong Kong", "Hungary", "Iceland", "India", "Indonesia", "Iran (Islamic Republic of)", "Iraq", "Ireland", "Israel", "Italy", "Jamaica",
            "Japan", "Jordan", "Kazakhstan", "Kenya", "Kiribati", "Korea, Democratic People's Republic of", "Korea, Republic of", "Kuwait", "Kyrgyzstan",
            "Lao, People's Democratic Republic", "Latvia", "Lebanon", "Lesotho", "Liberia", "Libyan Arab Jamahiriya", "Liechtenstein", "Lithuania", "Luxembourg",
            "Macau", "Macedonia, The Former Yugoslav Republic of", "Madagascar", "Malawi", "Malaysia", "Maldives", "Mali", "Malta", "Marshall Islands", "Martinique",
            "Mauritania", "Mauritius", "Mayotte", "Mexico", "Micronesia, Federated States of", "Moldova, Republic of", "Monaco", "Mongolia", "Montserrat", "Morocco",
            "Mozambique", "Myanmar", "Namibia", "Nauru", "Nepal", "Netherlands", "Netherlands Antilles", "New Caledonia", "New Zealand", "Nicaragua", "Niger", "Nigeria",
            "Niue", "Norfolk Island", "Northern Mariana Islands", "Norway", "Oman", "Pakistan", "Palau", "Panama", "Papua New Guinea", "Paraguay", "Peru", "Philippines",
            "Pitcairn", "Poland", "Portugal", "Puerto Rico", "Qatar", "Reunion", "Romania", "Russian Federation", "Rwanda", "Saint Kitts and Nevis", "Saint Lucia",
            "Saint Vincent and the Grenadines", "Samoa", "San Marino", "Sao Tome and Principe", "Saudi Arabia", "Senegal", "Seychelles", "Sierra Leone", "Singapore",
            "Slovakia (Slovak Republic)", "Slovenia", "Solomon Islands", "Somalia", "South Africa", "South Georgia and the South Sandwich Islands", "Spain", "Sri Lanka",
            "St. Helena", "St. Pierre and Miquelon", "Sudan", "Suriname", "Svalbard and Jan Mayen Islands", "Swaziland", "Sweden", "Switzerland", "Syrian Arab Republic",
            "Taiwan, Province of China", "Tajikistan", "Tanzania, United Republic of", "Thailand", "Togo", "Tokelau", "Tonga", "Trinidad and Tobago", "Tunisia",
            "Turkey", "Turkmenistan", "Turks and Caicos Islands", "Tuvalu", "Uganda", "Ukraine", "United Arab Emirates", "United Kingdom", "United States",
            "United States Minor Outlying Islands", "Uruguay", "Uzbekistan", "Vanuatu", "Venezuela", "Vietnam", "Virgin Islands (British)", "Virgin Islands (U.S.)",
            "Wallis and Futuna Islands", "Western Sahara", "Yemen", "Yugoslavia", "Zambia", "Zimbabwe"
    };

    public static CountriesFragment newInstance(String text) {
        CountriesFragment mFragment = new CountriesFragment();
        Bundle mBundle = new Bundle();
        mBundle.putString(TEXT_FRAGMENT, text);
        mFragment.setArguments(mBundle);
        return mFragment;
    }

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        loadHints();
    }

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
        View rootView = inflater.inflate(R.layout.fragment_countries, container, false);
        mInflater = inflater;
        mainContainer = (ViewGroup) rootView.findViewById(R.id.container);
        //rootView.setLayoutParams(new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT));
        return rootView;
    }

    @Override
    public void onActivityCreated(Bundle savedInstanceState) {
        super.onActivityCreated(savedInstanceState);
        setHasOptionsMenu(true);
    }

    @Override
    public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
        super.onCreateOptionsMenu(menu, inflater);
        inflater.inflate(R.menu.menu, menu);

        SearchView searchView = (SearchView) MenuItemCompat.getActionView(menu.findItem(R.id.menu_search));
        searchView.setQueryHint(this.getString(R.string.search));

        ((EditText) searchView.findViewById(android.support.v7.appcompat.R.id.search_src_text))
                .setHintTextColor(getResources().getColor(R.color.nliveo_white));


        searchView.setSuggestionsAdapter(mAdapter);
        searchView.setOnQueryTextListener(onQuerySearchView);
        searchView.setOnSuggestionListener(onQuerySuggestion);

        menu.findItem(R.id.menu_add).setVisible(true);
        menu.findItem(R.id.menu_search).setVisible(true);

        mSearchCheck = false;
    }

    @Override
    public boolean onOptionsItemSelected(MenuItem item) {

        switch (item.getItemId()) {

            case R.id.menu_add:
                addCountry();
                break;

            case R.id.menu_search:
                mSearchCheck = true;
                break;
        }
        return true;
    }

    private void addCountry() {
        final ViewGroup newView = (ViewGroup) mInflater.inflate(R.layout.country_row, mainContainer, false);
        final TextView countryName = (TextView) newView.findViewById(android.R.id.text1);
        countryName.setText(COUNTRIES[(int) (Math.random() * COUNTRIES.length)]);


        final Animation fadeIn = AnimationUtils.loadAnimation(getActivity(), R.anim.fade_in);
        final Animation fadeOut = AnimationUtils.loadAnimation(getActivity(), R.anim.fade_out);
        fadeIn.setFillAfter(false);
        fadeOut.setFillAfter(false);

        final ImageButton closeButton = (ImageButton) newView.findViewById(R.id.delete_button);
        closeButton.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                newView.startAnimation(fadeOut);
                new Handler().postDelayed(new Runnable() {
                    @Override
                    public void run() {
                        mainContainer.removeView(newView);
                    }
                }, fadeOut.getDuration());
            }
        });

        mainContainer.addView(newView, 0);
        newView.startAnimation(fadeIn);
    }

    private SearchView.OnQueryTextListener onQuerySearchView = new SearchView.OnQueryTextListener() {
        @Override
        public boolean onQueryTextSubmit(String query) {
            mSearchCheck = false;
            return false;
        }

        @Override
        public boolean onQueryTextChange(String query) {
            if (mSearchCheck) {
                // implement your search here
                giveSuggestions(query);
            }
            return false;
        }
    };

    private void giveSuggestions(String query) {
        final MatrixCursor cursor = new MatrixCursor(new String[]{BaseColumns._ID, CITY_NAME});
        for (int i = 0; i < COUNTRIES.length; i++) {
            if (COUNTRIES[i].toLowerCase().contains(query.toLowerCase()))
                cursor.addRow(new Object[]{i, COUNTRIES[i]});
        }
        mAdapter.changeCursor(cursor);
    }

    private SearchView.OnSuggestionListener onQuerySuggestion = new SearchView.OnSuggestionListener() {
        @Override
        public boolean onSuggestionSelect(int position) {
            return false;
        }

        @Override
        public boolean onSuggestionClick(int position) {
            return false;
        }
    };

    private void loadHints() {
        final String[] from = new String[]{CITY_NAME};
        final int[] to = new int[]{android.R.id.text1};
        mAdapter = new SimpleCursorAdapter(getActivity(),
                R.layout.hint_row,
                null,
                from,
                to,
                CursorAdapter.FLAG_REGISTER_CONTENT_OBSERVER);
    }
}

这里是 hint_row.xml 文件。

<?xml version="1.0" encoding="utf-8"?>
<TextView xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@android:id/text1"
    android:layout_width="match_parent"
    android:layout_height="48dp"
    android:textAppearance="?android:attr/textAppearanceListItemSmall"
    android:gravity="center_vertical"
    android:background="@color/nliveo_green_colorPrimaryDark"
    android:textColor="@color/nliveo_white"
    android:paddingLeft="15dp"
    android:paddingRight="15dp"
    android:minHeight="?android:attr/listPreferredItemHeightSmall"
    android:elevation="3dp"
    android:alpha="0.7" />

这是一个带有SearchView的简单菜单文件。menu.xml

<menu xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto">

    <item
        android:id="@+id/menu_search"
        app:actionViewClass="android.support.v7.widget.SearchView"
        android:icon="@mipmap/ic_search_white_24dp"
        app:showAsAction="ifRoom|collapseActionView"
        android:title="@string/search"/>
    <item
        android:id="@+id/menu_add"
        android:icon="@mipmap/ic_add_white_24dp"
        app:showAsAction="ifRoom"
        android:title="@string/add"/>

</menu>

我收到了这个美丽的建议... 自定义提示

1
请建议如何在工具栏使用暗色主题的情况下,为建议弹出窗口获取浅色主题。 - Machado

3

"Suggestions"是系统创建的动态列表,不属于活动内容。因此,您无法将浅色主题应用于它。

相反,您可以使用样式自定义建议,使其具有浅色主题的感觉。

使用这个hint_row.xml

<?xml version="1.0" encoding="utf-8"?>
<TextView xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@android:id/text1"
    style="@style/suggestionsTheme"
    android:layout_width="match_parent"
    android:layout_height="48dp"
    android:gravity="center_vertical"
    android:text="demo"
    android:paddingLeft="15dp"
    android:paddingRight="15dp" />

并应用这个样式

<style name="suggestionsTheme" parent="TextAppearance.AppCompat.Light.SearchResult.Subtitle" >
        <item name="android:background">@android:color/white</item>
        <item name="android:textColor">@android:color/black</item>

现在我得到了这个

Light suggestions

你可以根据需要添加更多样式


如何告诉应用程序将“hint_row.xml”用作建议TextView? - Sreekanth
请查看我的先前回答。使用上面的文件CountriesFragment.java - Azim Ansari
我发布了不同的答案,因为两个答案是不同的。第一个是关于自定义建议的,第二个是关于将轻量级appcompat搜索视图主题应用于建议的。两者彼此独立。一个人可以在自己的应用程序中使用自己想要的内容... - Azim Ansari
嗨,请问如何在这个建议列表中添加分隔符? - James

0

我知道我来晚了,但我认为这对那些仍在寻找此问题的人会有所帮助。如果使用Toolbar,建议的解决方案是有效的。首先,您需要在样式中覆盖Toolbar的主题,如下所示:

<style name="AppTheme.Toolbar" parent="Base.ThemeOverlay.AppCompat.Dark.ActionBar">
        <item name="searchViewStyle">@style/CustomSearchStyle</item>
    </style>

    <style name="CustomSearchStyle" parent="Base.Widget.AppCompat.SearchView.ActionBar">
        <item name="suggestionRowLayout">@layout/custom_search_layout</item>
    </style>

我使用了 Dark 主题,但我认为使用 Light 也可以解决这个问题。正如您所看到的,我已经覆盖了工具栏主题的 searchViewStyleSearchViewsuggestionRowLayout,在其中放置了自己的布局:

<?xml version="1.0" encoding="utf-8"?>
<!--
/*
 * Copyright (C) 2014 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
-->


<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="58dip"
    android:background="@color/white"
    style="@style/RtlOverlay.Widget.AppCompat.Search.DropDown">

    <!-- Icons come first in the layout, since their placement doesn't depend on
         the placement of the text views. -->
    <ImageView
        android:id="@android:id/icon1"
        android:layout_width="48dip"
        android:layout_height="48dip"
        android:scaleType="centerInside"
        android:layout_alignParentTop="true"
        android:layout_alignParentBottom="true"
        android:tint="@color/black"
        android:visibility="invisible"
        style="@style/RtlOverlay.Widget.AppCompat.Search.DropDown.Icon1" />

    <ImageView
        android:id="@+id/edit_query"
        android:layout_width="48dip"
        android:layout_height="48dip"
        android:scaleType="centerInside"
        android:layout_alignParentTop="true"
        android:layout_alignParentBottom="true"
        android:background="?attr/selectableItemBackground"
        android:visibility="gone"
        style="@style/RtlOverlay.Widget.AppCompat.Search.DropDown.Query" />

    <ImageView
        android:id="@android:id/icon2"
        android:layout_width="48dip"
        android:layout_height="48dip"
        android:scaleType="centerInside"
        android:layout_alignWithParentIfMissing="true"
        android:layout_alignParentTop="true"
        android:layout_alignParentBottom="true"
        android:visibility="gone"
        style="@style/RtlOverlay.Widget.AppCompat.Search.DropDown.Icon2" />


    <!-- The subtitle comes before the title, since the height of the title depends on whether the
         subtitle is visible or gone. -->
    <TextView android:id="@android:id/text2"
        style="?android:attr/dropDownItemStyle"
        android:singleLine="true"
        android:layout_width="match_parent"
        android:textColor="@color/black"
        android:textSize="16sp"
        tools:text="id/text2"
        android:layout_height="29dip"
        android:paddingBottom="4dip"
        android:gravity="top"
        android:layout_alignWithParentIfMissing="true"
        android:layout_alignParentBottom="true"
        android:visibility="gone"
        />

    <!-- The title is placed above the subtitle, if there is one. If there is no
         subtitle, it fills the parent. -->
    <TextView android:id="@android:id/text1"
        style="?android:attr/dropDownItemStyle"
        android:singleLine="true"
        android:textColor="@color/black"
        tools:text="id/text1"
        android:textStyle="bold"
        android:textSize="18sp"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_centerVertical="true"
        android:layout_above="@android:id/text2" />

</RelativeLayout>

这个布局我从原始主题中获取并进行了一些更改以满足我的需求。

注意:不幸的是,我没有找到如何更改标准的最近图标的方法,所以我将其保留了下来,因为对我来说这并不重要。

因此,要更改建议项的背景颜色,只需将其添加到根RelativeLayout中 - 在我的情况下,我将其更改为白色。您可以使用自己的颜色。 我检查了建议仅使用ImageView和id @android:id/icon1TextView和id @android:id/text1,因此我对这两个进行了更改。由于在Dark主题中,默认的最近图标是白色的,因此我添加了android:tint="@color/black"TextView可以按照您的喜好进行配置。

我们需要做的最后一件事就是将主题应用于我们的Toolbar

<android.support.v7.widget.Toolbar
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/toolbar"
    android:layout_width="match_parent"
    android:layout_height="?attr/actionBarSize"
    android:minHeight="?attr/actionBarSize"
    android:theme="@style/AppTheme.Toolbar"
    app:titleTextColor="@color/white"
    app:navigationIcon="?attr/homeAsUpIndicator"
    app:theme="@style/AppTheme.Toolbar"
    app:popupTheme="@style/ThemeOverlay.AppCompat.Light"
    tools:elevation="4dp">

这是我得到的结果:

enter image description here


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