SearchView OnCloseListener nie działa

101

Próbuję dodać obsługę SearchViewpaska ActionBar systemu Android 3.0+, ale nie mogę go uruchomić OnCloseListener.

Oto mój kod:

@Override
public boolean onCreateOptionsMenu(Menu menu) {
    getMenuInflater().inflate(R.menu.menu, menu);
    searchView = (SearchView) menu.findItem(R.id.search_textbox).getActionView();
    searchView.setOnQueryTextListener(new OnQueryTextListener() {
        @Override
        public boolean onQueryTextChange(String newText) {
            searchLibrary(newText);
            return false;
        }
        @Override
        public boolean onQueryTextSubmit(String query) { return false; }
    });
    searchView.setOnCloseListener(new OnCloseListener() {
        @Override
        public boolean onClose() {
            System.out.println("Testing. 1, 2, 3...");
            return false;
        }
    });
    return true;
}

Wyszukiwanie działa świetnie i wszystko działa, z wyjątkiem OnCloseListener. Nic nie jest drukowane do Logcat. Oto Logcat, kiedy naciskam przycisk „Zamknij”:

02-17 13:01:52.914: I/TextType(446): TextType = 0x0
02-17 13:01:57.344: I/TextType(446): TextType = 0x0
02-17 13:02:02.944: I/TextType(446): TextType = 0x0

Przejrzałem dokumentację i próbki, ale wydawało się, że nic tego nie zmienia. Używam go na Asus Transformer Prime i Galaxy Nexus, oba na Ice Cream Sandwich. Jakieś pomysły?

Aktualizacja:

Tak - System.out.println() ma pracę. Oto dowód:

   @Override
 public boolean onQueryTextChange(String newText) {
    System.out.println(newText + "hello");
    searchLibrary(newText);
    return false;
 }

Wyniki w tym Logcat:

02-17 13:04:20.094: I/System.out(21152): hello
02-17 13:04:24.914: I/System.out(21152): thello
02-17 13:04:25.394: I/System.out(21152): tehello
02-17 13:04:25.784: I/System.out(21152): teshello
02-17 13:04:26.064: I/System.out(21152): testhello
Michell Bak
źródło
Hmm, działa OK dla mnie z Androidem 3.2, ale NIE dla 4.0+
PJL
10
Podniesiony błąd, 25758
PJL
3
Cieszę się, że nie tylko ja mam ten problem. Czy ktoś ma jakieś inne hacki niż ten poniżej?
bencallis
2
Nauczyłem się dwóch rzeczy, jeśli showAsActionjest ustawione na always. Pole wyszukiwania ma własny przycisk zamykania , ale jeśli jest ustawione ifRoom | collapseActionView, rozwija się na pasku akcji.
Beraki,

Odpowiedzi:

153

Ja też spotykam się z tym problemem i nie mam innego wyjścia jak zrezygnować z „oncloselistener”. Zamiast tego możesz pobrać swoje menuItem setOnActionExpandListener. Następnie zastąp metody bezimplents.

@Override
public boolean onMenuItemActionExpand(MenuItem item) {
    // TODO Auto-generated method stub
    Log.d("*******","onMenuItemActionExpand");
    return true;
}

@Override
public boolean onMenuItemActionCollapse(MenuItem item) {
    //do what you want to when close the sesarchview
    //remember to return true;
    Log.d("*******","onMenuItemActionCollapse");
    return true;
}
niki huang
źródło
Myślę, że mówimy tylko o widoku SearchView ActionBar, który jest tylko plastrem miodu +
NKijak
nie przejmuj się używaniem onCloseListener, po prostu użyj tego z elementem menu.
Robert
12
Myślę, że możesz użyć MenuItemCompat.OnActionExpandListener na wcześniejszych poziomach API: developer.android.com/reference/android/support/v4/view/ ...
Ripityom
2
Pełna odpowiedź:if (Build.VERSION.SdkInt > BuildVersionCodes.NMr1) item.SetOnActionExpandListener(this); else MenuItemCompat.SetOnActionExpandListener(item, this);
FindOutIslamNow
61

W przypadku interfejsu API systemu Android 14+ (ICS i nowszych) użyj tego kodu:

// When using the support library, the setOnActionExpandListener() method is
// static and accepts the MenuItem object as an argument
MenuItemCompat.setOnActionExpandListener(menuItem, new OnActionExpandListener() {
    @Override
    public boolean onMenuItemActionCollapse(MenuItem item) {
        // Do something when collapsed
        return true;  // Return true to collapse action view
    }

    @Override
    public boolean onMenuItemActionExpand(MenuItem item) {
        // Do something when expanded
        return true;  // Return true to expand action view
    }
});

Więcej informacji: http://developer.android.com/guide/topics/ui/actionbar.html#ActionView

Ref: onActionCollapse / onActionExpand

łomża
źródło
31

W przypadku tego problemu wymyśliłem coś takiego,

private SearchView mSearchView;

@TargetApi(14)
@Override
public boolean onCreateOptionsMenu(Menu menu)
{

    MenuInflater inflater = getMenuInflater();
    inflater.inflate(R.menu.conversation_index_activity_menu, menu);

    mSearchView = (SearchView) menu.findItem(R.id.itemSearch).getActionView();

    MenuItem menuItem = menu.findItem(R.id.itemSearch);

    int currentapiVersion = android.os.Build.VERSION.SDK_INT;
    if (currentapiVersion >= android.os.Build.VERSION_CODES.ICE_CREAM_SANDWICH)
    {
        menuItem.setOnActionExpandListener(new OnActionExpandListener()
        {

            @Override
            public boolean onMenuItemActionCollapse(MenuItem item)
            {
                // Do something when collapsed
                Log.i(TAG, "onMenuItemActionCollapse " + item.getItemId());
                return true; // Return true to collapse action view
            }

            @Override
            public boolean onMenuItemActionExpand(MenuItem item)
            {
                // TODO Auto-generated method stub
                Log.i(TAG, "onMenuItemActionExpand " + item.getItemId());
                return true;
            }
        });
    } else
    {
        // do something for phones running an SDK before froyo
        mSearchView.setOnCloseListener(new OnCloseListener()
        {

            @Override
            public boolean onClose()
            {
                Log.i(TAG, "mSearchView on close ");
                // TODO Auto-generated method stub
                return false;
            }
        });
    }


    return super.onCreateOptionsMenu(menu);

}
Ben Benson
źródło
1
Co się stanie, jeśli zawsze rozszerzałeś za pomocą setIconofiedByDefault (false)? To nie działa ... :(
Joan Casadellà
19

Napotkałem ten sam problem na Androidzie 4.1.1. Wygląda na to, że to znany błąd: https://code.google.com/p/android/issues/detail?id=25758

W każdym razie jako obejście zastosowałem nasłuchiwanie zmian stanu (gdy SearchView jest odłączony od paska akcji, jest również oczywiście zamknięty).

view.addOnAttachStateChangeListener(new OnAttachStateChangeListener() {

    @Override
    public void onViewDetachedFromWindow(View arg0) {
        // search was detached/closed
    }

    @Override
    public void onViewAttachedToWindow(View arg0) {
        // search was opened
    }
});

Powyższy kod działał dobrze w moim przypadku.


Tę samą odpowiedź zamieszczam tutaj: https://stackoverflow.com/a/24573266/2162924

Dario
źródło
Tak, ten błąd został utworzony zaraz po wysłaniu tego pytania. Zobacz komentarze do pierwotnego pytania.
Michell Bak,
O ok, zobacz teraz. Ale w każdym razie może to obejście z odbiornikiem zmiany stanu może być przydatne również dla innych.
Dario,
Rozczarowujące, że OnCloseListener nie działa tak, jak myślisz, jest to w rzeczywistości ładne, czyste rozwiązanie. Sława!
welshk91
10

Skończyło się na tym, że użyłem trochę hacka, który działa dobrze w moim celu - nie jestem pewien, czy zadziała we wszystkich celach. W każdym razie sprawdzam, czy zapytanie wyszukiwania jest puste. To naprawdę nie jest związany z SearchView„s OnCloseListenerchociaż - to nadal nie działa!

searchView.setOnQueryTextListener(new OnQueryTextListener() {
            @Override
            public boolean onQueryTextChange(String newText) {
                if (newText.length() > 0) {
                    // Search
                } else {
                    // Do something when there's no input
                }
                return false;
            }
            @Override
            public boolean onQueryTextSubmit(String query) { return false; }
        });
Michell Bak
źródło
8

Cóż, to rozwiązało mój problem:

Element menu z showAsAction="always"

<item
    android:id="@+id/action_search"
    android:icon="@drawable/ic_action_search"
    android:title="Search"
    app:actionViewClass="android.support.v7.widget.SearchView"
    app:showAsAction="always"/>

i w działalności

searchView.setOnCloseListener(new OnCloseListener() {

        @Override
        public boolean onClose() {

            Log.i("SearchView:", "onClose");
            searchView.onActionViewCollapsed();
            return false;
        }
    });
Sushant
źródło
1
Ustawienie alwayswartości showAsActionatrybutu rozwiązuje problem. Ważną rzeczą jest to, że gdy alwayswartość jest is notobecna w showAsAction, rozwinięty SearchViewprzedstawia przycisk zamykania (ikona krzyżyka) tylko wtedy, gdy zapytanie w SearchViewnie jest ciągiem niezerowym. SearchView.onCloseClickedŻe uchwyty blisko WYDARZENIA przycisk mówi, że wywołania zwrotnego OnCloseListenernazywa się tylko wtedy, gdy kwerenda jest pusta, jeśli nie - to zdaje się pierwsza - ale potem, po bliskich zapytania rozliczeń przycisku znika i jesteśmy w stanie dostarczyć onClosewywołania zwrotnegoOnCloseListener
bpawlowski
1
Wskazówka: ta metoda jest wywoływana, gdy użytkownik zamyka widok wyszukiwania (dość oczywiste, ale zajęło mi to kilka razy). Pierwszy raz, gdy użytkownik kliknie X, usuwa tekst, a ja nie otrzymałem tej aktualizacji, po drugim kliknięciu X zamyka SearchView i wywoływane jest onClose. Mam nadzieję, że to pomoże!
Federico Alvarez
4

Aby OnCloseListenerdziałało, upewnij się, że showAsActionjest ustawione na alwaysw pozycji menu wyszukiwania.

<menu xmlns:android="http://schemas.android.com/apk/res/android"
      xmlns:app="http://schemas.android.com/apk/res-auto"
      xmlns:tools="http://schemas.android.com/tools"
      tools:context=".SearchActivity">

    <item
        android:id="@+id/search"
        android:title="@string/search"
        android:icon="@drawable/ic_search_toolbar"
        app:showAsAction="always"
        app:actionViewClass="android.support.v7.widget.SearchView"/>
</menu>
Julio Betta
źródło
2

Napotkałem ten sam problem z onCloseListener nie wywołującym SearchView. Zrozum z problemu błędu zgłoszonego w 25758 i niektórych postów, które przeczytałem, aby wywołać onCloseListener, musisz ustawić:

searchView.setIconifiedByDefault(true);

Ale w moim przypadku chciałem, aby widok wyszukiwania był otwarty i nie był wyświetlany przez cały czas. Udaje mi się to rozwiązać, dodając jeszcze jedną linię poniżej:

@Override
public boolean onCreateOptionsMenu(Menu menu) {
    MenuInflater inflater = getMenuInflater();
    inflater.inflate(R.menu.search_bar, menu);
    SearchManager searchManager = (SearchManager) getSystemService(Context.SEARCH_SERVICE);
    searchView = (SearchView) menu.findItem(R.id.search).getActionView();
    searchView.setSearchableInfo(searchManager.getSearchableInfo(getComponentName()));
    searchView.setOnQueryTextListener(queryTextListener);
    searchView.setIconifiedByDefault(true);
    searchView.setIconified(false);
    return true;
}

SearchView.setIconified (false) spowoduje otwarcie searchView, pomimo ustawienia wartości domyślnej iconified na true w poprzednim wierszu. W ten sposób udało mi się mieć zarówno SearchView, który otwiera się cały czas, jak i wywoływał onCloseListener.

gkl
źródło
2

Utwórz pozycję menu z app:showAsActionustawieniem na zawsze.

<item   
 android:id="@+id/action_search"  
 android:title="..."  
 android:icon="..."  
 app:actionViewClass="android.support.v7.widget.SearchView"  
 app:showAsAction="always"/>

Tworząc SearchVieww onCreateOptionsMenumetodzie zrób coś podobnego

inflater.inflate(R.menu.menu_search, menu);
final MenuItem item = menu.findItem(R.id.action_search);
final SearchView search = (SearchView) item.getActionView();
search.setQueryHint(getString(R.string.search_brand_item));
search.setOnQueryTextListener(new SearchView.OnQueryTextListener() {
  @Override
  public boolean onQueryTextSubmit(String query) {
    // add your code
    return false;
  }

  @Override
  public boolean onQueryTextChange(String newText) {
    // add your code 
    return false;
  }
});
search.setOnCloseListener(new SearchView.OnCloseListener() {
  @Override
  public boolean onClose() {
    // add your code here
    return false;
  }
});
search.setIconifiedByDefault(true); // make sure to set this to true

Należy search.setIconifiedByDefault(true)ustawić, aby truewywołać onClose()metodę na SearchView.OnCloseListener()utworzonym powyżej.

Ray Hunter
źródło
1

W przypadku MenuItemCompatproblemu dodałem ViewTreeObserver do śledzenia stanu widoczności. Możesz sprawdzić moją odpowiedź tutaj: https://stackoverflow.com/a/28762632/1633609

Sir Nikolay Cesar Pierwszy
źródło
0

Powodem, dla którego OnCloseListenernie jest wywoływany, jest błąd w kodzie Androida - słuchacz jest wywoływany tylko wtedy, gdy również dzwonisz setIconifiedByDefault(true).

Joseph Earl
źródło
7
Właśnie próbowałem dodać setIconifiedByDefault (true), ale nie jest to wywoływane
Giuseppe
@Joseph Earl: Mam podobny problem tutaj: stackoverflow.com/questions/43702055/… . Jakieś przemyślenia lub pomysły, jak to naprawić?
AJW
0

wydaje się już stary wątek, ale myślałem, że mam ten sam problem z API 18 na początku. Po przeszukaniu go i znalezieniu tego wątku, kolejna godzina przeczytania wypróbowanego i błędnego javadoc dla czegoś, czego nie udaję w pełni rozumiem w javadoc, następująca praca dla mnie teraz:

searchView.setIconifiedByDefault(true);

   // OnQueryTextListener
   @Override
   public boolean onQueryTextSubmit(String query) {
      Log.d(tag, "onQueryTextSubmit: " + query);
      return true;
   }

   @Override
   public boolean onQueryTextChange(String query) {
      Log.d(tag, "onQueryTextChange: " + query);
      return true;
   }

   // OnCloseListener
   @Override
   public boolean onClose() {
      Log.w(tag, "onClose: ");
      return false;
   }

Bawiłem się trochę z prawdą / fałszem, to w jakiś sposób robi różnicę i teraz działa. Miejmy nadzieję, że może to komuś zaoszczędzić czas.

Sean
źródło
0

To obejście, ale zadziałało dla mnie

  searchView.setOnQueryTextListener(new android.widget.SearchView.OnQueryTextListener() {

                String lastText;

                @Override
                public boolean onQueryTextChange(final String newText) {
                    if (lastText != null && lastText.length() > 1 && newText.isEmpty()) {
                        // close ctn clicked

                        return true;
                    }
}
Nativ
źródło
0
    searchView.setOnCloseListener {
        d("click", "close clicked")
        return@setOnCloseListener false
    }

jeśli klikniesz zamknij searchView ->

D / kliknięcie: zamknięcie kliknięto

Oleksandr Yahnenko
źródło
1
Odpowiedzi zawierające fragment kodu i tajemnicze słowa nie są szczególnie jasne. Po prostu użyj języka naturalnego, aby opisać, dlaczego uważasz, że to rozwiązuje problem, a następnie pokaż wdrożenie rozwiązania.
0

Napotkałem ten problem, próbując wykryć wyświetlanie / odrzucanie SearchView. Skończyło się na tym, że użyłem innego słuchacza i działało to, czego potrzebowałem:

        setOnQueryTextFocusChangeListener { _, hasFocus ->
            if (hasFocus) {
                // SearchView is being shown
            } else {
                // SearchView was dismissed
            }
        }
Psylocke
źródło
0

Użyłem przycisku zamykania SearchView i ustawiłem na nim setOnClickListener

searchView.findViewById<ImageView>(R.id.search_close_btn).setOnClickListener {
    searchView.setQuery("", false)
    searchView.clearFocus()
}
Alexander
źródło
-2

W systemie Android nie ma konsoli do logowania. Zamiast tego użyj struktury rejestrowania systemu Android:

Log.d("Test Tag", "Testing.  1, 2, 3...");

Zobacz także to pytanie: Dlaczego „System.out.println” nie działa w systemie Android?

Chris Knight
źródło
2
Nieprawda, działa dobrze. Zobacz moje zaktualizowane pytanie - dodałem linię w metodzie onQueryTextChange, aby to udowodnić. Próbowałem także dodać Log.d (), ale to też nic nie wyświetlało.
Michell Bak
Och, moja wina! Wygląda na to, że gdzieś po drodze zdecydowali się wyprowadzić System.out.println do Log.i. Powodzenia
Chris Knight
-3

Istnieją dwa typowe wzorce dla SearchView.setOnCloseListener(). To naprawdę dotyczy wszystkich słuchaczy, ale odnoszę się konkretnie do twojego pytania. Pierwszy sposób polega na utworzeniu funkcji nasłuchującej i dołączeniu jej do zmiennej składowej, a drugi polega na tym, aby klasa implementowała interfejs i by funkcja obsługi była funkcją składową.

Tworzenie obiektu detektora wygląda następująco:

private SearchView mSearchView;
private final SearchView.OnCloseListener mOnCloseListener = 
    new SearchView.OnCloseListener() {
        public boolean onClose() {
            doStuff();
            return myBooleanResult;
        }
    };
mSearchView.setOnCloseListener(mOnCloseListener);

Implementacja detektora na poziomie klasy wygląda następująco:

public class MyClass implements OnCloseListener {
    private SearchView mSearchView;

    public MyClass(...) {
        mSearchView.setOnCloseListener(this);
    }

    @Override
    public boolean onClose() {
        doStuff();
        return false;
    }
}

Nie widziałem żadnych przykładów, które tworzyłyby OnCloseListenerad hoc, jak to zrobiłeś w swoim pytaniu.

iskrzący
źródło
Hej Sparky, dziękuję za komentarz. Naprawdę nie rozumiem, jak to powinno cokolwiek zmienić. Zagnieżdżony odbiornik jest również prawidłowym sposobem tworzenia go i działa na Honeycomb, jak widać na podstawie komentarzy tutaj. Nie miałem żadnych problemów z zagnieżdżonymi słuchaczami w ICS poza tym - co znowu działa na Honeycomb.
Michell Bak
Przez zagnieżdżonych słuchaczy mam na myśli anonimowe klasy wewnętrzne.
Michell Bak
Zgadzam się, że to nie ma znaczenia. Komentuję tylko to, co jest obecne w bazie kodu. Poszukam i zobaczę, czy może warunki, w których onClose zostały przedefiniowane.
Sparky
Nie jestem pewien, czy rozumiesz Javę - nazywa się to anonimową klasą wewnętrzną.
Joseph Earl