使用DataBinding的Android SearchView示例教程

时间:2020-02-23 14:29:15  来源:igfitidea点击:

今天,我们将研究Android SearchView小部件,并开发一个应用程序,该应用程序可通过查询的文本过滤ListView。
我们将使用DataBinding来连接"活动"和"适配器"中的布局。
如果您尚未阅读有关DataBinding的信息,请先参阅本教程以获取更好的理解。

Android SearchView

Android通过在ToolBar/ActionBar中显示SearchView小部件或者将其插入到布局中来允许我们在应用中使用搜索功能。
从Android 3.0开始可以使用Android SearchView小部件。

SearchView在XML布局中定义,如下所示。

<android.support.v7.widget.SearchView
      android:id="@+id/search"
      android:layout_width="match_parent"
      android:layout_height="wrap_content" 

Android中有多种搜索形式,例如语音搜索,建议等。
在本教程中,我们将使用SearchView.OnQueryTextListener和Filterable接口。

Filterable接口过滤ListView上查询的文本,并显示结果ListView行。

OnQueryTextListener接口可以检测两个事件。

  • 当用户在文本字段中键入每个字符时,就会调用onQueryTextChange
  • 按下搜索时会触发onQueryTextSubmit

Android SearchView示例

下图显示了最终的Android SearchView示例项目。

该项目由一个Activity和一个用于ListView的适配器组成。

Android SearchView示例代码

下面给出activity_main.xml。
它由一个ListView和一个顶部的SearchView组成。

activity_main.xml

<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="https://schemas.android.com/apk/res/android">

  <RelativeLayout
      android:layout_width="fill_parent"
      android:layout_height="wrap_content"
      android:orientation="horizontal">

      <android.support.v7.widget.SearchView
          android:id="@+id/search"
          android:layout_width="match_parent"
          android:layout_height="wrap_content"
          android:clickable="true" 

      <ListView
          android:id="@+id/list_view"
          android:layout_width="fill_parent"
          android:layout_height="wrap_content"
          android:layout_alignParentLeft="true"
          android:layout_alignParentStart="true"
          android:layout_below="@+id/search" 

  </RelativeLayout>

</layout>

MainActivity.java在下面给出。

package com.theitroad.searchview;

import android.databinding.DataBindingUtil;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.support.v7.widget.SearchView;

import com.theitroad.searchview.databinding.ActivityMainBinding;

import java.util.ArrayList;
import java.util.List;

public class MainActivity extends AppCompatActivity {

  ActivityMainBinding activityMainBinding;
  ListAdapter adapter;

  List<String> arrayList= new ArrayList<>();

  @Override
  protected void onCreate(Bundle savedInstanceState) {
      super.onCreate(savedInstanceState);
      activityMainBinding = DataBindingUtil.setContentView(this, R.layout.activity_main);

      arrayList.add("January");
      arrayList.add("February");
      arrayList.add("March");
      arrayList.add("April");
      arrayList.add("May");
      arrayList.add("June");
      arrayList.add("July");
      arrayList.add("August");
      arrayList.add("September");
      arrayList.add("October");
      arrayList.add("November");
      arrayList.add("December");

      adapter= new ListAdapter(arrayList);
      activityMainBinding.listView.setAdapter(adapter);

      activityMainBinding.search.setActivated(true);
      activityMainBinding.search.setQueryHint("Type your keyword here");
      activityMainBinding.search.onActionViewExpanded();
      activityMainBinding.search.setIconified(false);
      activityMainBinding.search.clearFocus();

      activityMainBinding.search.setOnQueryTextListener(new SearchView.OnQueryTextListener() {
          @Override
          public boolean onQueryTextSubmit(String query) {
              return false;
          }

          @Override
          public boolean onQueryTextChange(String newText) {

              adapter.getFilter().filter(newText);

              return false;
          }
      });
  }
}

在上面的代码中,我们将一个ArrayList of Months传递给列表适配器。

每次搜索查询文本更改时,我们都会调用适配器类中定义的过滤器方法。

ListAdapter.java类如下所示。

package com.theitroad.searchview;

import android.content.Context;
import android.databinding.DataBindingUtil;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.Filter;
import android.widget.Filterable;
import com.theitroad.searchview.databinding.RowItemBinding;
import java.util.ArrayList;
import java.util.List;

public class ListAdapter extends BaseAdapter implements Filterable {

  List<String> mData;
  List<String> mStringFilterList;
  ValueFilter valueFilter;
  private LayoutInflater inflater;

  public ListAdapter(List<String> cancel_type) {
      mData=cancel_type;
      mStringFilterList = cancel_type;
  }

  @Override
  public int getCount() {
      return mData.size();
  }

  @Override
  public String getItem(int position) {
      return mData.get(position);
  }

  @Override
  public long getItemId(int position) {
      return position;
  }

  @Override
  public View getView(int position, View convertView, final ViewGroup parent) {

      if (inflater == null) {
          inflater = (LayoutInflater) parent.getContext()
                  .getSystemService(Context.LAYOUT_INFLATER_SERVICE);
      }
      RowItemBinding rowItemBinding = DataBindingUtil.inflate(inflater, R.layout.row_item, parent, false);
      rowItemBinding.stringName.setText(mData.get(position));

      return rowItemBinding.getRoot();
  }

  @Override
  public Filter getFilter() {
      if (valueFilter == null) {
          valueFilter = new ValueFilter();
      }
      return valueFilter;
  }

  private class ValueFilter extends Filter {
      @Override
      protected FilterResults performFiltering(CharSequence constraint) {
          FilterResults results = new FilterResults();

          if (constraint != null && constraint.length() > 0) {
              List<String> filterList = new ArrayList<>();
              for (int i = 0; i < mStringFilterList.size(); i++) {
                  if ((mStringFilterList.get(i).toUpperCase()).contains(constraint.toString().toUpperCase())) {
                      filterList.add(mStringFilterList.get(i));
                  }
              }
              results.count = filterList.size();
              results.values = filterList;
          } else {
              results.count = mStringFilterList.size();
              results.values = mStringFilterList;
          }
          return results;

      }

      @Override
      protected void publishResults(CharSequence constraint,
                                    FilterResults results) {
          mData = (List<String>) results.values;
          notifyDataSetChanged();
      }

  }

}

如您在上面的代码中看到的,我们正在使用内部类" ValueFilter"执行过滤,该内部类扩展了Filter类。
它通过检查搜索查询文本是否与ArrayList中给出的字符串匹配来过滤列表。

下面给出了ListView行的XML布局。

row_item.xml

<layout xmlns:android="https://schemas.android.com/apk/res/android">

  <RelativeLayout
      android:layout_width="match_parent"
      android:layout_height="wrap_content">

      <TextView
          android:id="@+id/stringName"
          android:layout_width="wrap_content"
          android:layout_height="wrap_content"
          android:layout_alignParentLeft="true"
          android:layout_alignParentStart="true"
          android:layout_centerVertical="true"
          android:padding="@dimen/activity_horizontal_margin"
          android:textAllCaps="false"
          android:textAppearance="?android:attr/textAppearanceMedium" 

  </RelativeLayout>

</layout>

运行中的android search view应用程序的输出如下。

上面显示的SearchView要求我们按搜索图标以激活文本字段。
另外,它不包含任何提示/占位符文本。

在MainActivity中添加以下代码以默认情况下启用SearchView并显示提示。

activityMainBinding.search.setActivated(true);
      activityMainBinding.search.setQueryHint("Type your keyword here");
      activityMainBinding.search.onActionViewExpanded();
      activityMainBinding.search.setIconified(false);
      activityMainBinding.search.clearFocus();