美文网首页
Android中SearchView的使用

Android中SearchView的使用

作者: 笔墨Android | 来源:发表于2018-04-23 21:21 被阅读0次

    亲爱的同学们我又来了,搬好小板凳准备开车了。。。

    不知道大家平时都用什么听音乐,我个人比较喜欢网易云音乐 (不是做广告,但是我这是干啥呢?),不过现在网易云音乐不能停周董的歌了,实在有些。。。那天突然想起最近研究的MaterialDesign,就想到的网易云音乐的标题栏是怎么实现的。后来我就各种百度,中于功夫不负有心人,总算是被我刨出来了!其实网易云音乐使用的就是标题上面说的SearchView,其实就是一个搜索的View。那么怎么实现的呢?请听下回分解!

    [站外图片上传中...(image-41ace8-1524489658384)]

    开个玩笑,同学们准备好,马上开车了。。。

    本文知识点

    • SearchView的介绍
    • 实现网易云音乐的搜索功能
      • 基本的搜索功能实现
      • 页面的美化问题
      • 一些常见的问题

    先简单说明一下,这里主要是讲解SearchView怎么实现网易云音乐的标题栏,但是都是以来Toolbar的,如果你对Toolbar和menu不是很了解的话!

    请看我公众号的这两篇文章(强势输出一波)

    上面很详细的讲解了关于Toolbar和menu的使用方法和注意事项!!!

    1. SearchView的介绍

    SearchView是和Toolbar联动,通过menu进行设置的搜索的控件(不知道我这么概括你能不能懂)。会在Toolbar的右侧出现一个搜索的按钮(系统自带的,也可以进行替换)。当你点击搜索按钮的时候,会出现相应的编辑框进行搜索。当你点击叉号的时候,本次搜索取消,还原成搜索按钮。

    2. 网易云音乐的搜索功能

    2.1 基本的搜索功能实现

    这里针对menu做了一些修改,所以可能和你出现的基本效果不太一样,但是我会把相应的内容贴出来,这样便于像我一样的懒癌患者,能很快的实现效果。毕竟开发项目紧的时候我是不会管是怎么实现的!!!先看一下基本功能的效果图

    [站外图片上传中...(image-35b1ae-1524489658384)]

    相信你看了之前的那两篇文章的话,很快就能写出下面这个标题栏的。

    • menu文件的代码
    <?xml version="1.0" encoding="utf-8"?>
    <!--仿网易云音乐的menu实现-->
    <menu xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:app="http://schemas.android.com/apk/res-auto">
    
        <item
            android:id="@+id/search"
            android:icon="@drawable/ic_search_black_24dp"
            android:title="搜索"
            app:actionViewClass="android.support.v7.widget.SearchView"
            app:showAsAction="always" />
    
        <item
            android:id="@+id/other"
            android:title="其他内容"
            app:showAsAction="never" />
    </menu>
    
    • 布局文件的代码
    <?xml version="1.0" encoding="utf-8"?>
    <LinearLayout 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:layout_width="match_parent"
        android:layout_height="match_parent"
        android:orientation="vertical"
        tools:context="com.jinlong.newmaterialdesign.toolbar.YunActivity">
    
        <android.support.v7.widget.Toolbar
            android:id="@+id/toolbar"
            android:layout_width="match_parent"
            android:layout_height="?attr/actionBarSize"
            android:background="#ff0000"
            app:popupTheme="@style/ToolbarTheme"
            app:navigationIcon="@mipmap/back_icon">
    
            <TextView
                android:id="@+id/tv_title"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_gravity="center"
                android:text="云Toolbar的实现"
                android:textColor="@android:color/white"
                android:textSize="18sp" />
        </android.support.v7.widget.Toolbar>
    
    </LinearLayout>
    
    • Activity中的代码
    public class YunActivity extends AppCompatActivity {
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_yun);
    
            initToolbar();
        }
    
        private void initToolbar() {
            Toolbar toolbar = findViewById(R.id.toolbar);
            toolbar.setTitle("");
            setSupportActionBar(toolbar);
        }
    
        @Override
        public boolean onCreateOptionsMenu(Menu menu) {
            MenuInflater menuInflater = getMenuInflater();
            menuInflater.inflate(R.menu.menu_yun,menu);
            return super.onCreateOptionsMenu(menu);
        }
    }
    

    上面代码跑一下,紧接着就可以看见上面的内容了!

    2.1.1 搜索按钮的初始化和监听问题

    • 初始化SearchView

      因为在初始化SearcheView,需要对相应的menu进行操作,所以一般都会在onCreateOptionsMenu(Menu menu)中进行获取。具体代码如下:

            //获取SearchView对象
            MenuItem searchItem = menu.findItem(R.id.search);
            mSearchView = (SearchView) searchItem.getActionView();
    

    这里注意一点,就是在初始化SearchView的时候,也可以使用MenuItemCompat.getActionView(searchItem);进行获取的,只不过是过时了。。。所以见到了不要说不知道就行

    • 相应的监听setOnQueryTextListener(OnQueryTextListener listener)
    setOnQueryTextListener(new SearchView.OnQueryTextListener() {
                @Override
                public boolean onQueryTextSubmit(String query) {
                    //在文字改变的时候回调,query是改变之后的文字
                    return false;
                }
    
                @Override
                public boolean onQueryTextChange(String newText) {
                    //文字提交的时候哦回调,newText是最后提交搜索的文字
                    return false;
                }
            });
    

    上面的内容可以实现简单的搜索了?其实我个人觉得这一个监听还不够?为什么这么说呢?因为你想要控制Fragment的切换,没有相应的时间点,或者说是没找到时机进行Fragment的切换问题,当时我想了好久,后来看见源码的时候,我才发现,其实这种时机google工程是早就替我们想好了,其实我觉得我们能想到的,google工程师会替我们实现的!

    • setOnSearchClickListener(OnClickListener listener) 在点击Search那个图标的时候回调的方法。
    • setOnCloseListener(OnCloseListener listener) 在点击搜索后那个叉号的时候回调的方法。

    这样就存在相应的时间点了,你在进来的时候开启一个事物,放进去一个Fragment(这里如果你想加动画效果的话,你可以使用ViewPager,然后通过设置显示那个的方法进行切换.其实事物也是可以设置动画的,看你怎么选择吧)。当你点击关闭的时候。再将之前的Fragment替换掉就可以了。这里为了大家能更好的理解,我还是用代码实现一下吧!先看下效果(虚拟机录得有点渣!)

    展示效果
    • 其实xml中没有什么变化,就不贴了!
    • Activity中的代码是最主要的,代码如下:
    public class YunActivity extends AppCompatActivity {
    
        private static final String TAG = YunActivity.class.getSimpleName();
        private SearchView mSearchView;
        private ViewPager mVpContent;
        private SearchFragment mSearchFragment;
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_yun);
    
            Log.e(TAG, "onCreate: ");
    
            initToolbar();
            initViewPager();
        }
    
    
        private void initToolbar() {
            Toolbar toolbar = findViewById(R.id.toolbar);
            toolbar.setTitle("");
            setSupportActionBar(toolbar);
        }
    
        private void initViewPager() {
            mVpContent = findViewById(R.id.vp_content);
    
            List<Fragment> list = new ArrayList<>();
            DefaultFragment defaultFragment = new DefaultFragment();
            list.add(defaultFragment);
            mSearchFragment = new SearchFragment();
            list.add(mSearchFragment);
    
            MainVPAdapter adapter = new MainVPAdapter(getSupportFragmentManager(), list);
    
            mVpContent.setAdapter(adapter);
        }
    
        @Override
        public boolean onCreateOptionsMenu(Menu menu) {
            Log.e(TAG, "onCreateOptionsMenu: ");
            MenuInflater menuInflater = getMenuInflater();
            menuInflater.inflate(R.menu.menu_yun, menu);
    
            //获取SearchView对象
            MenuItem searchItem = menu.findItem(R.id.search);
            mSearchView = (SearchView) searchItem.getActionView();
    
            //设置相应的监听,文字变化的监听
            mSearchView.setOnQueryTextListener(new SearchView.OnQueryTextListener() {
                @Override
                public boolean onQueryTextSubmit(String query) {
                    //在文字改变的时候回调,query是改变之后的文字
                    mSearchFragment.setSearchStr(query);
                    return false;
                }
    
                @Override
                public boolean onQueryTextChange(String newText) {
                    //文字提交的时候哦回调,newText是最后提交搜索的文字
                    return false;
                }
            });
    
            mSearchView.setOnSearchClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {
                    //开始搜索的时候,设置显示搜索页面
                    mVpContent.setCurrentItem(1);
                }
            });
    
    
            mSearchView.setOnCloseListener(new SearchView.OnCloseListener() {
                @Override
                public boolean onClose() {
                    //关闭搜索按钮的时候,设置显示默认页面
                    mVpContent.setCurrentItem(0);
                    return false;
                }
            });
    
            return super.onCreateOptionsMenu(menu);
        }
    }
    

    这里最主要的就是那几个监听,只要你理解了那几个监听的话基本上就没有问题了。

    • Fragment中的代码:
    public class SearchFragment extends Fragment {
    
    
        private TextView mTvSearch;
    
        public SearchFragment() {
            // Required empty public constructor
        }
    
    
        @Override
        public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
            // Inflate the layout for this fragment
    
            View rootView = inflater.inflate(R.layout.fragment_search, container, false);
    
            mTvSearch = rootView.findViewById(R.id.tv_search);
            return rootView;
        }
        
        /**
         * 搜索的内容
         */
        public void setSearchStr(String query) {
            if (!TextUtils.isEmpty(query))
                mTvSearch.setText("搜索的内容是" + query);
        }
    }
    

    这样就能实现相应的效果了。怎么样?不错吧!!!

    2.2 界面的美化问题

    2.2.1 默认的提示文字

    没有提示文字的样式

    上面的图是没有提示文字时候显示的样子,怎么添加提示文字呢?

    searchView.setQueryHint("相应的提示内容");
    

    通过上面的代码就可以添加搜索的提示文字了。

    2.2.2 搜索按钮不消失

    这个搜索按钮是在输入框的内部,当你设置内容的时候,搜索按钮会消失。这个我感觉我描述的不太正确,管他呢?你们理解就好。。。

    • setIconifiedByDefault(boolean iconified) 这个Api主要是控制搜索按钮是否在输入框内部的,true代表在内部显示,false代表在外部显示

    2.2.3 搜索按钮取消关闭图标的问题

    有的产品经理总会有奇葩的需求,想要去掉那个搜索后面的叉号。说不人性。。。只能默默的改了。。。其实我的内心是崩溃的。。。

    • onActionViewExpanded() 设置关闭图标不显示的Api

    虽然你能关闭这个图标,但是这样就存在一个问题了,之前写好的关闭切换Fragment的操作在这里就会失效了。怎么解决呢?想了半天,只有处理返回事件了,要不我根本就没有办法知道用户真么时候搜索完成啊?那就只有什么时候执行返回操作什么时候算他结束了呗!

            toolbar.setNavigationOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {
                    if (mSearchAutoComplete.isShown()) {
                        try {
                            mSearchAutoComplete.setText("");//清除文本
                            //利用反射调用收起SearchView的onCloseClicked()方法
                            Method method = mSearchView.getClass().getDeclaredMethod("onCloseClicked");
                            method.setAccessible(true);
                            method.invoke(mSearchView);
                        } catch (Exception e) {
                            e.printStackTrace();
                        }
                    } else {
                        finish();
                    }
                }
            });
    

    加上这段代码的话,通过反射拿到SearchView的onDloseClicked(),调用一下就可以了

    2.2.4 搜索栏的默认展开问题

    产品又说了,进到这个页面,默认应该是显示搜索对话框的,用户少操作一步,用户体验好,当时我就说了。那用户就要那样呢?产品说那样的奇葩用户不用管。。。(当时的我啊!满脑袋黑线)

    • setIconified(boolean iconify) 设置搜索输入框是否是展开的,这里注意啊!false代表展开,true代表关闭状态

    2.2.5 修改搜索图标或者去掉图标

    老根产品过不去也不行吧!这里自己看了看搜索图标觉得小了,想更改一下!怎么办呢?

    就是在页面的Activity的主题中,添加相应的searchViewStyle属性,这个属性可以自己设置的。

        <!--SearchView的主题设置-->
        <item name="searchViewStyle">@style/SearchViewStyle</item>
            
        <!--SearchView的主题设置-->
        <style name="SearchViewStyle" parent="Widget.AppCompat.SearchView">
            <!--修改图标的图片-->
            <item name="searchIcon">@mipmap/ic_directions_bike_white_24dp</item>
            <!--去掉图标-->
            <!--<item name="searchHintIcon">@null</item>-->
        </style>        
    

    这里的图片就看你发挥了。。。

    2.2.6 修改文字颜色

    当你觉得输入框的文字或者提示的文字是黑色比较难看的时候,那么你可以像下面这样修改

            //修改searchView的文字颜色
            SearchView.SearchAutoComplete mSearchAutoComplete = mSearchView.findViewById(R.id.search_src_text);
            //设置输入框内提示文字样式
            mSearchAutoComplete.setHintTextColor(getResources().getColor(android.R.color.white));//设置提示文字颜色
            mSearchAutoComplete.setTextColor(getResources().getColor(android.R.color.white));//设置内容文字颜色
    

    不知道还有没有什么其他的了,我感觉有了这些对付你们产品经理就已经足够了,不行桌子上放把刀、要不放个二维码啥的就可以了。。。

    希望我的文章对你有帮助!希望我们共同进步。。。see you!

    相关文章

      网友评论

          本文标题:Android中SearchView的使用

          本文链接:https://www.haomeiwen.com/subject/jythlftx.html