简体   繁体   English

ActionBar中的SearchView - * Up *按钮的问题

[英]SearchView in ActionBar — problems with the *Up* button

I am using the the SearchView in the ActionBar of the ListView . 我在ListViewActionBar中使用SearchView 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. 可以触摸放大镜, SearchView显示其编辑框,用户可以输入文本以过滤列表内容。 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. 但是,当用户按下向上按钮时, SearchView折叠回图标,清除窗口小部件内的文本,并重置过滤。 The effect (in my case) is that the list can be filtered only when the SearchView is not iconified. 效果(在我的情况下)是只有在SearchView没有图标化时才能过滤列表。 The wanted behaviour is to keep the filter text also after the SearchView was collapsed. 想要的行为是在SearchView折叠后保留过滤器文本。

Attention: The behaviour probably changed in Android 4.3. 注意: Android 4.3中的行为可能已更改。 With 4.2.2 it worked as wanted. 4.2.2它按预期工作。 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 . 注意图标和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 ). 我相信,当SearchView被展开时,默认情况下会出现向上按钮(按向上我的意思是<加上图标 - 使用官方导航中的蓝图和后退和向上看到右图)。 It seems that the default handler implementation just collapses the expanded SearchView (returns back to the icon state). 似乎默认处理程序实现只是折叠扩展的SearchView (返回图标状态)。

右图中的*向上*按钮示例

When debugging, I have found that the onQueryTextChange() is fired with the empty text when the Up is used. 在调试时,我发现当使用Up时,使用空文本触发onQueryTextChange() (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. (我相信这不是Android 4.2.2的情况,因为它在操作系统更新之前按原样运行。)这就是为什么列表项的过滤也被重置的原因 - 请参阅下面的onQueryTextChange() I want the SearchView collapsed, and the filter text displayed as subtitle in the action bar. 我希望SearchView折叠,过滤器文本显示为操作栏中的副标题。

So far, my code related to the SearchView looks like this: 到目前为止,我与SearchView相关的代码如下所示:

@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 . 重新启动的加载程序调用onCreateLoader Notice the mCurFilter is used for building the SQL query: 请注意, mCurFilter用于构建SQL查询:

@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. 我想检测在调用onQueryTextChange() 之前按下Up的情况。 This way (say) I could set a flag and block the mCurFilter assignment by the emptied SearchView content. 这样(比方说)我可以设置一个标志并通过清空的SearchView内容阻止mCurFilter分配。 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 (ie the expanded view is preset with the filter text). 此外,当再次展开搜索图标时,我想在mCurFilter 之前mCurFilter初始化扩展的SearchView的文本(即展开的视图是使用过滤器文本预设的)。 How that can be done? 怎么做?

Update: The earlier implementation of the SearchView had... 更新: SearchView的早期实现有......

@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: 我写了一个StatefulSearchView ,它保留了文本:

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: 在菜单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 "" : SearchView的源代码中,它清楚地表明他们将文本更改为""

@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. 如果您有问题,请告诉我。

I'm not sure I understand your problem but you can just detect when up is clicked like this: 我不确定我是否理解你的问题,但你可以检测到点击的时间是这样的:

@Override
public boolean onOptionsItemSelected(MenuItem item) {
    switch (item.getItemId()) {
        case android.R.id.home:
            doSOmething();
            return true;
    }
    return super.onOptionsItemSelected(item);
}

If you intercept the up click, you can presumably do anything you want here. 如果您拦截向上点击,您可以在这里做任何你想要的事情。 Returning true will consume the event and that should prevent any default action from taking place. 返回true将消耗该事件,并且应该阻止任何默认操作发生。 This way you can do whatever you want the up button to do while at the same time consuming the up event to prevent clearing of your filters. 通过这种方式,您可以执行任何您想要的向上按钮,同时消耗向上事件以防止清除过滤器。

I struggle with this a little until I found the solution. 在我找到解决方案之前,我有点挣扎。

Declare your menuItem like this, check the showAsAction attribute, type only ifRoom, if you set collapseActionView the widget will collapse and show the back button on the actionbar 像这样声明你的menuItem,检查showAsAction属性,只键入ifRoom,如果设置collapseActionView,小部件将折叠并显示操作栏上的后退按钮

<menu xmlns:android="http://schemas.android.com/apk/res/android" >
 <item
        android:id="@+id/search"
        android:actionViewClass="android.widget.SearchView"
        android:icon="@drawable/ic_2_action_search"
        android:showAsAction="ifRoom"
        android:title="@null"/>
</menu>

Set up your SearchView as usual, remember to Add setIconifiedByDefault this will make the icon to start up as an icon 像往常一样设置SearchView,记得添加setIconifiedByDefault这将使图标以图标的形式启动

SearchManager searchManager = (SearchManager)getSystemService(Context.SEARCH_SERVICE);
searchView = (SearchView) menu.findItem(R.id.search).getActionView();
searchView.setIconifiedByDefault(true);
searchView.setOnQueryTextListener(new SearchViewOnQueryListener());
searchView.setOnCloseListener(new SearchViewOnCloseListener());
searchView.setSearchableInfo(searchManager.getSearchableInfo(getComponentName()));

On your QueryListener is where you handle the end of your search like so, here is where you use onActionViewCollapse() which collapse back the ViewSearch 在您的QueryListener上,您可以像这样处理搜索结束,这里是使用onActionViewCollapse()的地方,它会折叠ViewSearch

@Override
public boolean onQueryTextSubmit(String query) {
            makeSearchRequest(SEARCH_TYPE_KEYWORD, query);
        searchView.setQuery("", false);
        searchView.clearFocus();
        searchView.onActionViewCollapsed();
        buttonClearSearchResults.setVisibility(View.VISIBLE);
        return false;
    }

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM