web-dev-qa-db-ger.com

Android SearchView.OnQueryTextListener OnQueryTextSubmit wird bei leerer Abfragezeichenfolge nicht ausgelöst

Ich verwende Android 4.1.2. Ich habe ein SearchView-Widget für eine ActionBar. Die Dokumentation zu SearchView.OnQueryTextListener von der Android-Entwicklerseite gibt an, dass onQueryTextSubmit ausgelöst wird, wenn "beim Abfragen des Benutzers die Abfrage erfolgt. Dies kann durch einen Tastendruck auf der Tastatur oder durch das Drücken einer Übermittlungstaste verursacht werden."

Dies ist nicht der Fall, wenn die Suchabfrage leer ist. Ich brauche dies, um eine leere Abfrage auszulösen, um den Suchfilter einer ListView zu löschen. Ist das ein Fehler oder mache ich etwas falsch?

21
tborja

Es ist kein Fehler, der source code prüft absichtlich auf null und leere Werte:

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

Sie sollten jedoch in der Lage sein, den OnQueryTextChange-Callback zu verwenden, um die Filtermöglichkeiten Ihrer ListView zu löschen, wenn der Benutzer die Suche EditText löscht.

13
Sam

eine einfachere Umgehung ist folgende: Verwenden Sie onQueryTextChange, aber nur wenn es leer ist.

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;
            }
    });
11
James Tan

Ich hatte das gleiche Problem und endete mit der folgenden Lösung: custom SearchView + OnQueryTextListener.onQueryTextChange

Benutzerdefinierte Suchansicht:

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

Aktion anlegen und Rückruf setzen: 

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

Und zuletzt der Hörer:

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

};

Getestet an ABS 4.3.

10
Piotr Bazan

Ich hatte das gleiche Problem mit SearchView. Meine Lösung besteht darin, SearchView wie im Guide http://novoda.com/blog/styling-the-actionbar-searchview/ - zu stylen und OnEditorActionListener für EditText ( Wie stelle ich beim Benutzer eine Aktion aus hat die Eingabetaste gedrückt? ) Welcher Teil der SearchView war dies:

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;

    });
9
Jan Hofman

Wie andere bereits erwähnt haben, ist dieses Verhalten beabsichtigt. Ich gab eine Lösung für OnQueryChangeListener auf und entschied mich für eine Problemumgehung, indem ich OnEditorActionListener in der EditText von SearchView implementierte, die Sie mit R.id.search_src_text behandeln können. Solange Sie setImeOptions von SearchView EditorInfo.IME_ACTION_SEARCH sind, können Sie mit einem Klick auf die Tastatur-Suchschaltfläche klicken. Siehe diese SO Antwort für weitere Details.

3
theblang

Ich hatte das gleiche Problem, da leere Abfragen nicht unterstützt werden, musste ich ActionBarSherlock herunterladen und dann die onSubmitQuery () - Methode ändern.

So sieht mein onSubmitQuery () jetzt aus

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

Hoffe das hilft.

1
M3rd0n

Ich kann das einfach erreichen, indem ich setOnQueryTextListener auf folgende Weise implementiert:

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

Wo sich meine loadLocalData-Methode befindet

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

Diese Lösung löscht Ihre Abfrage, selbst wenn Sie den Text mit der Schaltfläche "X" löschen

0
Giuseppe Sarno

Es ist ein alter Thread, aber ich habe eine andere Lösung gefunden (Kotlin-Code, funktioniert aber auch in Java):

override fun onQueryTextChange(newText: String?): Boolean {
            if(newText == null || newText.isEmpty())
                searchView.setQuery("\u00A0", false)
            return true
        }

\u00A0 ist ein Zeichen, das wie ein Leerzeichen aussieht, aber vom Code her nicht. Mit anderen Worten ist SearchView nicht leer. Eine leere Zeichenfolge oder " " würde nicht funktionieren, da die Basisanwendung von SearchView den Befehl trim verwendet. Soweit ich weiß, können Benutzer \u00A0-Zeichen nicht eingeben.

Dann müssen Sie getQuery in Ihrer benutzerdefinierten Suchansicht mit return super.getQuery.replace("\u00A0", "") überschreiben

0
Miku

Sie können dieses Verhalten nicht überschreiben. Eine Problemumgehung kann darin bestehen, den Filter zu löschen, wenn ein Benutzer die Suchansicht beendet.

Sie können den OnCloseListener dafür verwenden. Dies kann jedoch auch zu Problemen führen, abhängig von dem Mindest-API-Level, für den Sie entwickeln.

0
GeeF

In meinem Fall wollte ich dem Benutzer lediglich ermöglichen, seine Abfrage zu löschen, da sie bei der API-Suche als Schlüsselwort verwendet wurde.

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

wobei userQuery meine Variable ist, die für die Suche usw. verwendet wird.

Hoffe es hilft jemandem :)

0
Maik Martinez

Dies ist ein sehr schmutziger Hack , er funktioniert jedoch wie erwartet und aktiviert die Übergabeaktion, auch wenn in SearchView kein Text eingegeben (oder eingegeben und dann bearbeitet) wird. 

Er erhält nachdenklich Zugriff auf den Aktions-Listener des inneren TextView-Editors, verpackt ihn in einen benutzerdefinierten Listener, wo er den Aufruf an den Handler delegiert, und legt ihn schließlich als Aktionslistener für die innere TextView fest.

    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
samvel1024

Eine andere Option ist das manuelle Auslösen der onQueryTextChange-Methode über einen 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;
    }
}

Dies alles gilt für alle hier aufgegebenen Standard-XML-Dateien, darum geht es nicht in dieser Antwort. Dies ist eine Problemumgehung, für die ich mich entschieden habe, andere zu verwenden

0
engineercoding