ActionBar 中的 SearchView -- *Up* 按钮的问题 [英] SearchView in ActionBar -- problems with the *Up* button

查看:16
本文介绍了ActionBar 中的 SearchView -- *Up* 按钮的问题的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我在 ListViewActionBar 中使用了 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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆