2012-11-27 12 views
19

Sto usando Android 4.1.2. Ho un widget SearchView su un ActionBar. Documentazione su SearchView.OnQueryTextListener dal sito per sviluppatori Android indica che viene generato onQueryTextSubmit quando "Chiamato quando l'utente invia la query, a causa di una pressione di un tasto sulla tastiera o della pressione di un pulsante di invio".Android SearchView.OnQueryTextListener OnQueryTextSubmit non attivato sulla stringa di query vuota

Ciò non accade se la query di ricerca è vuota. Ho bisogno di questo per sparare su una query vuota per cancellare il filtro di ricerca di un ListView. È un errore o sto facendo qualcosa di sbagliato?

risposta

13

E non è un bug, il source code controlla deliberatamente contro i valori nulli e vuoti:

private void onSubmitQuery() { 
    CharSequence query = mQueryTextView.getText(); 
    if (query != null && TextUtils.getTrimmedLength(query) > 0) { 

Tuttavia si dovrebbe essere in grado di utilizzare il callback OnQueryTextChange per cancellare filterables del vostro ListView quando l'utente cancella l'EditText ricerca.

+10

Grazie per le informazioni e la ricerca nel codice sorgente. Credo che l'OnQueryTextSubmit debba essere attivato anche se il testo della query è vuoto per consentirci di cancellare il filtro di ricerca e visualizzare di nuovo l'intero elenco non filtrato. Anche se inseguo il testo della query tramite l'evento OnQueryTextChange, il problema si verifica quando il testo della ricerca diventa vuoto. Nessun evento è stato licenziato. Dovrei mettere un'altra voce di menu nella barra delle azioni solo per visualizzare di nuovo l'intero elenco non filtrato. – tborja

+0

Suggerisco che quando OnQueryTextChange ti informa che la ricerca di EditText è vuota, cancelli manualmente il filtro. Sono d'accordo nel cercare di chiamare 'onSubmitQuery()' con una stringa vuota in qualsiasi modo, semplicemente non funzionerà. – Sam

+0

In alcuni casi non si desidera eseguire il filtraggio immediato (sul cambio di testo), poiché l'elenco dei suggerimenti lo sta già facendo. Quindi si filtra la lista reale solo al clic di ricerca. E poi è necessario che l'utente abbia la possibilità di cancellare questa ricerca. Quindi sì, penso anche che questo controllo sia un bug. – Ixx

0

Non è possibile sovrascrivere questo comportamento. Una soluzione alternativa potrebbe essere quella di cancellare il filtro, quando un utente esce dal searchview.

Per questo è possibile utilizzare OnCloseListener. Tuttavia, questo può causare anche problemi, a seconda del livello API minimo per il quale si sta sviluppando.

1

Ho avuto lo stesso problema, dal momento che le query vuote non sono supportate, ho dovuto scaricare e utilizzare ActionBarSherlock e quindi modificare il metodo onSubmitQuery().

Ecco come il mio onSubmitQuery() sembra ora

private void onSubmitQuery() { 
    CharSequence query = mQueryTextView.getText(); 
    if (query == null) {query = "";} 
    if (mOnQueryChangeListener == null 
      || !mOnQueryChangeListener.onQueryTextSubmit(query.toString())) { 
     if (mSearchable != null) { 
      launchQuerySearch(KeyEvent.KEYCODE_UNKNOWN, null, query.toString()); 
      setImeVisibility(false); 
     } 
     dismissSuggestions(); 
    } 
} 

Spero che questo aiuti.

+0

Questo funziona ... non è bello modificare la libreria, ma non ho trovato un'altra soluzione. – Ixx

10

Ho avuto lo stesso problema e finire con la seguente soluzione: personalizzato SearchView + OnQueryTextListener.onQueryTextChange

personalizzato SearchView:

public class MySearchView extends SearchView { 

private boolean expanded; 

public MySearchView(Context context) { 
    super(context); 
} 

@Override 
public void onActionViewExpanded() { 
    super.onActionViewExpanded(); 
    expanded = true; 
} 

@Override 
public void onActionViewCollapsed() { 
    super.onActionViewCollapsed(); 
    expanded = false; 
} 

public boolean isExpanded() { 
    return expanded; 
} 
} 

Creazione azione e l'impostazione di richiamata:

@Override 
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) { 
    super.onCreateOptionsMenu(menu, inflater); 
    searchAction = menu.add(0, SEARCH_ACTION_ID, 0 , getString(R.string.action_search)); 
    searchAction.setShowAsAction(SHOW_AS_ACTION_ALWAYS | SHOW_AS_ACTION_COLLAPSE_ACTION_VIEW);  
    searchView = new MySearchView(getSherlockActivity()); 
    searchView.setOnQueryTextListener(searchQueryListener); 
    searchView.setIconifiedByDefault(true); 
    searchAction.setActionView(searchView); 
} 

E ultimo l'ascoltatore:

private OnQueryTextListener searchQueryListener = new OnQueryTextListener() { 
    @Override 
    public boolean onQueryTextSubmit(String query) { 
     search(query); 
     return true; 
    } 

    @Override 
    public boolean onQueryTextChange(String newText) { 
     if (searchView.isExpanded() && TextUtils.isEmpty(newText)) { 
      search(""); 
     } 

     return true; 
    } 

    public void search(String query) { 
     // reset loader, swap cursor, etc. 
    } 

}; 

Testato su ABS 4.3.

+2

Sembra che non sia effettivamente necessario un SearchView personalizzato (con isExpanded()). isIconified() farà lo stesso anche se si prende l'inverso di quello. Come in se isIconified() è true e newText è vuoto, l'utente ha appena aperto SearchView, ma non ha cancellato esplicitamente il testo nella visualizzazione di ricerca. Almeno, sembra funzionare per ABS 4.x – kwazi

3

Come altri hanno menzionato questo comportamento è intenzionale. Ho rinunciato a una soluzione per OnQueryChangeListener e ho deciso di aggirare il problema implementando OnEditorActionListener su SearchView EditText, che è possibile ottenere un handle per l'utilizzo di R.id.search_src_text. Finché si setImeOptions di SearchView a EditorInfo.IME_ACTION_SEARCH è possibile gestire un clic sul pulsante di ricerca della tastiera. Vedi this SO answer per maggiori dettagli.

0

Un'altra opzione è quella di attivare manualmente il metodo onQueryTextChange attraverso un TextWatcher:

public class MyActivity extends Activity implements SearchView.OnQueryTextListener, TextWatcher { 

    // Basic onCreate(Bundle) here 

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

     final SearchView searchView = (SearchView) menu.findItem(R.id.action_search).getActionView(); 
     final SearchManager manager = (SearchManager) getSystemService(SEARCH_SERVICE); 
     searchView.setSearchableInfo(manager.getSearchableInfo(getComponentName())); 
     searchView.setOnQueryTextListener(this); 

     final int resource_edit_text = searchView.getContext().getResources().getIdentifier("android:id/search_src_text", null, null); 
     ((EditText) searchView.findViewById(resource_edit_text)).addTextChangedListener(this); 

     return super.onCreateOptionsMenu(menu); 
    } 

    // Implementation of TextWatcher, used to have a proper onQueryTextChange (it doesn't update when the last character is removed) 
    @Override 
    public void beforeTextChanged (final CharSequence charSequence, final int start, final int count, final int after) {} 

    @Override 
    public void onTextChanged (final CharSequence charSequence, final int start, final int before, final int after) {} 

    @Override 
    public void afterTextChanged (final Editable editable) { 
     if (editable.length() == 0) 
      onQueryTextChange(editable.toString()); 
    } 

    // Implementation of OnQueryTextChangeListener 

    @Override 
    public boolean onQueryTextChange (final String query) { 
     // do stuff 
     return false; 
    } 

    @Override 
    public boolean onQueryTextSubmit (final String query) { 
     // do stuff 
     return false; 
    } 
} 

Tutto questo va con tutti i file XML predefiniti che sono state date qui, che non è il punto di questa risposta.Questa è una soluzione che scelgo di utilizzare, sentiti libero di usare gli altri

+0

All'interno di 'TextWatcher.afterTextChanged()' callback, if-condition non dovrebbe essere 'editable.length() == 0'. Dovrebbe essere 'modificabile.length()> 0 '. Grazie per la tua soluzione, mi aiuta a lavorare su Api-8. – johnkarka

+0

Se si utilizza il supporto-v7 per ActionBarActivity, aggiungere un'altra riga per trovare 'if (edit_text == null) edit_text = (EditText) searchView.findViewById (android.support.v7.appcompat.R.id.search_src_text);' – johnkarka

8

Ho avuto lo stesso problema con SearchView. Mia soluzione che consiste styling SearchView come mostrato nella guida http://novoda.com/blog/styling-the-actionbar-searchview/ e modificando OnEditorActionListener per EditText (How do I trigger an action when the user has hit enter?) che fa parte del SearchView era questo:

final SearchView searchView = (SearchView)findViewById(R.id.search); 
int searchPlateId = searchView.getContext().getResources().getIdentifier("android:id/search_src_text", null, null); 
EditText searchPlate = (EditText) searchView.findViewById(searchPlateId); 
searchPlate.setOnEditorActionListener(new TextView.OnEditorActionListener() { 
    @Override 
    public boolean onEditorAction(TextView v, int actionId, KeyEvent event) { 

     if (actionId == EditorInfo.IME_ACTION_SEARCH) { 
      //Do something 
     } 
     return false; 

    }); 
+4

se si utilizza v7 searchView, quindi searchPlace id è semplicemente 'R.id.search_src_text', quindi' EditText searchPlate = (EditText) searchView.findViewById (R.id.search_src_text) ' – CQM

0

riesco a farlo semplicemente implementando il setOnQueryTextListener in questo modo :

SearchView searchView = (SearchView) menu.findItem(R.id.searchProductView).getActionView(); 
    searchView.setOnQueryTextListener(new SearchView.OnQueryTextListener() { 
     @Override 
     public boolean onQueryTextSubmit(String query) { 
      return false; 
     } 

     @Override 
     public boolean onQueryTextChange(String newText) { 
      if (TextUtils.isEmpty(newText)) { 
       loadLocalData(newText); 
      } 
      return true; 
     } 
    }); 

Dove il mio metodo è loadLocalData

//query my DB 
products = ProductDAO.findByIdList(idList); 
LinearLayoutManager layoutManager = new LinearLayoutManager(this); 
listView.setLayoutManager(layoutManager); 
listView.setAdapter(<YOURADAPTER>) 

Questa soluzione si dirada la tua richiesta anche se cancelli il testo con il tasto "X"

8

ive un lavoro più semplice: usa onQueryTextChange, ma esegue il rendering solo se vuoto.

searchView.setOnQueryTextListener(new SearchView.OnQueryTextListener() { 
      @Override 
      public boolean onQueryTextSubmit(String query) { 
        renderList(true); 
        return false; 
      } 

      @Override 
      public boolean onQueryTextChange(String newText) { 
        if (searchView.getQuery().length() == 0) { 
          renderList(true); 
        } 
        return false; 
      } 
    }); 
+0

Esattamente il modo più semplice! Funziona bene per me –

+0

Molto utile !! Grazie. – Beraki

0

Si tratta di un hack molto sporco, ma funziona correttamente come previsto, consentendo l'azione presentare anche quando non c'è testo immesso (o inserito poi modificato) nella SearchView.

Risponde in modo riflessivo al listener di azioni dell'editor TextView interno, lo avvolge in un listener personalizzato dove delega la chiamata al gestore e infine lo imposta come listener di azioni di TextView interno.

Class klass = searchView.getClass(); 
    try { 
     Field currentListenerField = klass.getDeclaredField("mOnEditorActionListener"); 
     currentListenerField.setAccessible(true); 
     TextView.OnEditorActionListener previousListener = (TextView.OnEditorActionListener) currentListenerField.get(searchView); 
     TextView.OnEditorActionListener newListener = new TextView.OnEditorActionListener() { 
      @Override 
      public boolean onEditorAction(TextView v, int actionId, KeyEvent event) { 
       if (v.getText().length() == 0) 
        handleQuery(""); 
       return previousListener.onEditorAction(v, actionId, event); 
      } 
     }; 
     Field innerTextViewField = klass.getDeclaredField("mSearchSrcTextView"); 
     innerTextViewField.setAccessible(true); 
     SearchView.SearchAutoComplete innerTextView = (SearchView.SearchAutoComplete) innerTextViewField.get(searchView); 
     innerTextView.setOnEditorActionListener(newListener); 
    } catch (Exception e) { 
     throw new IllegalStateException(e); 
    } 
0

Nel mio caso ho voluto solo per consentire all'utente di cancellare il suo interrogazione come è stato utilizzato come parola chiave nella ricerca di API, così l'idea più semplice era:

searchView.setOnSearchClickListener(new View.OnClickListener() { 
     @Override 
     public void onClick(View v) { 
      userQuery = ""; 
     } 
    }); 

dove UserQuery è la mia variabile utilizzata per ricerca ecc.

Spero che aiuti qualcuno :)

Problemi correlati