创建看起来像材料设计准则的SearchView

 mobiledu2502931517 发布于 2022-12-04 15:38

我目前正在学习如何将我的应用程序转换为Material设计,现在我有点卡住了.我添加了工具栏,我的导航抽屉覆盖了所有内容.

我现在正在尝试创建一个类似于材料指南中的可扩展搜索: 在此输入图像描述

这就是我现在所拥有的,我无法弄清楚如何使它如上所述:
我的搜索

这是我的菜单xml:



    

这有效,我得到一个扩展到SearchView的菜单项,我可以很好地过滤我的列表.虽然看起来不像第一张照片.

我尝试使用MenuItemCompat.setOnActionExpandListener(),R.id.action_search所以我可以将主页图标更改为后退箭头,但这似乎不起作用.侦听器中没有任何内容被触发.即使它起作用,它仍然不会非常接近第一张图像.

如何在新的appcompat工具栏中创建看起来像材质指南的SearchView?

7 个回答
  • 如果您使用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步

    在SearchView中扩展AppCompatActivityonCreateOptionsMenu设置.

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

    结果

    在此输入图像描述

    在此输入图像描述

    2022-12-11 02:05 回答
  • 这是我尝试这样做的:

    第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_
        
        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.如果有人可以帮助我这样做那么那就是金色的.

    2022-12-11 02:11 回答
  • 另一种可以达到预期效果的方法是使用此材料搜索视图库.它自动处理搜索历史记录,也可以向视图提供搜索建议.

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

    样品

    建立

    在使用此lib之前,必须在应用程序模块MsvAuthoritybr.com.mauker包中实现一个名为的类,并且它应该有一个名为的公共静态String变量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_/>
    

    在此之后,你只需要获得MaterialSearchView通过参考getViewById(),并打开它,或者使用其关闭MaterialSearchView#openSearch()MaterialSearchView#closeSearch().

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

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

    有关如何使用lib的更多信息,请查看github页面.

    2022-12-11 02:12 回答
  • 我知道它是一个旧线程,但仍然发布我刚刚创建的库.希望这可以帮助某人.

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

    材料搜索视图

    2022-12-11 02:13 回答
  • 您问题中的第一个屏幕截图不是公共小部件.支持SearchView(android.support.v7.widget.SearchView)模仿Android 5.0 Lollipop的SearchView(android.widget.SearchView).您的第二个屏幕截图被其他材料设计的应用使用,例如Google Play.

    您的第一个屏幕截图中的SearchView用于云端硬盘,YouTube和其他闭源Google Apps.幸运的是,它也用于Android 5.0拨号器.您可以尝试向后移植视图,但它使用一些5.0 API.

    您将要查看的类是:

    SearchEditTextLayout,AnimUtils和DialtactsActivity了解如何使用View.您还需要来自ContactsCommon的资源.

    祝你好运.

    2022-12-11 02:14 回答
  • 要获得SearchView所需的外观,您可以使用样式.

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

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

    属性的整个列表,你可以找到在此文章中,"搜索查看"部分.

    其次,你需要创建一个stylefor Toolbar,用作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.

    2022-12-11 02:14 回答
  • 经过一个星期的困惑.我想我已经明白了.
    我现在只使用工具栏内的EditText.这是由redjit上的oj88向我建议的.

    我现在有这个:
    新的SearchView

    首先在我的活动的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
            // /sf/ask/17360801/
            // 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) {
                // /sf/ask/17360801/
                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);
        }
    }
    

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

    private enum ActionDrawableState {
        BURGER, ARROW
    }
    
    /**
     * Modified version of this, /sf/ask/17360801/<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添加搜索视图,请执行以下操作:

    toolbar.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:min
        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>
    

    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
            // /sf/ask/17360801/
            // 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);
    

    2022-12-11 02:57 回答
撰写答案
今天,你开发时遇到什么问题呢?
立即提问
热门标签
PHP1.CN | 中国最专业的PHP中文社区 | PNG素材下载 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有