ActionBar 中的 SearchView -- *Up* 按钮的问题 [英] SearchView in ActionBar -- problems with the *Up* button
问题描述
我在 ListView
的 ActionBar
中使用了 SearchView
.可以触摸放大镜,SearchView
显示其编辑框,用户可以输入用于过滤列表内容的文本.它几乎有效.但是,当用户按下 Up 按钮时,SearchView
会折叠回图标,小部件内的文本会被清除,并且过滤会被重置.效果(就我而言)是只有当 SearchView
未图标化时才能过滤列表.所需的行为是在 SearchView
折叠后也保留过滤器文本.
注意:该行为可能在 Android 4.3 中发生了变化.使用 4.2.2 它可以正常工作.请参阅下面的观察结果.
详细信息:更具体地说,菜单包含以下项目:
注意图标和 android:showAsAction
.我相信 Up 按钮在 SearchView
展开时默认出现(Up 我的意思是 <
加图标 - 从官方 ,它清楚地表明他们将文本更改为""
:
@Override公共无效 onActionViewCollapsed() {setQuery("", false);清除焦点();更新视图可见性(真);mQueryTextView.setImeOptions(mCollapsedImeOptions);mExpandedInActionView = false;}/*** {@inheritDoc}*/@覆盖公共无效 onActionViewExpanded() {如果(mExpandedInActionView)返回;mExpandedInActionView = true;mCollapsedImeOptions = mQueryTextView.getImeOptions();mQueryTextView.setImeOptions(mCollapsedImeOptions | EditorInfo.IME_FLAG_NO_FULLSCREEN);mQueryTextView.setText("");设置图标化(假);}
如果您有问题,请告诉我.
I am using the the SearchView
in the ActionBar
of the ListView
. The magnifying glass can be touched, the SearchView
shows its edit box, and the user can enter the text for filtering the content of the list. It almost works. However, when the user presses the Up button, the SearchView
collapses back to the icon, the text inside the widget is cleared, and the filtering is reset. The effect (in my case) is that the list can be filtered only when the SearchView
is not iconified. The wanted behaviour is to keep the filter text also after the SearchView
was collapsed.
Attention: The behaviour probably changed in Android 4.3. With 4.2.2 it worked as wanted. See the observations below.
Details: To be more specific, the menu contains the following item:
<item android:id="@+id/menu_search_customers"
android:title="@string/menu_search_text"
android:icon="@android:drawable/ic_menu_search"
android:showAsAction="ifRoom|collapseActionView"
android:actionViewClass="android.widget.SearchView" />
Notice the icon and the android:showAsAction
. I belive the Up button appears by default when the SearchView
is expanded (by Up I mean the <
plus the icon -- see the right image with the blue book from the official Navigation with Back and Up). It seems that the default handler implementation just collapses the expanded SearchView
(returns back to the icon state).
When debugging, I have found that the onQueryTextChange()
is fired with the empty text when the Up is used. (I believe this was not the case with Android 4.2.2, because it worked as wanted before the OS update.) This is the reason why the filtering of the list items is also reset -- see my onQueryTextChange()
below. I want the SearchView
collapsed, and the filter text displayed as subtitle in the action bar.
So far, my code related to the SearchView
looks like this:
@Override
public boolean onCreateOptionsMenu(Menu menu) {
// MenuInflater adds the magnifying glass icon for the SearchView
// to the ActionBar as the always visible menu item.
MenuInflater inflater = getMenuInflater();
inflater.inflate(R.menu.customers_menu, menu);
// Get the related SearchView widget.
SearchView sv = (SearchView) menu.findItem(R.id.menu_search_customers)
.getActionView();
// Get the changes immediately.
sv.setOnQueryTextListener(new SearchView.OnQueryTextListener() {
// I am not sure whether the onQueryTextSubmit() is important
// for the purpose.
@Override
public boolean onQueryTextSubmit(String query) {
getActionBar().setSubtitle(mCurFilter);
return true;
}
@Override
public boolean onQueryTextChange(String newText) {
// The newText is stored into a member variable that
// is used when the new CursorLoader is created.
mCurFilter = newText;
getActionBar().setSubtitle(mCurFilter);
getLoaderManager().restartLoader(0, null,
CustomersOverviewActivity.this);
return true;
}
});
return true;
}
The restarted loader calls the onCreateLoader
. Notice the mCurFilter
is used for building the SQL query:
@Override
public Loader<Cursor> onCreateLoader(int id, Bundle args) {
String[] projection = { CustomerTable._ID,
CustomerTable.CODE,
CustomerTable.NAME,
CustomerTable.STREET,
CustomerTable.TOWN };
String selection = null; // init
String[] selectionArgs = null; // init
if ( ! mCurFilter.isEmpty()) {
selection = CustomerTable.NAME + " like ?";
selectionArgs = new String[]{ "%" + mCurFilter +"%" };
}
CursorLoader cursorLoader = new CursorLoader(this,
DemoContentProvider.CUSTOMERS_CONTENT_URI, projection,
selection, selectionArgs,
orderInfo);
return cursorLoader;
}
I would like to detect the situation when the Up is pressed before the onQueryTextChange()
is called. This way (say) I could set a flag and block the mCurFilter
assignment by the emptied SearchView
content. Also, when the search icon is expanded again, I would like to initialize the text in the expanded SearchView
from the mCurFilter
before it is shown (i.e. the expanded view is preset with the filter text). How that can be done?
Update: The earlier implementation of the SearchView
had...
@Override
public void onActionViewCollapsed() {
clearFocus();
updateViewsVisibility(true);
mQueryTextView.setImeOptions(mCollapsedImeOptions);
mExpandedInActionView = false;
}
Now, it contains...
@Override
public void onActionViewCollapsed() {
setQuery("", false);
clearFocus();
updateViewsVisibility(true);
mQueryTextView.setImeOptions(mCollapsedImeOptions);
mExpandedInActionView = false;
}
Do you know what could be the reason for setting the query to the empty string? Should I override the new implementation by the old code? Or is there a better way?
I have written a StatefulSearchView
which retains the text:
import android.content.Context;
import android.os.Parcel;
import android.os.Parcelable;
import android.text.TextUtils;
import android.util.AttributeSet;
import android.util.Log;
import android.view.View;
import android.widget.EditText;
import android.widget.SearchView;
import android.widget.SearchView.OnQueryTextListener;
import android.widget.TextView;
public class StatefulSearchView extends SearchView implements android.view.View.OnLayoutChangeListener, OnQueryTextListener,android.widget.SearchView.OnCloseListener{
private boolean mSaveText=true;
private OnQueryTextListener mQueryListener;
private String mQuery;
private OnCloseListener mCloseListener;
private boolean fromIconify = true;
public StatefulSearchView(Context context, AttributeSet attrs) {
super(context, attrs);
addOnLayoutChangeListener(this);
super.setOnCloseListener(this);
}
public StatefulSearchView(Context context) {
super(context);
// TODO Auto-generated constructor stub
addOnLayoutChangeListener(this);
super.setOnCloseListener(this);
}
public void setSaveSearchTextState(boolean save){
this.mSaveText = save;
this.setSaveEnabled(mSaveText);
}
public void setOnStatefulQueryTextListener(OnQueryTextListener listener) {
mQueryListener = listener;
super.setOnQueryTextListener(this);
}
@Override
public void onLayoutChange(View v, int left, int top, int right,
int bottom, int oldLeft, int oldTop, int oldRight, int oldBottom) {
if(super.isIconfiedByDefault() || !super.isIconified() && !TextUtils.isEmpty(mQuery) && mSaveText){
setSavedText(mQuery);
}
Log.i("onLayoutChanged()",""+mQuery);
}
@Override
public void setIconified(boolean iconify) {
mQuery = getQuery().toString();
Log.i("setIconified()",""+mQuery);
super.setOnCloseListener(null);
super.setIconified(iconify);
super.setIconified(iconify);
super.setOnCloseListener(this);
fromIconify = true;
}
@Override
public void setOnCloseListener(OnCloseListener listener) {
mCloseListener = listener;
super.setOnCloseListener(this);
}
@Override
protected Parcelable onSaveInstanceState() {
Parcelable state = super.onSaveInstanceState();
return new SearchQueryState(state, mQuery, mSaveText);
}
@Override
protected void onRestoreInstanceState(Parcelable state) {
SearchQueryState sqs = (SearchQueryState)state;
super.onRestoreInstanceState(sqs.getSuperState());
mQuery = sqs.getSavedQuery();
mSaveText = sqs.getSaveText();
}
@Override
public boolean onQueryTextChange(String arg0) {
mQuery = arg0;
return mQueryListener.onQueryTextChange(mQuery);
}
@Override
public boolean onQueryTextSubmit(String arg0) {
// TODO Auto-generated method stub
return mQueryListener.onQueryTextSubmit(arg0);
}
private TextView getTextView(){
int searchTextViewId = getContext().getResources().getIdentifier("android:id/search_src_text", null, null);
return (TextView) this.findViewById(searchTextViewId);
}
private void setSavedText(String s){
super.setOnQueryTextListener(null);
Log.i("setSavedText()",""+s);
TextView t = getTextView();
t.setText(s);
if(!TextUtils.isEmpty(s))
((EditText)t).setSelection(s.length());
super.setOnQueryTextListener(mQueryListener);
}
private class SearchQueryState extends BaseSavedState{
private boolean mSaveText;
private String mQueryText;
public SearchQueryState(Parcel arg0) {
super(arg0);
this.mQueryText = arg0.readString();
this.mSaveText = arg0.readInt() == 1;
}
public SearchQueryState(Parcelable superState, String queryText, boolean saveText) {
super(superState);
this.mQueryText = queryText;
this.mSaveText = saveText;
}
public boolean getSaveText(){
return this.mSaveText;
}
public String getSavedQuery(){
return mQueryText;
}
@Override
public void writeToParcel(Parcel dest, int flags) {
// TODO Auto-generated method stub
super.writeToParcel(dest, flags);
dest.writeString(mQueryText);
dest.writeInt(mSaveText? 1: 0);
}
}
@Override
public boolean onClose() {
Log.i("onClose()", "Is from setIconified(): "+fromIconify);
if(!fromIconify){
mQuery = null;
fromIconify = false;
}
return mCloseListener == null ? false : mCloseListener.onClose();
}
}
In demonstration activity:
public class MainActivity extends Activity{
private StatefulSearchView mSearchView;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
getActionBar().setHomeButtonEnabled(true);
}
@Override
public boolean onMenuItemSelected(int featureId, MenuItem item) {
if(item.getItemId()==android.R.id.home) {
mSearchView.setIconified(true);
return true;
}
return super.onMenuItemSelected(featureId, item);
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.main, menu);
MenuItem item = menu.findItem(R.id.action_search);
mSearchView =(StatefulSearchView)item.getActionView();
mSearchView.setSaveSearchTextState(true);
mSearchView.setOnStatefulQueryTextListener(new OnQueryTextListener(){
@Override
public boolean onQueryTextChange(String newText) {
// TODO Auto-generated method stub
return false;
}
@Override
public boolean onQueryTextSubmit(String query) {
// TODO Auto-generated method stub
return false;
}});
return true;
}
In menu xml:
<menu xmlns:android="http://schemas.android.com/apk/res/android" >
<item
android:id="@+id/action_search"
android:orderInCategory="100"
android:showAsAction="always"
android:actionViewClass="com.nikola.despotoski.saveablesearchview.StatefulSearchView"
android:title="@string/action_settings"/>
</menu>
In the source of the SearchView
, it clearly says that they change the text to ""
:
@Override
public void onActionViewCollapsed() {
setQuery("", false);
clearFocus();
updateViewsVisibility(true);
mQueryTextView.setImeOptions(mCollapsedImeOptions);
mExpandedInActionView = false;
}
/**
* {@inheritDoc}
*/
@Override
public void onActionViewExpanded() {
if (mExpandedInActionView) return;
mExpandedInActionView = true;
mCollapsedImeOptions = mQueryTextView.getImeOptions();
mQueryTextView.setImeOptions(mCollapsedImeOptions | EditorInfo.IME_FLAG_NO_FULLSCREEN);
mQueryTextView.setText("");
setIconified(false);
}
Let me know if you have issues.
这篇关于ActionBar 中的 SearchView -- *Up* 按钮的问题的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!