Android高级进阶(十四)之Toolbar + SearchView

       今天公司暖气来了,意味着又到了年末。我们日夜重复着昨天的生活像白开水一样的活着,忙碌着却无成绩的挣扎着。没关系,有些人还是很快乐因为它们从中得到了充实,自乐其中。可是我们不要忘了这个世界上只有活的有意义才是最大的幸福。通过博客来记录生活与技术,只有把一些东西写下来,才能让我看得更明白,才能不断发现迷失的自己。今天我们就来讲一下Android开发中的寻找(SearchView)。首先,我们看一下今天要实现的SearchView的展示效果:

     上一节我们已经讲了SearchView是显示在ToolBar上的一个搜、索控件,这节我们就详细讲解下它的用法,为了故事的完整性我们还是从ToolBar开始。

一、ToolBar的展示与菜单(包括SearchView)

1. activity_main.xml(后面MainActivity的布局)

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:orientation="vertical">

    <android.support.v7.widget.Toolbar
        android:id="@+id/toolbar"
        style="@style/Toolbar.MyStyle"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:background="?attr/colorPrimary"
        app:title="我的Tool"
        app:titleTextColor="@color/colorWhite"
        app:navigationIcon="@mipmap/gongzhong_fanhui"
        app:titleTextAppearance="@style/Toolbar.TitleText"
       >
    </android.support.v7.widget.Toolbar>

</LinearLayout>

activity_main.xml里声明了一个ToolBar,android:background背景色为主题颜色,app:title标题为“我的Tool”,app:titleTextColor标题颜色为白色,app:navigationIcon返回箭头,app:titleTextAppearance="@style/Toolbar.TitleText"标题的字体样式在values-styles样式文件里定义如下(字体大小为15sp):

<!--Toolbar标题文字大小-->
    <style name="Toolbar.TitleText"     parent="TextAppearance.Widget.AppCompat.Toolbar.Title">
        <item name="android:textSize">15sp</item>
    </style>

 style="@style/Toolbar.MyStyle"整个ToolBar的样式在values-styles样式文件里定义如下:

  <style name="Toolbar.MyStyle" parent="Base.Widget.AppCompat.Toolbar">
        <item name="contentInsetStart">0dp</item>
        <item name="contentInsetStartWithNavigation">0dp</item>
    </style>

其中      <item name="contentInsetStart">0dp</item> 与<item name="contentInsetStartWithNavigation">0dp</item>的作用是让标题“我的ToolBar”离 返回箭头更贴近一些,因为默认标题与返回箭头间的空隙太大。截至目前整个styles.xml文件内容如下:

<resources>

    <!-- Base application theme. -->
    <style name="AppTheme" parent="Theme.AppCompat.Light.NoActionBar">
        <!-- Customize your theme here. -->
        <item name="colorPrimary">@color/colorPrimary</item>
        <item name="colorPrimaryDark">@color/colorPrimaryDark</item>
        <item name="colorAccent">@color/colorAccent</item>
    </style>

    <!--标题与NavigationIcon的距离-->
    <style name="Toolbar.MyStyle" parent="Base.Widget.AppCompat.Toolbar">
        <item name="contentInsetStart">0dp</item>
        <item name="contentInsetStartWithNavigation">0dp</item>
    </style>

    <!--Toolbar标题文字大小-->
    <style name="Toolbar.TitleText" parent="TextAppearance.Widget.AppCompat.Toolbar.Title">
        <item name="android:textSize">15sp</item>
    </style>
</resources>

2. 菜单定义menu---main.xml

<menu xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    tools:context="com.ricky.materialdesign.toolbar.MainActivity"
    xmlns:app="http://schemas.android.com/apk/res-auto">

    <item
        android:id="@+id/action_search"
        android:orderInCategory="100"
        app:actionViewClass="android.support.v7.widget.SearchView"
        app:showAsAction="always"
        android:title="查找"/>
    <item
        android:id="@+id/action_settings"
        android:orderInCategory="100"
        app:showAsAction="never"
        android:title="设置"/>
    <item
        android:id="@+id/action_share"
        android:orderInCategory="100"
        app:showAsAction="always"
        android:title="分享"
        android:icon="@android:drawable/ic_menu_share"/>
    <item
        android:id="@+id/action_edit"
        android:orderInCategory="100"
        app:showAsAction="ifRoom"
        android:title="编辑"
        android:icon="@android:drawable/ic_menu_edit"/>

</menu>

main.xml里定义了4个菜单项,第一个菜单项就是我们定义的SearchView,  app:showAsAction="always"表示这个搜索控件总会显示在ToolBar表面,第二个菜单项是设置菜单 app:showAsAction="never"意味着它将隐藏在右上角三个...的菜单里。第三个是分享菜单项,它与SearchView一样也会显示在ToolBar表面。第四个菜单项—编辑菜单,app:showAsAction="ifRoom"属性表示如果ToolBar表面还有空间的话那么它也将显示在ToolBar表面。

3. MainActivity.java

加载activity_main.xml与menu--main.xml来显示ToolBar和它附带的菜单项。

package com.example.administrator.toolbarstudy;

import android.graphics.Color;
import android.os.Bundle;
import android.support.v4.view.MenuItemCompat;
import android.support.v7.app.AppCompatActivity;
import android.support.v7.widget.SearchView;
import android.support.v7.widget.SearchView.OnCloseListener;
import android.support.v7.widget.SearchView.OnQueryTextListener;
import android.support.v7.widget.Toolbar;
import android.text.TextUtils;
import android.util.Log;
import android.view.KeyEvent;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.View.OnFocusChangeListener;
import android.view.ViewGroup;
import android.widget.Adapter;
import android.widget.EditText;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.ListAdapter;
import android.widget.ListView;
import android.widget.TextView;
import android.widget.Toast;

import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.List;

public class MainActivity extends AppCompatActivity {
    SearchView.SearchAutoComplete mSearchAutoComplete;
    SearchView mSearchView;
    MyAdapter adapter;
    String TAG = "MainActivity";
    ListView lvAutoText;
    List<String> namesCollection = new ArrayList<>();
    List<String> names = new ArrayList<>();

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
        setSupportActionBar(toolbar);
        getSupportActionBar().setDisplayShowTitleEnabled(true);

        //返回键
        toolbar.setNavigationOnClickListener(new OnClickListener() {
            @Override
            public void onClick(View v) {
                clickBack();
            }
        });
    }

    /**
     * 点击返回(包括手机物理按键)
     */
    public void clickBack()
    {
        if (mSearchAutoComplete.isShown()) {
            try {
                //折叠搜索框
                mSearchAutoComplete.setText("");
                Method method = mSearchView.getClass().getDeclaredMethod("onCloseClicked");
                method.setAccessible(true);
                method.invoke(mSearchView);
            } catch (Exception e) {
                e.printStackTrace();
            }
        } else {
            finish();
        }
        return;
    }

    /**
     * 让菜单同时显示图标和文字
     * @param featureId
     * @param menu
     * @return
     */
    @Override
    public boolean onMenuOpened(int featureId, Menu menu) {
        if (menu != null) {
            if (menu.getClass().getSimpleName().equalsIgnoreCase("MenuBuilder")) {
                try {
                    Method method = menu.getClass().getDeclaredMethod("setOptionalIconsVisible", Boolean.TYPE);
                    method.setAccessible(true);
                    method.invoke(menu, true);
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        }
        return super.onMenuOpened(featureId, menu);
    }

    /**
     * 根据menu--main.xml加载菜单
     * @param menu
     * @return
     */
    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        getMenuInflater().inflate(R.menu.main, menu);
        MenuItem item = menu.findItem(R.id.action_search);
        mSearchView = (SearchView) MenuItemCompat.getActionView(item);
        //通过id得到搜索框控件
         mSearchAutoComplete = (SearchView.SearchAutoComplete) mSearchView.findViewById(R.id.search_src_text);
         return true;
    }

  
    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
 
        int id = item.getItemId();
        if (id == R.id.action_settings) {
            Toast.makeText(MainActivity.this,"您点击了设置",Toast.LENGTH_SHORT).show();
            return true;
        }
        else if(id == R.id.action_share)
        {
            Toast.makeText(MainActivity.this,"您点击了分享",Toast.LENGTH_SHORT).show();
            return true;
        }
        return super.onOptionsItemSelected(item);
    }


    /**
     * 按系统返回键与按标题栏上的返回产生相同的效果
     * @param keyCode
     * @param event
     * @return
     */
    @Override
    public boolean onKeyDown(int keyCode, KeyEvent event) {
        if(keyCode  == KeyEvent.KEYCODE_BACK)
        {
            clickBack();
            return true;
        }
        return super.onKeyDown(keyCode, event);
    }
}

代码分析

3.1  折叠搜索控件(SearchView)

在上述代码里我们定义了返回键的响应处理

//返回键
        toolbar.setNavigationOnClickListener(new OnClickListener() {
            @Override
            public void onClick(View v) {
                clickBack();
            }
        });

clickBack函数实现了一个功能,就是当搜索框展开显示的时候,折叠SearchView(搜索框),如果SearchView本来就是折叠的则点返回键直接关闭当前页面。同时,我们在Activity的onKeyDown里也调用的clickBack函数。其中mSearchAutoComplete.就是搜索文本框,它是一个自动完成文本框,mSearchView就是SearchView控件实例,它们都在onCreateOptionsMenu函数里创建。

3.2 加载SearchView

onCreateOptionsMenu函数从menu--main.xml里加载出各菜单,并从中得到了mSearchView 与mSearchASutoComplete,这两个控件实例分别是SearchView控件与 SearchView控件中的搜索文本框,这两个变量在3.1中的clickBack函数中有使用。

3.3 菜单项的点击事件

 onOptionsItemSelected函数里处理了菜单的点击事件。

3.4  onMenuOpened

让菜单项同时显示图标与文本,例如下图中的“编辑”菜单项:

4. 界面效果

4.1 截止目前,运行效果如下:

点击搜索图标展开SearchView控件,输入文本后点右边的叉号删除文本,当SearchView展开的时候点返回箭头则折叠SearchView搜索文本框,当SearchView已经折叠的时候,然后继续按返回键则关闭当前页面(这种情况以下动画中没有演示)。

4.2 改进UI

我们从上述运行效果图中可以看出:

“搜索图标”、“搜索文字”、“X号”、“三个点点”的颜色都是黑色,能不能让它们变成白色。答案是可以的!为AppTheme添加一个配置android:textColorSecondary将其设置为白色可以改变菜单项图标的颜色。

<!-- Base application theme. -->
<style name="AppTheme" parent="Theme.AppCompat.Light.NoActionBar">
    <!-- Customize your theme here. -->
    <item name="colorPrimary">@color/colorPrimary</item>
    <item name="colorPrimaryDark">@color/colorPrimaryDark</item>
    <item name="colorAccent">@color/colorAccent</item>
    <!--设置menu中item的图标颜色-->
    <item name="android:textColorSecondary">@color/colorWhite</item>-->
</style>

同时在MainActivity.java代码中onCreateOptionsMenu函数里添加代码:

int colorWhite = this.getResources().getColor(R.color.colorWhite);
mSearchAutoComplete.setTextColor(colorWhite);

其中mSearchAutoComplete就是那个搜索文本框。

这样再运行效果如下:

这下界面颜色一致了都是白色的了,漂亮多了。这只是个UI,接下来我们研究一下与SearchView相关的事件处理函数以及结合ListView实现  “搜索自动提示” 功能。

二、SearchView相关代码

1. SearchView相关代码:

  /**
     * 根据menu--main.xml加载菜单
     * @param menu
     * @return
     */
    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        getMenuInflater().inflate(R.menu.main, menu);

        MenuItem item = menu.findItem(R.id.action_search);
        mSearchView = (SearchView) MenuItemCompat.getActionView(item);
        //设置最大宽度mSearchView.setMaxWidth

        //通过id得到搜索文本框控件
         mSearchAutoComplete = (SearchView.SearchAutoComplete) mSearchView.findViewById(R.id.search_src_text);
         int color = this.getResources().getColor(R.color.colorWhite);
         mSearchAutoComplete.setTextColor(color);
        /*------------------ SearchView有三种默认展开搜索框的设置方式,区别如下: ------------------*/

        //1.设置搜索框直接展开显示。左侧有放大镜(在搜索框外) 右侧无叉叉 有输入内容后有叉叉 不能关闭搜索框
        //searchView.setIconifiedByDefault(false);

        //2.设置搜索框直接展开显示。左侧有放大镜(在搜索框中) 右侧无叉叉 有输入内容后有叉叉 不能关闭搜索框
        mSearchView.onActionViewExpanded();

        //3.false设置搜索框直接展开显示,true缩减为一个搜索图标。左侧有放大镜(在搜索框中) 右侧有叉叉 可以关闭搜索框
        mSearchView.setIconified(true);

        //SearchView用到了一个布局,在V7compat里面找到abc_search_view.xml,在里面可以找到SearchView各组成部分的资源ID

        //设置"提交搜索"按钮的图标,就是那个">"右箭头提交按钮
        //ImageView icon = (ImageView) mSearchView.findViewById(R.id.search_go_btn);
        //icon.setImageResource(R.mipmap.voice_search);

        //设置搜索框文本的hint,与mSearchAutoComplete.setHint功能一样
        mSearchView.setQueryHint("搜索本地歌曲by code");

        //设置搜索文本框的字体
        mSearchAutoComplete.setHintTextColor(getResources().getColor(android.R.color.darker_gray));
        mSearchAutoComplete.setTextColor(getResources().getColor(android.R.color.background_light));
        mSearchAutoComplete.setTextSize(14);

        //修改搜索框控件间的间隔(这样只是为了在细节上更加接近网易云音乐的搜索框)
        LinearLayout search_edit_frame = (LinearLayout) mSearchView.findViewById(R.id.search_edit_frame);
        ViewGroup.MarginLayoutParams params = (ViewGroup.MarginLayoutParams) search_edit_frame.getLayoutParams();
        params.leftMargin = 0;
        params.rightMargin = 0;
        search_edit_frame.setLayoutParams(params);


        //设置提交按钮是否可用(可见)
        mSearchView.setSubmitButtonEnabled(true);

         //searchView.setSuggestionsAdapter(adapter)
        //监听mSearchAutoComplete文本框焦点改变,例如点返回键后SearchView折叠mSearchAutoComplete失去了焦点时执行
        mSearchView.setOnQueryTextFocusChangeListener(new OnFocusChangeListener() {

            @Override
            public void onFocusChange(View v, boolean hasFocus) {
               Log.i(TAG,"onFocusChange");

            }
        });
        //searchView折叠监听,当前项目中点击返回键时执行
        mSearchView.setOnCloseListener(new OnCloseListener() {

            @Override
            public boolean onClose() {
                Log.i(TAG,"OnCloseListener");
                return false;
            }
        });

        ////搜索图标按钮(打开搜索框的按钮)的点击事件
        mSearchView.setOnSearchClickListener(new OnClickListener() {

            @Override
            public void onClick(View v) {
                Toast.makeText(MainActivity.this, "点击了搜索图标按钮", Toast.LENGTH_SHORT).show();
            }
        });
        //监听文本变化,调用查询
        mSearchView.setOnQueryTextListener(new OnQueryTextListener() {

            //X右边的"搜索提交"按钮
            @Override
            public boolean onQueryTextSubmit(String text) {
                Toast.makeText(MainActivity.this, "点击了提交按钮:"+text, Toast.LENGTH_SHORT).show();
                return false;
            }

            @Override
            public boolean onQueryTextChange(String text) {
                // 文本改变的时候回调
                Log.i(TAG,"文本变化~~~~~"+text);
                return false;
            }
        });

        return true;
    }

注释还是比较全的。在 这里我们主要看一下setOnQueryTextListener,它包含2个回调函数onQueryTextSubmit与onQueryTextChange,其中onQueryTextChange检测文本变化,例如当你输入字母a时就会调用这个函数,这个正好可以用来实现那种边输入边搜索的效果。

2.  SearchView结合Listviews实现自动提示

   我们可以结合Listview来实现边搜索边提示的功能。例如输入a,则请求服务器,服务器会返回abc, aaa,acd ...等包含a的搜索提示列表。在这里我们不请求服务器,为了演示方便我们把“搜索提示文本的集合”放在本地,如一个字符串数组:

  List<String> namesCollection = new ArrayList<>();
  namesCollection.add("abcd");
        namesCollection.add("adc");
        namesCollection.add("bbc");
        namesCollection.add("bac");
        namesCollection.add("cab");
        namesCollection.add("ccb")

到时候我们在搜索文本框里输入a,ListView将显示abcd, adc, bac,cab. 输入d将显示adc.  那我们在何处去从集合里筛选呢,答案是从onQueryTextChange里监听输入文本的变化,每输入一个字符会去从集合中筛选出与输入匹配的字符串,最终显示在Listview里。好了原理分析完了,我们看具体如何实现:

2.1 布局

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:orientation="vertical">

    <android.support.v7.widget.Toolbar
        android:id="@+id/toolbar"
        style="@style/Toolbar.MyStyle"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:background="?attr/colorPrimary"
        app:title="我的Tool"
        app:titleTextColor="@color/colorWhite"
        app:navigationIcon="@mipmap/gongzhong_fanhui"
        app:titleTextAppearance="@style/Toolbar.TitleText"
       >
    </android.support.v7.widget.Toolbar>

    <ListView
        android:layout_gravity="center_horizontal"
        android:divider="@color/colorPrimary"
        android:dividerHeight="0.3dp"
        android:id="@+id/lvAutoText"
        android:layout_width="300dp"
        android:layout_height="wrap_content">
    </ListView>
</LinearLayout>

2.2 MainActivity.java代码

package com.example.administrator.toolbarstudy;

import android.graphics.Color;
import android.os.Bundle;
import android.support.v4.view.MenuItemCompat;
import android.support.v7.app.AppCompatActivity;
import android.support.v7.widget.SearchView;
import android.support.v7.widget.SearchView.OnCloseListener;
import android.support.v7.widget.SearchView.OnQueryTextListener;
import android.support.v7.widget.Toolbar;
import android.text.TextUtils;
import android.util.Log;
import android.view.KeyEvent;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.View.OnFocusChangeListener;
import android.view.ViewGroup;
import android.widget.Adapter;
import android.widget.EditText;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.ListAdapter;
import android.widget.ListView;
import android.widget.TextView;
import android.widget.Toast;

import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.List;

public class MainActivity extends AppCompatActivity {
    SearchView.SearchAutoComplete mSearchAutoComplete;
    SearchView mSearchView;
    MyAdapter adapter;
    String TAG = "MainActivity";
    ListView lvAutoText;
    List<String> namesCollection = new ArrayList<>();
    List<String> filterNames = new ArrayList<>();

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
        setSupportActionBar(toolbar);
        getSupportActionBar().setDisplayShowTitleEnabled(true);

        //返回键
        toolbar.setNavigationOnClickListener(new OnClickListener() {
            @Override
            public void onClick(View v) {
                clickBack();
            }
        });
        lvAutoText = this.findViewById(R.id.lvAutoText);
        namesCollection.add("abcd");
        namesCollection.add("adc");
        namesCollection.add("bbc");
        namesCollection.add("bac");
        namesCollection.add("cab");
        namesCollection.add("ccb");
        filterNames.addAll(namesCollection);
        adapter = new MyAdapter(filterNames,this);
        lvAutoText.setAdapter(adapter);

    }

    /**
     * 点击返回(包括手机物理按键)
     */
    public void clickBack()
    {
        if (mSearchAutoComplete.isShown()) {
            try {
                //如果搜索框中有文字,则会先清空文字,但网易云音乐是在点击返回键时直接关闭搜索框
                mSearchAutoComplete.setText("");
                Method method = mSearchView.getClass().getDeclaredMethod("onCloseClicked");
                method.setAccessible(true);
                method.invoke(mSearchView);
            } catch (Exception e) {
                e.printStackTrace();
            }
        } else {
            finish();
        }
        return;
    }

    /**
     * 让菜单同时显示图标和文字
     * @param featureId
     * @param menu
     * @return
     */
    @Override
    public boolean onMenuOpened(int featureId, Menu menu) {
        if (menu != null) {
            if (menu.getClass().getSimpleName().equalsIgnoreCase("MenuBuilder")) {
                try {
                    Method method = menu.getClass().getDeclaredMethod("setOptionalIconsVisible", Boolean.TYPE);
                    method.setAccessible(true);
                    method.invoke(menu, true);
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        }
        return super.onMenuOpened(featureId, menu);
    }

    /**
     * 根据menu--main.xml加载菜单
     * @param menu
     * @return
     */
    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        getMenuInflater().inflate(R.menu.main, menu);

        MenuItem item = menu.findItem(R.id.action_search);
        mSearchView = (SearchView) MenuItemCompat.getActionView(item);
        //设置最大宽度mSearchView.setMaxWidth

        //通过id得到搜索框控件
         mSearchAutoComplete = (SearchView.SearchAutoComplete) mSearchView.findViewById(R.id.search_src_text);
         int color = this.getResources().getColor(R.color.colorWhite);
         mSearchAutoComplete.setTextColor(color);
        /*------------------ SearchView有三种默认展开搜索框的设置方式,区别如下: ------------------*/

        //1.设置搜索框直接展开显示。左侧有放大镜(在搜索框外) 右侧无叉叉 有输入内容后有叉叉 不能关闭搜索框
        //searchView.setIconifiedByDefault(false);

        //2.设置搜索框直接展开显示。左侧有放大镜(在搜索框中) 右侧无叉叉 有输入内容后有叉叉 不能关闭搜索框
        mSearchView.onActionViewExpanded();

        //3.false设置搜索框直接展开显示,true缩减为一个搜索图标。左侧有放大镜(在搜索框中) 右侧有叉叉 可以关闭搜索框
        mSearchView.setIconified(true);

        //SearchView用到了一个布局compat里面找到abc_search_view.xml,该里面的控件的属性

        //设置提交搜索按钮的图标
        //ImageView icon = (ImageView) mSearchView.findViewById(R.id.search_go_btn);
        //icon.setImageResource(R.mipmap.voice_search);

        //设置搜索文本的hint,与mSearchAutoComplete.setHint功能一样
        mSearchView.setQueryHint("搜索本地歌曲by code");

        //设置搜索文本框的字体
        mSearchAutoComplete.setHintTextColor(getResources().getColor(android.R.color.darker_gray));
        mSearchAutoComplete.setTextColor(getResources().getColor(android.R.color.background_light));
        mSearchAutoComplete.setTextSize(14);

        //修改搜索框控件间的间隔(这样只是为了在细节上更加接近网易云音乐的搜索框)
        LinearLayout search_edit_frame = (LinearLayout) mSearchView.findViewById(R.id.search_edit_frame);
        ViewGroup.MarginLayoutParams params = (ViewGroup.MarginLayoutParams) search_edit_frame.getLayoutParams();
        params.leftMargin = 0;
        params.rightMargin = 0;
        search_edit_frame.setLayoutParams(params);


        //设置提交按钮是否可用(可见)
        mSearchView.setSubmitButtonEnabled(true);

         //searchView.setSuggestionsAdapter(adapter)
        //监听mSearchAutoComplete文本框焦点改变,例如点返回键后SearchView折叠mSearchAutoComplete失去了焦点时执行
        mSearchView.setOnQueryTextFocusChangeListener(new OnFocusChangeListener() {

            @Override
            public void onFocusChange(View v, boolean hasFocus) {
               Log.i(TAG,"onFocusChange");

            }
        });
        //searchView折叠监听,当前项目中点击返回键时执行
        mSearchView.setOnCloseListener(new OnCloseListener() {

            @Override
            public boolean onClose() {
                Log.i(TAG,"OnCloseListener");
                return false;
            }
        });

        ////搜索图标按钮(打开搜索框的按钮)的点击事件
        mSearchView.setOnSearchClickListener(new OnClickListener() {

            @Override
            public void onClick(View v) {
                Toast.makeText(MainActivity.this, "点击了搜索图标按钮", Toast.LENGTH_SHORT).show();
            }
        });
        //监听文本变化,调用查询
        mSearchView.setOnQueryTextListener(new OnQueryTextListener() {

            //X右边的"搜索提交"按钮
            @Override
            public boolean onQueryTextSubmit(String text) {
                Toast.makeText(MainActivity.this, "点击了提交按钮:"+text, Toast.LENGTH_SHORT).show();
                return false;
            }

            @Override
            public boolean onQueryTextChange(String text) {
                // 文本改变的时候回调
                Log.i(TAG,"文本变化~~~~~"+text);
                List<String> queryResult = QueryNames(namesCollection,text);
                filterNames.clear();
                if(queryResult != null && queryResult.size() > 0)
                {
                    filterNames.addAll(queryResult);
                }

                setAdapter(adapter);
                return false;
            }
        });

        return true;
    }

    /**
     * 从namesCollection集合中筛选与输入的文本想匹配的字符串
     * @param namesCollection  提示文本(关键字)的集合,一般存在服务器数据库
     * @param text    搜索框里输入的文本
     * @return
     */
    private List<String> QueryNames(List<String> namesCollection,String text) {

        if(TextUtils.isEmpty(text))
        {
            return null;
        }
        List<String> temp = new ArrayList<>();
        for(String name: namesCollection)
        {
            if(name.contains(text))
            {
                temp.add(name);
            }
        }

        return temp;
    }

    /**
     * 为ListView配置数据
     * @param adapter
     */
    public void setAdapter(ListAdapter adapter)
    {
        if(adapter == null)
        {
            adapter = new MyAdapter(filterNames,MainActivity.this);
            lvAutoText.setAdapter(adapter);
        }
        else
        {
            if(adapter instanceof  MyAdapter)
            {
                ((MyAdapter)adapter).notifyDataSetChanged();
            }
        }
        return;
    }

    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        // Handle action bar item clicks here. The action bar will
        // automatically handle clicks on the Home/Up button, so long
        // as you specify a parent activity in AndroidManifest.xml.
        int id = item.getItemId();
        if (id == R.id.action_settings) {
            Toast.makeText(MainActivity.this,"您点击了设置",Toast.LENGTH_SHORT).show();
            return true;
        }
        else if(id == R.id.action_share)
        {
            Toast.makeText(MainActivity.this,"您点击了分享",Toast.LENGTH_SHORT).show();
            return true;
        }
        return super.onOptionsItemSelected(item);
    }


    /**
     * 按系统返回键与按标题栏上的返回产生相同的效果
     * @param keyCode
     * @param event
     * @return
     */
    @Override
    public boolean onKeyDown(int keyCode, KeyEvent event) {
        if(keyCode  == KeyEvent.KEYCODE_BACK)
        {
            clickBack();
            return true;
        }
        return super.onKeyDown(keyCode, event);
    }
}

我们主要看以下代码片段:

   public boolean onQueryTextChange(String text) {
                // 文本改变的时候回调
                Log.i(TAG,"文本变化~~~~~"+text);
                List<String> queryResult = QueryNames(namesCollection,text);
                filterNames.clear();
                if(queryResult != null && queryResult.size() > 0)
                {
                    filterNames.addAll(queryResult);
                }

                setAdapter(adapter);
                return false;
            }
 /**
     * 从namesCollection集合中筛选与输入的文本想匹配的字符串
     * @param namesCollection  提示文本(关键字)的集合,一般存在服务器数据库
     * @param text    搜索框里输入的文本
     * @return
     */
    private List<String> QueryNames(List<String> namesCollection,String text) {

        if(TextUtils.isEmpty(text))
        {
            return null;
        }
        List<String> temp = new ArrayList<>();
        for(String name: namesCollection)
        {
            if(name.contains(text))
            {
                temp.add(name);
            }
        }

        return temp;
    }

  onQueryTextChange监听搜索文本框里的text变化,同时调用QueryNames函数从 集合中筛选出与text匹配的子集合,然后调用setAdapter展示子集合到ListView里。这样就模拟实现了自动提示文本,即一边输入一边提示“搜索关键字”的功能。就这么Easy!最终效果如图所示:

最后按照惯例给出源码下载地址:https://download.csdn.net/download/gaoxiaoweiandy/10789571

发布了44 篇原创文章 · 获赞 27 · 访问量 2万+

猜你喜欢

转载自blog.csdn.net/gaoxiaoweiandy/article/details/83999117