Automatyczne zwijanie ActionBar SearchView po zamknięciu miękkiej klawiatury


79

Obecnie używam elementu menu ActionBar, aby wyświetlić widok wyszukiwania na pasku akcji. Gdy pozycja menu wyszukiwania jest rozszerzona, wyświetlana jest klawiatura programowa, której chcę. Teraz, gdy użytkownik naciśnie przycisk Wstecz, aby zamknąć klawiaturę programową, chciałbym również zwinąć widok wyszukiwania na pasku akcji.

Próbowałem zaimplementować następujące odbiorniki OnKeyListener i OnFocusChangeListener w MenuItem i ActionView. Próbowałem również użyć OnBackPressed () w działaniu. Żadne z powyższych nie wykrywa, kiedy przycisk Wstecz jest używany do zamykania klawiatury programowej.

Jakieś pomysły?

Zaimplementowałem OnActionExpandListener, aby wiedzieć, kiedy SearchView jest widoczny.


Oto bardzo popularna odpowiedź stackoverflow.com/questions/1109022/ ...
jmishra

2
to mu nie pomoże, musi przechwycić klawisz wstecz z klawiatury
dor506

@acrespo Jaka odpowiedź? Komentujesz pytanie ...
Niesamowity styczeń

Odpowiedzi:


100

Rozszerzę odpowiedź @ user1258568 dla leniwych. To zadziałało dla mnie. Zauważ, że czyści zapytanie, gdy utraci się fokus.

final MenuItem searchMenuItem = optionsMenu.findItem(R.id.search);
final SearchView searchView = (SearchView) searchMenuItem.getActionView();

searchView.setOnQueryTextFocusChangeListener(new View.OnFocusChangeListener() {
    @Override
    public void onFocusChange(View view, boolean queryTextFocused) {
        if(!queryTextFocused) {
            searchMenuItem.collapseActionView();
            searchView.setQuery("", false);
        }
    }
});

1
Działa świetnie. Jeśli dodasz searchView w kodzie, może być konieczne użycie menu.getItem(yourSearchViewItemPosition)zamiast tego.
GeeF,

@AlexBonel Jak to? Wiem, że S3 i S4 mają idiotyczne przyciski sprzętowe, ale nie jestem pewien, jak to wpłynie na ten fragment. Być może dzieje się tak dlatego, że menu ActionBar jest ukryte, a funkcja searchMenuItem działa inaczej. Mam pod ręką S4, muszę to przetestować.
Jon Willis

@JonWillis Jeśli nie jest to dla Ciebie trudne, czy mógłbyś podzielić się swoimi doświadczeniami z takiego zachowania na S4?
Alex Bonel,

4
Fajnie, po godzinach poszukiwań i wdrożeń, aby spróbować to zrobić, znalazłem odpowiedź :) ... Pierwszą rzeczą, o której pomyślałem, było użycie słuchacza z fokusem, ale setOnFocusChangeListener()zamiast tego użyłem setOnQueryTextFocusChangeListener(). Z twoją metodą wszystko działa dobrze. Dziękuję Ci.
Ionut Negru

2
@IonutNegru nie ma za co! czasami trzeba pokochać Android SDK. Chcę zobaczyć, jak przepisują to w rozsądny, nowoczesny sposób i porzucają starsze wsparcie, ale to się nigdy nie stanie.
Jon Willis

37

Znalazłem lepsze rozwiązanie.

searchView.setOnQueryTextFocusChangeListener(). 

Jest OnQueryTextFocusChangeListenerwywoływana, gdy klawiatura jest wyświetlana lub ukryta. Jest wywoływana jako pierwsza, gdy klawiatura jest wyświetlana, a widok wyszukiwania będzie miał fokus. Jest wywoływany ponownie, gdy keyboardjest ukryty, a widok wyszukiwania straci fokus, może close search viewnastępnie użyć

menuItem.collapseActionView().

5
To jest mylące. OnQueryTextFocusChangeListenerNie uzyskać wywołana, gdy klawiatura jest wyświetlana lub ukryte. Jest wywoływany tylko wtedy, gdy searchViewjest ostry i / lub nieostry. Tak więc, gdy SearchViewfokus jest pierwszy raz, OnQueryTextFocusChangeListenerwywoływany jest element i wyświetlana jest również klawiatura. Teraz, jeśli przycisk Wstecz zostanie naciśnięty, klawiatura zostanie ukryta, ale OnQueryTextFocusChangeListenernie zostanie wywołana. Po ponownym naciśnięciu przycisku Wstecz przycisk searchViewzwija się i OnQueryTextFocusChangeListenerjest wywoływany.
faizal

11

Just Override onBackPressed w ten sposób:

@Override
    public void onBackPressed() {
        if (searchView.isShown()){
            searchView.onActionViewCollapsed();  //collapse your ActionView
            searchView.setQuery("",false);       //clears your query without submit
            isClosed = true;                     //needed to handle closed by back
        } else{
            super.onBackPressed();
        }
    }

a twoje onCreateOptionsMenu zwiększyłoby mSearchView w następujący sposób:

@Override
    public boolean onCreateOptionsMenu(Menu menu) {
        super.onCreateOptionsMenu(menu);
        getMenuInflater().inflate(R.menu.menu_search, menu);
        mSearchView = (SearchView) menu.findItem(R.id.menu_action_search).getActionView();
        mSearchView.setOnQueryTextListener(this);
        mSearchView.setOnSearchClickListener(this);
        mSearchView.setOnCloseListener(this);
        isClosed = true;
        return true;
    }

czy masz klasę zaimplementuj następujące w ten sposób:

public class myActivity extends FragmentActivity implements
    SearchView.OnQueryTextListener, View.OnClickListener, SearchView.OnCloseListener {

które będziesz również potrzebować:

@Override
public void onClick(View view) {
    isClosed = false;
}

@Override
public boolean onClose() {
    isClosed = true;
    return false;
}

Będziesz musiał ustawić „mSearchView” i „isClosed” jako obie zmienne globalne dla działania.


3
Myślę, że to nie działa; z mojego doświadczenia wynika, że ​​metoda onBackPressed nie jest wywoływana, jeśli klawiatura jest podniesiona; po prostu odrzuca klawiaturę i trzeba nacisnąć ponownie, aby wywołać tę metodę. To jest na 2.3; nie eksperymentowałem z 3.x i 4.0, ale podejrzewam, że to jest to samo.
Kevlar

@Kevlar Myślę, że możesz mieć rację. Przetestuję to ponownie i upewnię się, że nie ma sposobu. Wygląda na to, że moje rozwiązanie różni się nieco od tego, czego chcą. O ile wiem, nie sądzę, aby można było poradzić sobie z jakimkolwiek plecami, gdy wyświetlana jest miękka klawiatura. Moje rozwiązanie na pewno działa po zamknięciu klawiatury. Będzie testować na różnych SDK.
Codeversed

1
próbowałem zwinąć wyszukiwanie za pomocą: searchMenuItem.collapseActionView (); ale okazało się, że searchView.onActionViewCollapsed (); załatwił mi sprawę - dzięki!
bkurzius

Myślę, że nie powinieneś bezpośrednio wywoływać ... funkcji. Te funkcje nie mogą być wywoływane bezpośrednio z twojego kodu ...
user457015

jak używać collapseActionView () na poziomie API 11.
madan V

3

Odpowiedź Jona Willisa działa świetnie. To ulepszenie jego odpowiedzi.

Najpierw utwórz nową klasę, która implementuje View.OnFocusChangeListener:

public class SearchViewFocusListener implements View.OnFocusChangeListener {

    private final MenuItem mMenuItem;

    public SearchViewFocusListener(MenuItem menuItem) {
        mMenuItem = menuItem;
    }

    @Override
    public void onFocusChange(View v, boolean hasFocus) {
        if (!hasFocus) {
            mMenuItem.collapseActionView();
            if (v instanceof SearchView) {
                ((SearchView) v).setQuery("", false);
            }
        }
    }

}

Następnie ustaw odbiornik na SearchView:

searchView.setOnQueryTextFocusChangeListener(new SearchViewFocusListener(menuItem));

działa ładnie, ale jak wyczyścić fokus z ikony wyszukiwania? FocusChangeListener przechwytuje naciśnięcie przycisku Wstecz na urządzeniu, co zamyka klawiaturę programową i zamyka widok wyszukiwania, a następnie pojawia się ikona wyszukiwania, tak jak bym chciał. Jednak ikona wyszukiwania jest podświetlona (ma fokus) i wolałbym, aby nie była aktywna. Próbowałem wyczyścić na kilka sposobów, ale bez powodzenia. Jakieś pomysły?
AJW

2

Wystarczy umieścić atrybut „collapseActionView” w układzie menu

<menu xmlns:android="http://schemas.android.com/apk/res/android"
      xmlns:app="http://schemas.android.com/apk/res-auto">
    <item
        android:id="@+id/menu_item_search"
        android:title="@string/search"
        android:iconifiedByDefault="true"
        android:icon="@drawable/ic_action_search" 
        app:actionViewClass="android.support.v7.widget.SearchView"
        app:showAsAction="ifRoom|collapseActionView"/> <--this one
</menu>

To da ci funkcjonalność, której szukasz. Nie zapomnij wywołać metody „clearFocus” w SearchView, aby zamknąć klawiaturę po wysłaniu zapytania.


1

To właśnie zrobiłem, aby klawiatura zniknęła. Możesz spróbować sprawdzić, czy to działa dla Ciebie. Ustawiłem jako searchViewniewidoczne, a następnie ponownie widoczne.

    //set query change listener
     searchView.setOnQueryTextListener(new SearchView.OnQueryTextListener(){
        @Override
        public boolean onQueryTextChange(String newText) {
            // TODO Auto-generated method stub
            return false;
        }

        @Override
        public boolean onQueryTextSubmit(String query) {
            /**
             * hides and then unhides search tab to make sure keyboard disappears when query is submitted
             */
                  searchView.setVisibility(View.INVISIBLE);
                  searchView.setVisibility(View.VISIBLE);
            return false;
        }

     });

U mnie też działało, ale musisz dodać getActivity (). SupportInvalidateOptionsMenu (); aby przywrócić pasek akcji
almisoft

1

Jest to osiągalne w następujący sposób:

   private void setupSearchView(Menu menu) {
        final MenuItem searchMenuItem = menu.findItem(R.id.action_search);
        final SearchView searchView = (SearchView) searchMenuItem.getActionView();

        [...]

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

Rozwiązania oparte na setOnQueryTextFocusChangeListener () nie działały u mnie, ponieważ zdarzenie nie zostało uruchomione - searchView nie stracił fokusu po przesłaniu, prawdopodobnie dlatego, że wykonuję wyszukiwanie w tym samym działaniu, które zawiera widok wyszukiwania.

W każdym razie uważam, że użycie OnQueryTextListener jest bardziej poprawne, ponieważ dokładniej opisuje zdarzenie złożenia tekstu.


0
@Override
    public boolean onCreateOptionsMenu(Menu menu) {
        getSupportMenuInflater().inflate(R.menu.home_screen, menu);

        SearchManager searchManager = (SearchManager) getSystemService(Context.SEARCH_SERVICE);
        final MenuItem searchMenuItem = menu.findItem(R.id.menu_search);
        final SearchView searchView = (SearchView) searchMenuItem
                .getActionView();
        searchView.setIconifiedByDefault(false);
        if (searchManager != null && searchView != null) {
            searchView.setSearchableInfo(searchManager
                    .getSearchableInfo(getComponentName()));

            searchView
                    .setOnQueryTextFocusChangeListener(new View.OnFocusChangeListener() {

                        @Override
                        public void onFocusChange(View v, boolean hasFocus) {

                            if (!hasFocus) {
                                if (searchMenuItem != null) {
                                    searchMenuItem.collapseActionView();
                                }// end if
                                if (searchView != null) {
                                    searchView.setQuery("", false);

                                }// end if
                            }// end if

                        }
                    });

            searchView
                    .setOnQueryTextListener(new SearchView.OnQueryTextListener() {

                        @Override
                        public boolean onQueryTextSubmit(String query) {
                            /**
                             * hides and then unhides search tab to make sure
                             * keyboard disappears when query is submitted
                             */
                            if (searchView != null) {
                                searchView.setVisibility(View.INVISIBLE);
                                searchView.setVisibility(View.VISIBLE);

                            }
                            return false;
                        }

                        @Override
                        public boolean onQueryTextChange(String newText) {
                            // TODO Auto-generated method stub
                            return false;
                        }
                    });

        }

        return super.onCreateOptionsMenu(menu);
    }

0

Jeśli chcesz zwinąć klawiaturę, gdy użytkownik kliknie ikonę wyszukiwania na klawiaturze, można to zrobić w prosty sposób

inside onquerytextsubmitted {

searchView.clearfocus()

}


0

Musisz dwukrotnie wywołać setIconified.

Aby faktycznie zwinąć widok wyszukiwania i zamknąć klawiaturę.
Przy pierwszym wywołaniu tekst widoku wyszukiwania jest czyszczony za pomocą klawiatury drugiego połączenia, a widok wyszukiwania zostaje zamknięty.


0

Z jakiegoś powodu menuItem.collapseActionView()nie zadziałało, więc skorzystałemsearchView.setIconified(true) zamiast tego .

Daje to poniższy wynik jako przykład kodu.

final MenuItem searchItem = (MenuItem) menu.findItem(R.id.menu_item_search);
final SearchView searchView = (SearchView) searchItem.getActionView();

searchView.setOnQueryTextFocusChangeListener(new SearchView.OnFocusChangeListener() {
    @Override
    public void onFocusChange(View v, boolean hasFocus) {
        if (!hasFocus) {
            searchView.setIconified(true);
        }
    }
});
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.