DataBindingを使用したAndroid SearchViewの例チュートリアル

今日はAndroidのSearchViewウィジェットを見て、クエリされたテキストでListViewをフィルタリングするアプリケーションを開発します。アクティビティとアダプターのレイアウトを接続するためにDataBindingを使用します。DataBindingについてまだ読んでいない場合は、まずこちらのチュートリアルを参照してください。

AndroidのSearchView

Androidでは、ToolBar/ActionBarにSearchViewウィジェットを表示したり、レイアウトに挿入したりしてアプリ内で検索機能を使用することができます。AndroidのSearchViewウィジェットはAndroid 3.0以降で利用可能です。SearchViewは以下のようにXMLレイアウトで定義されます。

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

音声検索、サジェストなど、Androidでの検索の形式はさまざまあります。このチュートリアルでは、SearchView.OnQueryTextListenerFilterableインターフェースを使用します。Filterableインターフェースは、クエリされたテキストをListView上でフィルタリングし、結果のListView行を表示します。OnQueryTextListenerインターフェースは2つのイベントを検出できます。

  1. onQueryTextChangeは、ユーザーがテキストフィールドに各文字を入力するたびに呼び出されます。
  2. onQueryTextSubmitは、検索が押されたときにトリガーされます。

Android SearchViewの例

下の画像は、最終的なAndroid SearchViewの例プロジェクトを示しています。このプロジェクトには、アクティビティとリストビュー用のアダプターが含まれています。

Android SearchViewの例のコード

次に示すのは、activity_main.xmlです。上部にSearchViewがあるListViewで構成されています。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.journaldev.searchview;

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

import com.journaldev.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をリストアダプターに渡しています。検索クエリのテキストが変更されるたびに、アダプタークラスで定義されているfilterメソッドを呼び出しています。ListAdapter.javaクラスは次のようになります。

package com.journaldev.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.journaldev.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();
        }

    }

}

上記のコードでわかるように、ArrayListに含まれる文字列と検索クエリのテキストが一致するかどうかを確認するために、Filterクラスを拡張したValueFilterという内部クラスを使用してフィルタリングを行っています。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の検索ビューアプリケーションの出力です。上記の表示されたSearchViewでは、テキストフィールドをアクティブにするために検索アイコンを押す必要があります。また、ヒント/プレースホルダーテキストも含まれていません。SearchViewをデフォルトで有効にし、ヒントを表示するために、MainActivityに以下のコードを追加してください。

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

上記のカスタマイズしたSearchViewは、次のようになります。これでAndroidのSearchViewチュートリアルは終了です。後のチュートリアルでは、SearchViewの高度な機能について詳しく説明します。以下のリンクからAndroid SearchViewプロジェクトをダウンロードすることができます。

Android SearchViewの例題プロジェクトをダウンロードする

Source:
https://www.digitalocean.com/community/tutorials/android-searchview-example-tutorial