web-dev-qa-db-ja.com

SearchViewの状態を復元するためのより良い方法はありますか?

SearchViewに折りたたみ可能なActionBarがあります。検索が実行された後、関連するListViewがフィルタリングされ、一致するアイテムのみが表示されます。その状態の間、SearchViewは展開されたままで、検索文字列が表示されます。ユーザーがSearchViewを閉じると、フィルターを削除します。

検索状態を復元したい、例えば構成の変更時、または別のアクティビティから戻ったときにアクティビティが破棄された場合。

onRestoreInstanceState()でクエリ文字列を復元し、onCreateOptionsMenu()でクエリ文字列を見つけた場合は

searchView.setQuery(query, true); 

クエリを再度実行するため。これは、クエリフィルターをすぐに適用するよりも優れていることがわかりましたonRestoreInstanceState()。後者の場合、リストはすぐにフィルタリングされずに表示され、クエリが再度適用されます。 setQuery()では、これは起こりません。

問題:クエリが実行され、リストがフィルタリングされますが、検索ビューは折りたたまれたままです。したがって、ユーザーは検索ビューを使用してフィルターを削除したり、別のクエリを適用したりすることはできません。

onCreateOptionsMenu()では、検索アイテムと検索ビューが存在することを確認できるため、searchItem.expandActionView()を呼び出すことができます。不思議なことに、これだけが実際にActionViewを展開します。setIconified(false)を呼び出しても、2回続けて呼び出された場合でも、ビューは展開されません。

expandActionView()を呼び出す前にsetQuery()を使用すると、SearchViewが開き、テキストが表示されます(それ以外の場合、expandActionView()SearchViewを空にします)。

残念ながら、expandActionView()には副作用があります。提案リストも表示され、キーボードが開きます。

searchView.clearFocus()を使用してキーボードを非表示にできます。したがって、残りの問題は提案リストです。テキストのあるSearchViewで開いている提案リストを閉じるにはどうすればよいですか?

それほど多くの副作用がないアクションバーの検索ビューを復元するためのより良い方法があるのだろうか。

18
dschulten

回避策を見つけました。それは非常に醜いですが、それは機能します。

これが、構成の変更後に検索ボックスインスタンスの状態を復元する方法です。

まず、onRestoreInstanceStateでクエリ文字列を復元します

currentQuery = state.getString(KEY_SAVED_FILTER_CONSTRAINT);

OnCreateOptionsMenuで検索ビューを設定し、currentQueryがある場合は、検索項目を展開してクエリを再送信します。フォーカスをクリアしてキーボードを非表示にします。

    MenuItem searchItem = menu.findItem(R.id.action_search);
    searchView = (SearchView) searchItem.getActionView();
    searchView.setSearchableInfo(searchManager
            .getSearchableInfo(getComponentName()));

    if (!TextUtils.isEmpty(currentQuery)) {
        searchItem.expandActionView();
        searchView.setQuery(currentQuery, true);
        searchView.clearFocus();
    }

最後に、提案リストを閉じる必要があります。検索ビューからクエリテキストビューを取得する方法は次のとおりです。

private AutoCompleteTextView findQueryTextView(ViewGroup viewGroup) {
    AutoCompleteTextView queryTextView = null;
    if (viewGroup != null) {
        int childCount = viewGroup.getChildCount();
        for (int i = 0; i < childCount; i++) {
            View child = viewGroup.getChildAt(i);
            if (child instanceof AutoCompleteTextView) {
                queryTextView = (AutoCompleteTextView) child;
                break;
            } else if (child instanceof ViewGroup) {
                queryTextView = findQueryTextView((ViewGroup) child);
                if (queryTextView != null) {
                    break;
                }
            }
        }
    }
    return queryTextView;
} 

次に、提案リストを却下できます。

    AutoCompleteTextView queryTextView = findQueryTextView(searchView);
    if (queryTextView != null) {
        queryTextView.dismissDropDown();
    }

ただし、これはonCreateOptionsMenu内からは機能しません。それを機能させるには、dismissDropDownの呼び出しをアクティビティのonNewIntentメソッドに移動する必要がありました。

これを非常に醜いものにしているのは、復元手順がライフサイクルのさまざまなフェーズに分散していることと、提案リストに到達するために再帰的なビュー検索が必要であるという事実です。

14
dschulten

私の愚見で。 searchViewの状態を復元する場合は、 onSaveInstanceState(Bundle outState) を使用する必要があります。 onCreate(Bundle)または onRestoreInstanceState(Bundle) で状態を復元できるように、強制終了される前にアクティビティからインスタンスごとの状態を取得するために呼び出されます(このメソッドによって入力されたバンドルは両方に渡されます) 。

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
    // if you saved something on outState you can recover them here
    if (savedInstanceState != null) {
             mSearchString = savedInstanceState.getString(SEARCH_KEY);
    }
}

// This is called before the activity is destroyed
@Override
protected void onSaveInstanceState(Bundle outState) {
    super.onSaveInstanceState(outState);
    mSearchString = mSearchView.getQuery().toString();
    outState.putString(SEARCH_KEY, mSearchString);
}

このメソッドは、アクティビティが強制終了される前に呼び出されるため、将来戻ってきたときに状態を復元できます。これで、ユーザーが向きを変更したときに、onCreate(Bundle)またはonRestoreInstanceState(Bundle)を介してユーザーインターフェイスの状態を復元できます。

SearchViewにフォーカスする必要があるため、 onCreateOptionsMenu(Menu menu) を使用する必要があります。

@Override
public boolean onCreateOptionsMenu(Menu menu) {
    getMenuInflater().inflate(R.menu.main, menu);

    MenuItem searchMenuItem = menu.findItem(R.id.menu_main_action_search);

    mSearchView = (SearchView) MenuItemCompat.getActionView(searchMenuItem);

    //focus the SearchView
    if (mSearchString != null && !mSearchString.isEmpty()) {
        searchMenuItem.expandActionView();
        mSearchView.setQuery(mSearchString, true);
        mSearchView.clearFocus();
    }

    return super.onCreateOptionsMenu(menu);
}

また、完全なコードで このリンク を確認することもできます。

7
Cabezas