创建一个看起来像材料设计指南的 SearchView

Posted

技术标签:

【中文标题】创建一个看起来像材料设计指南的 SearchView【英文标题】:Creating a SearchView that looks like the material design guidelines 【发布时间】:2015-02-17 19:59:45 【问题描述】:

我目前正在学习如何将我的应用程序转换为 Material Design,我现在有点卡住了。我已经添加了工具栏,并让导航抽屉覆盖了所有内容。我现在正在尝试创建一个看起来像 material guidelines 中的可扩展搜索: 这就是我现在所拥有的,我不知道如何使它像上面那样:

这是我的菜单 xml:

<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto">
    <item
        android:id="@+id/action_search"
        android:icon="@android:drawable/ic_menu_search"
        android:title="Search"
        app:showAsAction="always"
        app:actionViewClass="android.support.v7.widget.SearchView" />
</menu>

这行得通,我得到一个扩展到 SearchView 的菜单项,我可以很好地过滤我的列表。不过,它看起来一点也不像第一张照片。 我尝试在R.id.action_search 上使用MenuItemCompat.setOnActionExpandListener(),所以我可以将主页图标更改为后退箭头,但这似乎不起作用。监听器中没有任何东西被触发。即使这样有效,它仍然不会非常接近第一张图片。 如何在新的 appcompat 工具栏中创建一个看起来像材料指南的 SearchView?

【问题讨论】:

app:showAsAction="always|collapseActionView" 您可能想在这里看看我的回答:***.com/a/41013994/5326551 【参考方案1】:

实现预期效果的另一种方法是使用此Material Search View library。它会自动处理搜索历史,还可以向视图提供搜索建议。

示例:(显示为葡萄牙语,但也适用于英语和意大利语)。

设置

在你可以使用这个库之前,你必须在你的应用模块的br.com.mauker包中实现一个名为MsvAuthority的类,并且它应该有一个名为CONTENT_AUTHORITY的公共静态字符串变量。给它你想要的值,不要忘记在清单文件中添加相同的名称。 lib会使用这个文件来设置Content Provider权限。

示例:

MsvAuthority.java

package br.com.mauker;

public class MsvAuthority 
    public static final String CONTENT_AUTHORITY = "br.com.mauker.materialsearchview.searchhistorydatabase";

AndroidManifest.xml

<?xml version="1.0" encoding="utf-8"?>
<manifest ...>

    <application ... >
        <provider
        android:name="br.com.mauker.materialsearchview.db.HistoryProvider"
        android:authorities="br.com.mauker.materialsearchview.searchhistorydatabase"
        android:exported="false"
        android:protectionLevel="signature"
        android:syncable="true"/>
    </application>

</manifest>

用法

要使用它,请添加依赖项:

compile 'br.com.mauker.materialsearchview:materialsearchview:1.2.0'

然后,在您的 Activity 布局文件中,添加以下内容:

<br.com.mauker.materialsearchview.MaterialSearchView
    android:id="@+id/search_view"
    android:layout_
    android:layout_/>

之后,您只需使用getViewById() 获取MaterialSearchView 引用,然后使用MaterialSearchView#openSearch()MaterialSearchView#closeSearch() 打开或关闭它。

P.S.:不仅可以从Toolbar 打开和关闭视图。您可以使用基本上任何Button 中的openSearch() 方法,例如浮动操作按钮。

// Inside onCreate()
MaterialSearchView searchView = (MaterialSearchView) findViewById(R.id.search_view);
Button bt = (Button) findViewById(R.id.button);

bt.setOnClickListener(new View.OnClickListener() 
        @Override
        public void onClick(View v) 
            searchView.openSearch();
        
    );

您也可以使用返回按钮关闭视图,执行以下操作:

@Override
public void onBackPressed() 
    if (searchView.isOpen()) 
        // Close the search on the back button press.
        searchView.closeSearch();
     else 
        super.onBackPressed();
    

有关如何使用该库的更多信息,check the github page。

【讨论】:

优秀的库,以及抽象打开/关闭方法的好主意,以便不需要 MenuItem 来打开/关闭它,我计划在我的应用程序中使用这个带有搜索图标的 FloatingActionButton ,所以它会很好用。 为什么没有像'Search'这样的字符串参数?似乎该库将人们限制为字符串的英语或葡萄牙语版本:/ 但是可以通过使用自述文件中所述的样式来更改提示字符串。至于语音输入提示,稍后发布:github.com/Mauker1/MaterialSearchView/issues/23 @rpgmaker 检查最新更新,现在可以更改这些字符串。 @Mauker 知道如何将 android:imeOptions="actionSearch" 设置为组件的 EditText 吗? (我想在键盘上显示一个“搜索”按钮)【参考方案2】:

我知道它是一个旧线程,但仍在发布我刚刚创建的库。希望这可能对某人有所帮助。

https://github.com/Shahroz16/material-searchview

【讨论】:

这并不难,但我喜欢你的工作。它节省了我创建自己的搜索视图的时间。谢谢大哥!【参考方案3】:

这是我的尝试:

第 1 步:创建一个名为 SearchViewStyle 的样式

<style name="SearchViewStyle" parent="Widget.AppCompat.SearchView">
    <!-- Gets rid of the search icon -->
    <item name="searchIcon">@drawable/search</item>
    <!-- Gets rid of the "underline" in the text -->
    <item name="queryBackground">@null</item>
    <!-- Gets rid of the search icon when the SearchView is expanded -->
    <item name="searchHintIcon">@null</item>
    <!-- The hint text that appears when the user has not typed anything -->
    <item name="queryHint">@string/search_hint</item>
</style>

第 2 步:创建一个名为 simple_search_view_item.xml 的布局

<?xml version="1.0" encoding="utf-8"?>
<android.support.v7.widget.SearchView
    android:layout_gravity="end"
    android:layout_
    android:layout_
    style="@style/SearchViewStyle"
    xmlns:android="http://schemas.android.com/apk/res/android" />  

第 3 步:为此搜索视图创建一个菜单项

<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto">
    <item
        app:actionLayout="@layout/simple_search_view_item"
        android:title="@string/search"
        android:icon="@drawable/search"
        app:showAsAction="always" />
</menu>  

第 4 步:扩展菜单

@Override
public boolean onCreateOptionsMenu(Menu menu) 
    MenuInflater inflater = getMenuInflater();
    inflater.inflate(R.menu.menu_searchable_activity, menu);
    return true;
  

结果:

我唯一没能做的就是让它填满Toolbar 的整个宽度。如果有人可以帮助我做到这一点,那就太好了。

【讨论】:

I wasn't able to do was to make it fill the entire width,您使用的是哪个支持库版本?尝试为您的工具栏设置app:contentInsetStartWithNavigation="0dp" @LittleChild,试试 Magnesh 给出的解决方案。如果仍未解决,请尝试在工具栏中添加以下行。 app:contentInsetStartWithNavigation="0dp" app:contentInsetLeft="0dp" app:contentInsetStart="0dp" app:paddingStart="0dp" android:layout_marginLeft="0dp" android:layout_marginStart="0dp" 感谢您对 SearchViewStyle 中的每一行进行解释! Little Child 对于整个宽度,你可以这样做:("***.com/questions/27946569/…)【参考方案4】:

以下将创建一个与 Gmail 中的相同的 SearchView 并将其添加到给定的工具栏。您只需实现自己的“ViewUtil.convertDpToPixel”方法。

private SearchView createMaterialSearchView(Toolbar toolbar, String hintText) 

    setSupportActionBar(toolbar);
    ActionBar actionBar = getSupportActionBar();
    actionBar.setDisplayHomeAsUpEnabled(true);
    actionBar.setDisplayShowCustomEnabled(true);
    actionBar.setDisplayShowTitleEnabled(false);

    SearchView searchView = new SearchView(this);
    searchView.setIconifiedByDefault(false);
    searchView.setMaxWidth(Integer.MAX_VALUE);
    searchView.setMinimumHeight(Integer.MAX_VALUE);
    searchView.setQueryHint(hintText);

    int rightMarginFrame = 0;
    View frame = searchView.findViewById(getResources().getIdentifier("android:id/search_edit_frame", null, null));
    if (frame != null) 
        LinearLayout.LayoutParams frameParams = new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT);
        rightMarginFrame = ((LinearLayout.LayoutParams) frame.getLayoutParams()).rightMargin;
        frameParams.setMargins(0, 0, 0, 0);
        frame.setLayoutParams(frameParams);
    

    View plate = searchView.findViewById(getResources().getIdentifier("android:id/search_plate", null, null));
    if (plate != null) 
        plate.setLayoutParams(new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT));
        plate.setPadding(0, 0, rightMarginFrame, 0);
        plate.setBackgroundColor(Color.TRANSPARENT);
    

    int autoCompleteId = getResources().getIdentifier("android:id/search_src_text", null, null);
    if (searchView.findViewById(autoCompleteId) != null) 
        EditText autoComplete = (EditText) searchView.findViewById(autoCompleteId);
        LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(0, (int) ViewUtil.convertDpToPixel(36));
        params.weight = 1;
        params.gravity = Gravity.CENTER_VERTICAL;
        params.leftMargin = rightMarginFrame;
        autoComplete.setLayoutParams(params);
        autoComplete.setTextSize(16f);
    

    int searchMagId = getResources().getIdentifier("android:id/search_mag_icon", null, null);
    if (searchView.findViewById(searchMagId) != null) 
        ImageView v = (ImageView) searchView.findViewById(searchMagId);
        v.setImageDrawable(null);
        v.setPadding(0, 0, 0, 0);
        LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(LinearLayout.LayoutParams.WRAP_CONTENT, LinearLayout.LayoutParams.WRAP_CONTENT);
        params.setMargins(0, 0, 0, 0);
        v.setLayoutParams(params);
    

    toolbar.setTitle(null);
    toolbar.setContentInsetsAbsolute(0, 0);
    toolbar.addView(searchView);

    return searchView;

【讨论】:

【参考方案5】:

如果您使用的是android.support.v7 库,实际上很容易做到这一点。

步骤 - 1

声明一个菜单项

<item android:id="@+id/action_search"
    android:title="Search"
    android:icon="@drawable/abc_ic_search_api_mtrl_alpha"
    app:showAsAction="ifRoom|collapseActionView"
    app:actionViewClass="android.support.v7.widget.SearchView" />

步骤 - 2

扩展 AppCompatActivity 并在 onCreateOptionsMenu 中设置 SearchView。

import android.support.v7.widget.SearchView;

...

public class YourActivity extends AppCompatActivity 

    ...

    @Override
    public boolean onCreateOptionsMenu(Menu menu) 
        getMenuInflater().inflate(R.menu.menu_home, menu);
        // Retrieve the SearchView and plug it into SearchManager
        final SearchView searchView = (SearchView) MenuItemCompat.getActionView(menu.findItem(R.id.action_search));
        SearchManager searchManager = (SearchManager) getSystemService(SEARCH_SERVICE);
        searchView.setSearchableInfo(searchManager.getSearchableInfo(getComponentName()));
        return true;
    

    ... 


结果

【讨论】:

我投了赞成票,但是您使用的是哪个模拟器?我试过了,但我没有得到navigate-back按钮,而是一个搜索图标,它到屏幕左边缘的距离与X图标和屏幕右边缘之间的距离不一样(我没有动作溢出)。 Posted the question here,你能调查一下吗? 它不是材料搜索。这只是操作栏中通常的旧搜索 我回答了我自己的子问题,以使其始终可见,而无需单击搜索按钮,将行 searchView.setIconifiedByDefault(false); 添加到 onCreateOptionsMenu 函数。 另一个有用的花絮 - 如果您希望最初扩展搜索视图,请确保您拥有 app:showAsAction="always" 而不是 app:showAsAction="ifRoom|collapseActionView" 另外,使用此方法,即使搜索栏展开,OverflowIcon 仍然可见(即,3 点)。但有些应用程序通过完全扩展搜索并将背景更改为白色来处理搜索。喜欢GMail【参考方案6】:

要获得所需的 SearchView 外观,您可以使用样式。

首先,您需要为您的 SearchView 创建style,它应该如下所示:

<style name="CustomSearchView" parent="Widget.AppCompat.SearchView">
    <item name="searchIcon">@null</item>
    <item name="queryBackground">@null</item>
</style>

您可以在this 文章的“SearchView”部分下找到完整的属性列表。

其次,你需要为你的Toolbar创建一个style,用作ActionBar:

<style name="ToolbarSearchView" parent="Base.ThemeOverlay.AppCompat.Dark.ActionBar">
    <item name="searchViewStyle">@style/CustomSearchView</item>
</style>

最后你需要以这种方式更新你的工具栏主题属性:

<android.support.v7.widget.Toolbar xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:id="@+id/toolbar"
    android:layout_
    android:layout_
    app:theme="@style/ToolbarSearchView" />

结果:

注意:您需要直接更改 Toolbar 主题属性。如果您只是更新您的主题 searchViewStyle 属性,它不会影响您的 Toolbar

【讨论】:

嘿,您是自己添加了navigate-back(后退箭头)和cancel(x)图标还是自动添加的? @Solace 它们是自动添加的 它们是否仅在您开始在 SearchView 中编写搜索查询时出现,或者即使您没有编写任何内容并且搜索提示可见时它们也存在?我问是因为我的直到我开始编写查询才会出现。所以这些信息对我来说非常有用 @Solace navigate-back 始终显示,clear 仅在您编写一些搜索查询后显示。【参考方案7】:

经过一周的困惑。我想我已经弄明白了。 我现在只在工具栏中使用 EditText。这是 oj88 在 reddit 上向我建议的。 我现在有这个: 首先在我的活动的 onCreate() 中,我在工具栏的右侧添加了带有图像视图的 EditText,如下所示:

    // Setup search container view
    searchContainer = new LinearLayout(this);
    Toolbar.LayoutParams containerParams = new Toolbar.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT);
    containerParams.gravity = Gravity.CENTER_VERTICAL;
    searchContainer.setLayoutParams(containerParams);

    // Setup search view
    toolbarSearchView = new EditText(this);
    // Set width / height / gravity
    int[] textSizeAttr = new int[]android.R.attr.actionBarSize;
    int indexOfAttrTextSize = 0;
    TypedArray a = obtainStyledAttributes(new TypedValue().data, textSizeAttr);
    int actionBarHeight = a.getDimensionPixelSize(indexOfAttrTextSize, -1);
    a.recycle();
    LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(0, actionBarHeight);
    params.gravity = Gravity.CENTER_VERTICAL;
    params.weight = 1;
    toolbarSearchView.setLayoutParams(params);

    // Setup display
    toolbarSearchView.setBackgroundColor(Color.TRANSPARENT);
    toolbarSearchView.setPadding(2, 0, 0, 0);
    toolbarSearchView.setTextColor(Color.WHITE);
    toolbarSearchView.setGravity(Gravity.CENTER_VERTICAL);
    toolbarSearchView.setSingleLine(true);
    toolbarSearchView.setImeActionLabel("Search", EditorInfo.IME_ACTION_UNSPECIFIED);
    toolbarSearchView.setHint("Search");
    toolbarSearchView.setHintTextColor(Color.parseColor("#b3ffffff"));
    try 
        // Set cursor colour to white
        // https://***.com/a/26544231/1692770
        // https://github.com/android/platform_frameworks_base/blob/kitkat-release/core/java/android/widget/TextView.java#L562-564
        Field f = TextView.class.getDeclaredField("mCursorDrawableRes");
        f.setAccessible(true);
        f.set(toolbarSearchView, R.drawable.edittext_whitecursor);
     catch (Exception ignored) 
    

    // Search text changed listener
    toolbarSearchView.addTextChangedListener(new TextWatcher() 
        @Override
        public void beforeTextChanged(CharSequence s, int start, int count, int after) 
        

        @Override
        public void onTextChanged(CharSequence s, int start, int before, int count) 
            Fragment mainFragment = getFragmentManager().findFragmentById(R.id.container);
            if (mainFragment != null && mainFragment instanceof MainListFragment) 
                ((MainListFragment) mainFragment).search(s.toString());
            
        

        @Override
        public void afterTextChanged(Editable s) 
            // https://***.com/a/6438918/1692770
            if (s.toString().length() <= 0) 
                toolbarSearchView.setHintTextColor(Color.parseColor("#b3ffffff"));
            
        
    );
    ((LinearLayout) searchContainer).addView(toolbarSearchView);

    // Setup the clear button
    searchClearButton = new ImageView(this);
    Resources r = getResources();
    int px = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 16, r.getDisplayMetrics());
    LinearLayout.LayoutParams clearParams = new LinearLayout.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT);
    clearParams.gravity = Gravity.CENTER;
    searchClearButton.setLayoutParams(clearParams);
    searchClearButton.setImageResource(R.drawable.ic_close_white_24dp); // TODO: Get this image from here: https://github.com/google/material-design-icons
    searchClearButton.setPadding(px, 0, px, 0);
    searchClearButton.setOnClickListener(new View.OnClickListener() 
        @Override
        public void onClick(View v) 
            toolbarSearchView.setText("");
        
    );
    ((LinearLayout) searchContainer).addView(searchClearButton);

    // Add search view to toolbar and hide it
    searchContainer.setVisibility(View.GONE);
    toolbar.addView(searchContainer);

这行得通,但后来我遇到了一个问题,当我点击主页按钮时,没有调用 onOptionsItemSelected()。所以我无法通过按主页按钮来取消搜索。我尝试了几种在主页按钮上注册点击监听器的不同方法,但它们没有奏效。 最终我发现我使用的 ActionBarDrawerToggle 正在干扰事物,所以我将其删除。这个监听器然后开始工作:

    toolbar.setNavigationOnClickListener(new View.OnClickListener() 
        @Override
        public void onClick(View v) 
            // toolbarHomeButtonAnimating is a boolean that is initialized as false. It's used to stop the user pressing the home button while it is animating and breaking things.
            if (!toolbarHomeButtonAnimating) 
                // Here you'll want to check if you have a search query set, if you don't then hide the search box.
                // My main fragment handles this stuff, so I call its methods.
                FragmentManager fragmentManager = getFragmentManager();
                final Fragment fragment = fragmentManager.findFragmentById(R.id.container);
                if (fragment != null && fragment instanceof MainListFragment) 
                    if (((MainListFragment) fragment).hasSearchQuery() || searchContainer.getVisibility() == View.VISIBLE) 
                        displaySearchView(false);
                        return;
                    
                
            

            if (mDrawerLayout.isDrawerOpen(findViewById(R.id.navigation_drawer)))
                mDrawerLayout.closeDrawer(findViewById(R.id.navigation_drawer));
            else
                mDrawerLayout.openDrawer(findViewById(R.id.navigation_drawer));
        
    );

所以我现在可以使用主页按钮取消搜索,但我还不能按返回按钮来取消它。所以我将这个添加到 onBackPressed() 中:

    FragmentManager fragmentManager = getFragmentManager();
    final Fragment mainFragment = fragmentManager.findFragmentById(R.id.container);
    if (mainFragment != null && mainFragment instanceof MainListFragment) 
        if (((MainListFragment) mainFragment).hasSearchQuery() || searchContainer.getVisibility() == View.VISIBLE) 
            displaySearchView(false);
            return;
        
    

我创建了这个方法来切换 EditText 和菜单项的可见性:

public void displaySearchView(boolean visible) 
    if (visible) 
        // Stops user from being able to open drawer while searching
        mDrawerLayout.setDrawerLockMode(DrawerLayout.LOCK_MODE_LOCKED_CLOSED);

        // Hide search button, display EditText
        menu.findItem(R.id.action_search).setVisible(false);
        searchContainer.setVisibility(View.VISIBLE);

        // Animate the home icon to the back arrow
        toggleActionBarIcon(ActionDrawableState.ARROW, mDrawerToggle, true);

        // Shift focus to the search EditText
        toolbarSearchView.requestFocus();

        // Pop up the soft keyboard
        new Handler().postDelayed(new Runnable() 
            public void run() 
                toolbarSearchView.dispatchTouchEvent(MotionEvent.obtain(SystemClock.uptimeMillis(), SystemClock.uptimeMillis(), MotionEvent.ACTION_DOWN, 0, 0, 0));
                toolbarSearchView.dispatchTouchEvent(MotionEvent.obtain(SystemClock.uptimeMillis(), SystemClock.uptimeMillis(), MotionEvent.ACTION_UP, 0, 0, 0));
            
        , 200);
     else 
        // Allows user to open drawer again
        mDrawerLayout.setDrawerLockMode(DrawerLayout.LOCK_MODE_UNLOCKED);

        // Hide the EditText and put the search button back on the Toolbar.
        // This sometimes fails when it isn't postDelayed(), don't know why.
        toolbarSearchView.postDelayed(new Runnable() 
            @Override
            public void run() 
                toolbarSearchView.setText("");
                searchContainer.setVisibility(View.GONE);
                menu.findItem(R.id.action_search).setVisible(true);
            
        , 200);

        // Turn the home button back into a drawer icon
        toggleActionBarIcon(ActionDrawableState.BURGER, mDrawerToggle, true);

        // Hide the keyboard because the search box has been hidden
        InputMethodManager imm = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE);
        imm.hideSoftInputFromWindow(toolbarSearchView.getWindowToken(), 0);
    

我需要一种方法来在抽屉图标和后退按钮之间切换工具栏上的主页按钮。我最终在this SO answer 中找到了下面的方法。虽然我稍微修改了一下以使我更有意义:

private enum ActionDrawableState 
    BURGER, ARROW


/**
 * Modified version of this, https://***.com/a/26836272/1692770<br>
 * I flipped the start offset around for the animations because it seemed like it was the wrong way around to me.<br>
 * I also added a listener to the animation so I can find out when the home button has finished rotating.
 */
private void toggleActionBarIcon(final ActionDrawableState state, final ActionBarDrawerToggle toggle, boolean animate) 
    if (animate) 
        float start = state == ActionDrawableState.BURGER ? 1.0f : 0f;
        float end = Math.abs(start - 1);
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) 
            ValueAnimator offsetAnimator = ValueAnimator.ofFloat(start, end);
            offsetAnimator.setDuration(300);
            offsetAnimator.setInterpolator(new AccelerateDecelerateInterpolator());
            offsetAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() 
                @Override
                public void onAnimationUpdate(ValueAnimator animation) 
                    float offset = (Float) animation.getAnimatedValue();
                    toggle.onDrawerSlide(null, offset);
                
            );
            offsetAnimator.addListener(new Animator.AnimatorListener() 
                @Override
                public void onAnimationStart(Animator animation) 

                

                @Override
                public void onAnimationEnd(Animator animation) 
                    toolbarHomeButtonAnimating = false;
                

                @Override
                public void onAnimationCancel(Animator animation) 

                

                @Override
                public void onAnimationRepeat(Animator animation) 

                
            );
            toolbarHomeButtonAnimating = true;
            offsetAnimator.start();
        
     else 
        if (state == ActionDrawableState.BURGER) 
            toggle.onDrawerClosed(null);
         else 
            toggle.onDrawerOpened(null);
        
    

这行得通,我已经设法解决了我在此过程中发现的一些错误。我不认为它是 100%,但它对我来说足够好。

编辑:如果您想在 XML 而不是 Java 中添加搜索视图,请执行以下操作:

工具栏.xml:

<android.support.v7.widget.Toolbar 
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:id="@+id/toolbar"
    contentInsetLeft="72dp"
    contentInsetStart="72dp"
    android:layout_
    android:layout_
    android:background="?attr/colorPrimary"
    android:elevation="4dp"
    android:minHeight="?attr/actionBarSize"
    app:contentInsetLeft="72dp"
    app:contentInsetStart="72dp"
    app:popupTheme="@style/ActionBarPopupThemeOverlay"
    app:theme="@style/ActionBarThemeOverlay">

    <LinearLayout
        android:id="@+id/search_container"
        android:layout_
        android:layout_
        android:gravity="center_vertical"
        android:orientation="horizontal">

        <EditText
            android:id="@+id/search_view"
            android:layout_
            android:layout_
            android:layout_weight="1"
            android:background="@android:color/transparent"
            android:gravity="center_vertical"
            android:hint="Search"
            android:imeOptions="actionSearch"
            android:inputType="text"
            android:maxLines="1"
            android:paddingLeft="2dp"
            android:singleLine="true"
            android:textColor="#ffffff"
            android:textColorHint="#b3ffffff" />

        <ImageView
            android:id="@+id/search_clear"
            android:layout_
            android:layout_
            android:layout_gravity="center"
            android:paddingLeft="16dp"
            android:paddingRight="16dp"
            android:src="@drawable/ic_close_white_24dp" />
    </LinearLayout>
</android.support.v7.widget.Toolbar>

你的Activity的onCreate():

    searchContainer = findViewById(R.id.search_container);
    toolbarSearchView = (EditText) findViewById(R.id.search_view);
    searchClearButton = (ImageView) findViewById(R.id.search_clear);

    // Setup search container view
    try 
        // Set cursor colour to white
        // https://***.com/a/26544231/1692770
        // https://github.com/android/platform_frameworks_base/blob/kitkat-release/core/java/android/widget/TextView.java#L562-564
        Field f = TextView.class.getDeclaredField("mCursorDrawableRes");
        f.setAccessible(true);
        f.set(toolbarSearchView, R.drawable.edittext_whitecursor);
     catch (Exception ignored) 
    

    // Search text changed listener
    toolbarSearchView.addTextChangedListener(new TextWatcher() 
        @Override
        public void beforeTextChanged(CharSequence s, int start, int count, int after) 
        

        @Override
        public void onTextChanged(CharSequence s, int start, int before, int count) 
            Fragment mainFragment = getFragmentManager().findFragmentById(R.id.container);
            if (mainFragment != null && mainFragment instanceof MainListFragment) 
                ((MainListFragment) mainFragment).search(s.toString());
            
        

        @Override
        public void afterTextChanged(Editable s) 
        
    );

    // Clear search text when clear button is tapped
    searchClearButton.setOnClickListener(new View.OnClickListener() 
        @Override
        public void onClick(View v) 
            toolbarSearchView.setText("");
        
    );

    // Hide the search view
    searchContainer.setVisibility(View.GONE);

【讨论】:

效果很好,看起来很棒,谢谢!但是,我没有在代码中创建布局,而是在 xml 中创建了带有 EditText 和 ImageView 的 LinearLayout,然后在 onCreate 中对其进行了膨胀。 是的,我尝试在 XML 中执行此操作,但我认为我做错了,因为 Android Studio 不会在布局 XML 中为我提供自动完成功能。 您能否使用所需的相应 XML 布局设计更新此答案?这可以很好地帮助其他人。 @Mike 你能更新你的答案并放上你完整的 github 源代码吗? 请将完整的项目发布到github【参考方案8】:

您问题中的第一个屏幕截图不是公共小部件。支持 SearchView (android.support.v7.widget.SearchView) 模仿 Android 5.0 Lollipop 的 SearchView (android.widget.SearchView)。您的第二个屏幕截图被其他材料设计的应用程序(如 Google Play)使用。

您的第一个屏幕截图中的 SearchView 用于 Drive、YouTube 和其他封闭源代码的 Google Apps。幸运的是,它也用于Android 5.0 Dialer。您可以尝试向后移植视图,但它使用一些 5.0 API。

您要查看的类是:

SearchEditTextLayout、AnimUtils 和 DialtactsActivity 了解如何使用视图。您还需要来自ContactsCommon 的资源。

祝你好运。

【讨论】:

感谢您对此进行调查,我希望已经有一些东西可以做到这一点。现在我刚刚使用了一个带有透明背景的 EditText,它似乎可以满足我的需要。 这个答案让我非常不安。为什么谷歌使用一个恰好符合他们自己的材料设计指南的私有小部件,然后为我们发布一个不符合的糟糕小部件?现在每个开发人员都在独自挣扎?这有什么可能的原因?

以上是关于创建一个看起来像材料设计指南的 SearchView的主要内容,如果未能解决你的问题,请参考以下文章

Android 切换按钮 - 材料设计

根据材料设计指南实施 SearchView

材料设计的ButtomSheet没有正确显示 - 快速

创建交互式可视化的指南?

主题颜色材料设计与角度材料

Google Material Design ALL 24 立面图