Material Design 系列之 SearchView +

2020-12-03  本文已影响0人  Time_x

前言

SearchView 是 Android 原生的搜索框控件,它提供了一个用户界面,可以让用户在文本框内输入文字,并允许通过看监听器监控用户输入,当用户输入完成后提交搜索时,也可通过监听器执行实际的搜索。

一、常见属性

相关方法 解释说明
setIconifiedByDefault(boolean) 设置该搜索框默认是否自动缩小为图标
setImeOptions(int) 设置输入法搜索选项字段,默认是搜索,可以是:下一页、发送、完成等
setInputType(int) 设置输入类型
setMaxWidth(int) 设置最大宽度
setQueryHint(CharSequence) 设置查询提示字符串
setThreshold(int threshold) 设置触发查询的最少字符数(默认 2 个字符才会触发查询)
setIconified(boolean iconify) 置搜索框直接展开显示。左侧有放大镜(在搜索框中) 右侧有叉叉,可以关闭搜索框
setIconifiedByDefault(boolean iconified) 设置搜索框直接展开显示。左侧有放大镜(在搜索框外) 右侧无叉叉 有输入内容后有叉叉,不能关闭搜索框
mSearchView.onActionViewExpanded() 设置搜索框直接展开显示。左侧有无放大镜(在搜索框中) 右侧无叉叉 有输入内容后有叉叉,不能关闭搜索框
setSubmitButtonEnabled(boolean enabled) 设置提交按钮是否可见

使用 SearchView 时可使用如下常用方法。

如果为 SearchView 增加一个配套的 ListView,则可以为 SearchView 增加自动完成功能。下面实例示范如何使用 SearchView。

二、基础使用

SearchView 常规使用结合 ToolBar,完成 APP 首页 Tab 栏的搜索功能,ToolBar 加载 Menu 形式来呈现 SearchView 效果。本文重点讲解 SearchView 使用,如果对 ToolBar 相关知识点属性不熟悉的,请参考阅读:

Android Material Design 系列之 Toolbar 使用详解

1、menu 新建 search.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"
        xmlns:tools="http://schemas.android.com/tools"
        tools:context=".toolbar.SearchViewActivity">
      <item
    android:id="@+id/search"
    android:title="搜索"
    app:actionViewClass="android.widget.SearchView"
    app:showAsAction="always" />
    <item
    android:id="@+id/setting"
    android:title="设置"
    app:showAsAction="never" />
    </menu> 

相信学习过 ToolBar 的对上面 menu 文件配置很熟悉,这里需要重点注意app:actionViewClass="android.widget.SearchView"属性,这个属性是用来加载一个 View,传入 SearchView 的完整包名。

2、SearchView 加载 Toolbar

既然可以将 SearchView 加载到 Toolbar 中,那么自然可以获取到 SearchView 控件实例,然后就可以设置 SearchView 相关属性。重写 Activity 中 onCreateOptionsMenu(Menu menu) 方法完成 menu 加载,可以根据MenuItemCompat.getActionView方法获取 SearchView 实例。

     @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        getMenuInflater().inflate(R.menu.searchview_menu, menu);
      // 获取搜索Menu
        MenuItem item = menu.findItem(R.id.search);
      // 通过MenuItemCompat.getActionView()方法获取SearchView
        SearchView mSearchView = (SearchView) MenuItemCompat.getActionView(item);
    } 

注意:记得在 onCreate()方法里设置setSupportActionBar(toolbar);

3、SearchView 显示模式

  //设置搜索框直接展开显示。左侧有放大镜(在搜索框中) 右侧有叉叉 可以关闭搜索框
    mSearchView.setIconified(false);
    //设置搜索框直接展开显示。左侧有放大镜(在搜索框外) 右侧无叉叉 有输入内容后有叉叉 不能关闭搜索框
    mSearchView.setIconifiedByDefault(false);
  //设置搜索框直接展开显示。左侧有无放大镜(在搜索框中) 右侧无叉叉 有输入内容后有叉叉 不能关闭搜索框
    mSearchView.onActionViewExpanded();` </pre>

4、SearchView 修改样式

1.设置搜索框提交按钮

搜索状态时,最右侧有一个提交按钮,默认是一个箭头图标,使用mSearchView.setSubmitButtonEnabled(true)方法设置。

image

2.更改提交按钮图标

SearchView 内置图标难免会不满足项目需求,查看 SearchView 源码发现,他加载了一个abc_search_view布局,于是打开 xml 文件发现提交按钮的 id。

    final LayoutInflater inflater = LayoutInflater.from(context);
    final int layoutResId = a.getResourceId(R.styleable.SearchView_layout, R.layout.abc_search_view);
    inflater.inflate(layoutResId, this, true);` </pre>

这下大家应该清楚接下来我要做什么骚操作了吧,没错就是 findViewById 获取到提交 View,手动setImageResource()给他设置图片。

    ImageView mSearchGoBtn = mSearchView.findViewById(R.id.search_go_btn);
    mSearchGoBtn.setImageResource(R.drawable.ic_baseline_emoji_emotions_24); 
image

3.设置搜索框属性

我们既然已经掌握如何更改提交按钮图标,那搜索框属性自然也可以使用同样的手段实现,先看下abc_search_view布局中搜索框是如何定义的。

  <view class="androidx.appcompat.widget.SearchView$SearchAutoComplete"
  android:id="@+id/search_src_text"
  android:layout_height="36dip"
  android:layout_width="0dp"
  android:layout_weight="1"
  android:layout_gravity="center_vertical"
  android:paddingLeft="@dimen/abc_dropdownitem_text_padding_left"
  android:paddingRight="@dimen/abc_dropdownitem_text_padding_right"
  android:singleLine="true"
  android:ellipsize="end"
  android:background="@null"
  android:inputType="text|textAutoComplete|textNoSuggestions"
  android:imeOptions="actionSearch"
  android:dropDownHeight="wrap_content"
  android:dropDownAnchor="@id/search_edit_frame"
  android:dropDownVerticalOffset="0dip"
  android:dropDownHorizontalOffset="0dip" /> 

我们发现居然不是直接继承 EditText,而是一个 SearchView 的内部类 SearchAutoComplete,跟踪到源码中发现,它继承自AppCompatAutoCompleteTextViewAppCompatAutoCompleteTextView又继承AutoCompleteTextView,这个类我们应该很熟悉了,那就可以猜想 SearchView 应该也能实现输入内容检索提示的功能。

    public static class SearchAutoComplete extends AppCompatAutoCompleteTextView {}
    public class AppCompatAutoCompleteTextView extends AutoCompleteTextView implements TintableBackgroundView {}
    public class AutoCompleteTextView extends EditText implements Filter.FilterListener {} 

同理 findViewById 获取 SearchAutoComplete,设置相关默认属性:

    SearchView.SearchAutoComplete mSearchEditView = mSearchView.findViewById(R.id.search_src_text);
     mSearchEditView.setHint("请输入搜索内容");  
    mSearchEditView.setHintTextColor(getResources().getColor(R.color.selectable_item_background_general_light_accent))      ;
    mSearchEditView.setTextSize(TypedValue.COMPLEX_UNIT_DIP,15); 

如果只想设置默认提示的话,使用mSearchView.setQueryHint("请输入搜索内容")方法也可以实现,根据自己需求选择合适的方法。

image

4.SearchView 监听事件

image

三、实战案例

以上已经介绍了 SearchView 的基本使用,日常开发过程中,往往需求跟系统自带的 View 有所差距(不知道是产品经理问题还是 UI 设计师问题,总之就是很烦)。下面根据自己项目中的经历,讲解下综合实战的方法。

1、Toolbar 返回键监听搜索框

场景:当 SearchView 打开时,点击 Toolbar 返回键,先关闭掉搜索框。

SearchView 并没有公开关闭搜索框方法,但是 SearchView 源码中,有一个onCloseClicked()方法,这个方法里面就是处理了"X"按钮的逻辑,如果搜索框有文本输入,则清除文本内容,否则直接关闭搜索框。

 void onCloseClicked() {
CharSequence text = mSearchSrcTextView.getText();
if (TextUtils.isEmpty(text)) {
    if (mIconifiedByDefault) {
        // If the app doesn't override the close behavior
        if (mOnCloseListener == null || !mOnCloseListener.onClose()) {
            // hide the keyboard and remove focus
            clearFocus();
            // collapse the search field
            updateViewsVisibility(true);
        }
    }
} else {
    mSearchSrcTextView.setText("");
    mSearchSrcTextView.requestFocus();
    mSearchSrcTextView.setImeVisibility(true);
}
  } 

所以我们利用反射(反射相关知识属于 Java 基础,如果还不会使用的小伙伴,自己补习一下),就可以实现应用场景的效果:

toolbar.setNavigationOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
    try {
        if (mSearchEditView.isShown()) {
            Method method = mSearchView.getClass().getDeclaredMethod("onCloseClicked");
            method.setAccessible(true);
            method.invoke(mSearchView);
        } else {
            finish();
        }
    } catch (Exception e) {
        e.printStackTrace();
    }
}
});  

2、去掉搜索框默认下划线

看到网上很多朋友说需要利用反射去掉,当然反射很强大,可以实现,但是这里介绍一种更简便的方式:

获取R.id.search_plateR.id.submit_area对应的 LinearLayout,设置 setBackground 为 null

    // 去掉搜索框默认的下划线
    search_plate = mSearchView.findViewById(R.id.search_plate);
    submit_area = mSearchView.findViewById(R.id.submit_area);
    search_plate.setBackground(null);
    submit_area.setBackground(null);` </pre>

3、设置搜索框背景样式

四、SearchView 搜索自动提示

上面提到过 SearchView.SearchAutoComplete 是继承 AutoCompleteTextView 类,根据setSuggestionsAdapter()方法可以实现输入搜索内容,自动提示的功能。关于 AutoCompleteTextView 类的使用,这里不做详细讲解,如果还有不会使用的朋友自行补习。

1、获取手机通讯录

setSuggestionsAdapter(CursorAdapter adapter)方法需要一个 CursorAdapter 参数,这里看到 Cursor,很多人就应该清楚,Cursor 光标或者游标。

正常情况下这里应该采用 Cursor 操作数据库,可以实现查询筛选功能,因为案例展示,这里以手机通讯录为例,搜索框输入信息后展示手机通讯录列表,不支持根据输入内容过滤功能。

    // 获取手机通讯录
    Cursor cursor = getContentResolver().query(ContactsContract.CommonDataKinds.Phone.CONTENT_URI, null, null, null, null); 

提示:获取通讯录需要手动申请权限

2、SimpleCursorAdapter 对象

      SimpleCursorAdapter simpleAdapter = new SimpleCursorAdapter(
                SearchViewActivity.this,
                R.layout.searchview_item, cursor,
                new String[]{ContactsContract.CommonDataKinds.Phone.DISPLAY_NAME},
                new int[]{R.id.name});` </pre>

参数:

3、SearchView 设置适配器

    // 设置SearchView 适配器
    mSearchView.setSuggestionsAdapter(simpleAdapter);
    //设置触发查询的最少字符数(默认2个字符才会触发查询)
    mSearchEditView.setThreshold(1);` </pre>
image

4、优化搜索列表

SearchView 展示的列表稍微有点丑,正常情况下都是在 Activity 中展示一个列表,所以在 Activity 布局中设置一个 ListView,使用方式和 SearchView.SearchAutoComplete 一致。

    private void setAdapter() {
Cursor cursor = getContentResolver().query(ContactsContract.CommonDataKinds.Phone.CONTENT_URI,null, null, null, null);
if (listView.getAdapter() != null) {
    ((SimpleCursorAdapter) listView.getAdapter()).changeCursor(cursor);
    } else {
    SimpleCursorAdapter simpleAdapter = new SimpleCursorAdapter(SearchViewActivity.this,
            R.layout.searchview_item, cursor,
            new String[]{ContactsContract.CommonDataKinds.Phone.DISPLAY_NAME},
            new int[]{R.id.name});
    listView.setAdapter(simpleAdapter);
}
  } 

在 SearchView 监听事件 setOnQueryTextListener 回调方法onQueryTextChange(String newText)中调用setAdapter()方法,上文讲过 onQueryTextChange 方法在搜索框文本发生变化时调用,可以实现实时刷新功能。

image

五、总结

SearchView 配合 Toolbar 在开发过程中可以快捷的实现 Tab 搜索效果,随着 Android 系统发展,原生控件也越来越漂亮,很多大厂品牌产品都采取原生的控件,所以 Android 高级 UI 部分还是非常值得学习的,如果你还不会,那就抓紧时间上车吧!

上一篇下一篇

猜你喜欢

热点阅读