2013-08-09 3 views
7

Я использую SearchView в ActionBarListView. Увеличительное стекло можно коснуться, SearchView показывает окно редактирования, и пользователь может ввести текст для фильтрации содержимого списка. Это почти работает. Однако, когда пользователь нажимает кнопку Up, SearchView сбрасывается обратно на значок, текст внутри виджета очищается, и фильтрация сбрасывается. Эффект (в моем случае) заключается в том, что список можно фильтровать только тогда, когда SearchView не отображается. Желаемое поведение заключается в том, чтобы сохранить текст фильтра также после обнуления SearchView.SearchView в ActionBar - проблемы с кнопкой * Up *

Внимание: Поведение, вероятно, изменилось в Android 4.3. С 4.2.2 он работал как раз. См. Замечания ниже.

Детали: Чтобы быть более конкретным, меню содержит следующие пункты:

<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" /> 

Обратите внимание на значок и android:showAsAction. Я верю, что кнопка Вверх появляется по умолчанию, когда SearchView расширен (на Вверх Я имею в виду < плюс значок - см. Правильное изображение с синей книгой от официального Navigation with Back and Up). Кажется, что реализация обработчика по умолчанию просто сворачивает развернутый SearchView (возвращается в состояние значка).

The *Up* button example at the right image

При отладке, я обнаружил, что onQueryTextChange() увольняют с пустым текстом, когда Up используется. (Я считаю, что это не относится к Android 4.2.2, потому что оно работало так, как нужно до обновления ОС.) Именно поэтому фильтрация элементов списка также сбрасывается - см. Мой onQueryTextChange() ниже. Я хочу, чтобы SearchView рухнул, а текст фильтра отображался как субтитр в панели действий.

До сих пор мой код связан с 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; 
} 

возобновленный погрузчик вызывает onCreateLoader. Обратите внимание, что 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; 
} 

Я хотел бы, чтобы обнаружить ситуацию, когда Up нажимается перед темonQueryTextChange() называется. Таким образом (скажем) я могу установить флаг и заблокировать назначение mCurFilter пустым содержимым SearchView. Кроме того, когда значок поиска снова расширяется, я хотел бы инициализировать текст в развернутом SearchView от mCurFilterдо (показано расширенное представление с текстом фильтра). Как это можно сделать?

Update: Ранее реализация SearchView была ...

@Override 
public void onActionViewCollapsed() { 
    clearFocus(); 
    updateViewsVisibility(true); 
    mQueryTextView.setImeOptions(mCollapsedImeOptions); 
    mExpandedInActionView = false; 
} 

Теперь она содержит ...

@Override 
public void onActionViewCollapsed() { 
    setQuery("", false); 
    clearFocus(); 
    updateViewsVisibility(true); 
    mQueryTextView.setImeOptions(mCollapsedImeOptions); 
    mExpandedInActionView = false; 
} 

Вы знаете, что может послужить причиной установки запроса на пустую строку? Должен ли я переопределить новую реализацию старым кодом? Или есть лучший способ?

+0

Интересная, для какой версии Android вы разрабатываете? Я хотел получить этот эффект, но не смог его достичь, мой поиск DID Неясно, когда я рухнул поиск ...:/ – o0rebelious0o

+0

Последний 4.3. Я просто учился, пытаясь создать демо-приложение. Совместимость со старыми версиями Android - это задача, запланированная на более поздний срок. Приятно иметь подтверждение, как мне показалось, что он работал раньше, когда я использовал 4.2. Но я не был уверен, не изменился ли код с того времени. – pepr

+0

Да, я считаю, что это на самом деле ошибка в раннем андроиде. Вы просмотрели http://developer.android.com/reference/android/view/CollapsibleActionView.html для onActionViewCollapsed(), чтобы обрабатывать очистку результатов поиска? (Ошибка в раннем андроиде означала, что этот метод бесполезен * вздох *) – o0rebelious0o

ответ

7

Я написал 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(); 
    } 


} 

В демонстрационной деятельности:

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; 
    } 

В меню 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> 

В источнике 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); 
    } 

Дайте мне знать, если у вас есть вопросы.

+0

Hi Nikola. Спасибо за код. В настоящее время у меня нет устройства Android для тестирования. Я не так хорошо разбираюсь в деталях «StatefulSearchView». Во всяком случае, 'onActionViewCollapsed' не содержал первый' setQuery ("", false) 'в предыдущей версии. Кажется, это след ... – pepr

+1

Теперь я вижу это лучше. Таким образом, ядро ​​должно переопределить методы onActionViewCollapsed и 'onActionViewExpanded'. 'Super.onActionViewXxxx();' выполняет код по умолчанию и добавляет полученный. «MSaveText» - это логический флаг, упомянутый в обновлении. Возможно, я, скорее всего, захочу использовать флаг в 'onQueryTextChange' вместо изменения слушателя. – pepr

+0

Да, это длинный рассказ короткий. –

1

Я не уверен, я понимаю вашу проблему, но вы можете просто определить, когда до щелчка, как это:

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

Если вы перехватывать вверх нажмите кнопку, вы, вероятно, может сделать все, что вы хотите здесь. Возврат true будет использовать событие, и это должно помешать любому действию по умолчанию. Таким образом, вы можете делать все, что хотите, чтобы кнопка «вверх» выполнялась одновременно, в то же время потребляя событие «вверх», чтобы предотвратить очистку фильтров.

+0

У меня есть вопрос. Пожалуйста, посмотрите на это. Если я правильно понял ваш код, это может быть способ узнать, когда нужно развернуть 'SearchView'. Во всяком случае, я нашел «трюк» только как рекомендацию «Оставшаяся обратная совместимость» (http://developer.android.com/training/search/backward-compat.html). Нет ли лучшего способа * внутри * SearchView'? – pepr

+0

Спасибо, и мой +1 за то, что напомнил мне, что 'SearchView' по-прежнему связан с меню в этом случае. – pepr

1

Я немного борюсь с этим, пока не нашел решение.

Объявить свой MENUITEM, как это, проверьте атрибут showAsAction, введите только ifRoom, если вы установите collapseActionView виджет разрушится и показать кнопку назад на ActionBar

<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> 

Установите свой 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())); 

на вашем QueryListener где вы обрабатывать конец вашего поиска, как это так, вот где вы используете onActionViewCollapse(), которые разрушаются обратно ViewSearc h

@Override 
public boolean onQueryTextSubmit(String query) { 
      makeSearchRequest(SEARCH_TYPE_KEYWORD, query); 
     searchView.setQuery("", false); 
     searchView.clearFocus(); 
     searchView.onActionViewCollapsed(); 
     buttonClearSearchResults.setVisibility(View.VISIBLE); 
     return false; 
    } 
Смежные вопросы