(EditText を extends してるのに AutoCompleteEditText じゃないのはなぜなんだ)
こんな感じで候補の一覧を Adapter として用意して AutoCompleteTextView の setAdapter() でセットします。
- public class CountriesActivity extends Activity {
- protected void onCreate(Bundle icicle) {
- super.onCreate(icicle);
- setContentView(R.layout.countries);
- AutoCompleteTextView textView = (AutoCompleteTextView) findViewById(R.id.countries_list);
- ArrayAdapter<String> adapter = new ArrayAdapter<String>(this, android.R.layout.simple_dropdown_item_1line, COUNTRIES);
- textView.setAdapter(adapter);
- }
- private static final String[] COUNTRIES = new String[] {
- "Belgium", "France", "Italy", "Germany", "Spain"
- };
- }
そこで、SearchManager の出番です。
SearchManager については以前のエントリ「Y.A.M の雑記帳 - Android SearchManager 検索ボックスを使うぜ!」あたりをみてください。
簡単にいうと、SearchManager から候補一覧の Cursor(候補は ContentProvider として提供される)を取得して、それを Adapter にセットすればいいわけです。
SearchManager から候補一覧を取得するには SearchManager の getSuggestions() を呼べばいいのですが、残念ながら @hide です。 ただ、SearchableInfo があれば同じことはできます。
シンプルな Adapter だとだいたいこんな感じです。
- import android.app.SearchManager;
- import android.app.SearchableInfo;
- import android.content.ContentResolver;
- import android.content.Context;
- import android.database.Cursor;
- import android.net.Uri;
- import android.support.v4.widget.ResourceCursorAdapter;
- import android.text.TextUtils;
- import android.util.Log;
- import android.view.View;
- import android.view.ViewGroup;
- import android.widget.TextView;
- class SearchRecentSuggestionsAdapter extends ResourceCursorAdapter {
- private static final boolean DEBUG = false;
- private static final String LOG_TAG = "SearchRecentSuggestionsAdapter";
- private static final int QUERY_LIMIT = 50;
- private SearchableInfo mSearchable;
- private boolean mClosed = false;
- static final int INVALID_INDEX = -1;
- private int mText1Col = INVALID_INDEX;
- public SearchRecentSuggestionsAdapter(Context context, SearchableInfo searchable) {
- super(context, R.layout.search_recent_row, null, true);
- mSearchable = searchable;
- }
- /**
- * Overridden to always return <code>false</code>, since we cannot be sure
- * that suggestion sources return stable IDs.
- */
- @Override
- public boolean hasStableIds() {
- return false;
- }
- /**
- * Use the search suggestions provider to obtain a live cursor. This will be
- * called in a worker thread, so it's OK if the query is slow (e.g. round
- * trip for suggestions). The results will be processed in the UI thread and
- * changeCursor() will be called.
- */
- @Override
- public Cursor runQueryOnBackgroundThread(CharSequence constraint) {
- if (DEBUG)
- Log.d(LOG_TAG, "runQueryOnBackgroundThread(" + constraint + ")");
- String query = (constraint == null) ? "" : constraint.toString();
- Cursor cursor = null;
- try {
- cursor = getSuggestions(mSearchable, query, QUERY_LIMIT);
- return cursor;
- } catch (RuntimeException e) {
- Log.w(LOG_TAG, "Search suggestions query threw an exception.", e);
- }
- return null;
- }
- public Cursor getSuggestions(SearchableInfo searchable, String query, int limit) {
- if (searchable == null) {
- return null;
- }
- String authority = searchable.getSuggestAuthority();
- if (authority == null) {
- return null;
- }
- Uri.Builder uriBuilder = new Uri.Builder().scheme(ContentResolver.SCHEME_CONTENT).authority(authority);
- // if content path provided, insert it now
- final String contentPath = searchable.getSuggestPath();
- if (contentPath != null) {
- uriBuilder.appendEncodedPath(contentPath);
- }
- // append standard suggestion query path
- uriBuilder.appendPath(SearchManager.SUGGEST_URI_PATH_QUERY);
- // get the query selection, may be null
- String selection = searchable.getSuggestSelection();
- // inject query, either as selection args or inline
- String[] selArgs = null;
- if (selection != null) {
- // use selection if provided
- selArgs = new String[] { query };
- } else {
- // no selection, use REST pattern
- uriBuilder.appendPath(query);
- }
- if (limit > 0) {
- uriBuilder.appendQueryParameter(SearchManager.SUGGEST_PARAMETER_LIMIT, String.valueOf(limit));
- }
- Uri uri = uriBuilder.build();
- return mContext.getContentResolver().query(uri, null, selection, selArgs, null);
- }
- public void close() {
- if (DEBUG)
- Log.d(LOG_TAG, "close()");
- changeCursor(null);
- mClosed = true;
- }
- /**
- * Cache columns.
- */
- @Override
- public void changeCursor(Cursor c) {
- if (DEBUG)
- Log.d(LOG_TAG, "changeCursor(" + c + ")");
- if (mClosed) {
- Log.w(LOG_TAG, "Tried to change cursor after adapter was closed.");
- if (c != null)
- c.close();
- return;
- }
- try {
- super.changeCursor(c);
- if (c != null) {
- mText1Col = c.getColumnIndex(SearchManager.SUGGEST_COLUMN_TEXT_1);
- }
- } catch (Exception e) {
- Log.e(LOG_TAG, "error changing cursor and caching columns", e);
- }
- }
- /**
- * Tags the view with cached child view look-ups.
- */
- @Override
- public View newView(Context context, Cursor cursor, ViewGroup parent) {
- View v = super.newView(context, cursor, parent);
- v.setTag(new ViewHolder(v));
- return v;
- }
- /**
- * Cache of the child views of drop-drown list items, to avoid looking up
- * the children each time the contents of a list item are changed.
- */
- private final static class ViewHolder {
- public final TextView mText1;
- public ViewHolder(View v) {
- mText1 = (TextView) v.findViewById(android.R.id.text1);
- }
- }
- @Override
- public void bindView(View view, Context context, Cursor cursor) {
- ViewHolder views = (ViewHolder) view.getTag();
- if (views.mText1 != null) {
- String text1 = getStringOrNull(cursor, mText1Col);
- views.mText1.setText(text1);
- views.mText1.setVisibility(TextUtils.isEmpty(text1) ? View.GONE : View.VISIBLE);
- }
- }
- /**
- * Gets the text to show in the query field when a suggestion is selected.
- *
- * @param cursor
- * The Cursor to read the suggestion data from. The Cursor should
- * already be moved to the suggestion that is to be read from.
- * @return The text to show, or <code>null</code> if the query should not be
- * changed when selecting this suggestion.
- */
- @Override
- public CharSequence convertToString(Cursor cursor) {
- if (cursor == null) {
- return null;
- }
- String query = getColumnString(cursor, SearchManager.SUGGEST_COLUMN_QUERY);
- if (query != null) {
- return query;
- }
- if (mSearchable.shouldRewriteQueryFromData()) {
- String data = getColumnString(cursor, SearchManager.SUGGEST_COLUMN_INTENT_DATA);
- if (data != null) {
- return data;
- }
- }
- if (mSearchable.shouldRewriteQueryFromText()) {
- String text1 = getColumnString(cursor, SearchManager.SUGGEST_COLUMN_TEXT_1);
- if (text1 != null) {
- return text1;
- }
- }
- return null;
- }
- /**
- * This method is overridden purely to provide a bit of protection against
- * flaky content providers.
- *
- * @see android.widget.ListAdapter#getView(int, View, ViewGroup)
- */
- @Override
- public View getView(int position, View convertView, ViewGroup parent) {
- try {
- return super.getView(position, convertView, parent);
- } catch (RuntimeException e) {
- Log.w(LOG_TAG, "Search suggestions cursor threw exception.", e);
- // Put exception string in item title
- View v = newView(mContext, mCursor, parent);
- if (v != null) {
- ViewHolder views = (ViewHolder) v.getTag();
- TextView tv = views.mText1;
- tv.setText(e.toString());
- }
- return v;
- }
- }
- public static String getColumnString(Cursor cursor, String columnName) {
- int col = cursor.getColumnIndex(columnName);
- return getStringOrNull(cursor, col);
- }
- private static String getStringOrNull(Cursor cursor, int col) {
- if (col == INVALID_INDEX) {
- return null;
- }
- try {
- return cursor.getString(col);
- } catch (Exception e) {
- Log.e(LOG_TAG, "unexpected error retrieving valid column from cursor, " + "did the remote process die?", e);
- return null;
- }
- }
- }
- <?xml version="1.0" encoding="utf-8"?>
- <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
- android:padding="8dip"
- android:layout_width="match_parent"
- android:layout_height="48dip" >
- <TextView android:id="@android:id/text1"
- style="?android:attr/dropDownItemStyle"
- android:textAppearance="?android:attr/textAppearanceSearchResultTitle"
- android:singleLine="true"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:layout_centerVertical="true" />
- </RelativeLayout>
- public class InputActivity extends Activity {
- protected void onCreate(Bundle icicle) {
- super.onCreate(icicle);
- setContentView(R.layout.main);
- final AutoCompleteTextView textView = (AutoCompleteTextView) findViewById(R.id.editText1);
- SearchManager searchManager = (SearchManager) getSystemService(Context.SEARCH_SERVICE);
- final SearchableInfo info = searchManager.getSearchableInfo(getComponentName());
- textView.setThreshold(info.getSuggestThreshold());
- textView.setImeOptions(info.getImeOptions());
- int inputType = info.getInputType();
- if ((inputType & InputType.TYPE_MASK_CLASS) == InputType.TYPE_CLASS_TEXT) {
- inputType &= ~InputType.TYPE_TEXT_FLAG_AUTO_COMPLETE;
- if (info.getSuggestAuthority() != null) {
- inputType |= InputType.TYPE_TEXT_FLAG_AUTO_COMPLETE;
- }
- }
- textView.setInputType(inputType);
- if (info.getSuggestAuthority() != null) {
- // 候補の CursorAdapter をセット
- SearchRecentSuggestionsAdapter adapter = new SearchRecentSuggestionsAdapter(this, info);
- textView.setAdapter(adapter);
- }
- findViewById(R.id.button1).setOnClickListener(new View.OnClickListener() {
- @Override
- public void onClick(View v) {
- // 検索文字列を候補に追加
- String query = textView.getText().toString();
- SearchRecentSuggestions suggestions = new SearchRecentSuggestions(InputActivity.this, info.getSuggestAuthority(),
- SearchRecentSuggestionsProvider.DATABASE_MODE_QUERIES);
- suggestions.saveRecentQuery(query, null);
- }
- });
- }
- }
0 件のコメント:
コメントを投稿