Android中SearchView的使用

8,239 阅读8分钟

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

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

开玩笑啊!!!

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

本文知识点

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

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

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

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

1. SearchView的介绍

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

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

2.1 基本的搜索功能实现

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

原谅我的配色

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

  • 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