OnCloseListener do SearchView não funciona

101

Estou tentando adicionar suporte para o SearchViewno Android 3.0+ ActionBar, mas não consigo fazer o OnCloseListenertrabalho.

Este é o meu código:

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

A pesquisa funciona muito bem e todos estão funcionando, exceto o OnCloseListener. Nada está sendo impresso no Logcat. Este é o Logcat para quando eu pressiono o botão "Fechar":

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

Verifiquei a documentação e as amostras, mas nada parecia mudar isso. Estou executando em um Asus Transformer Prime e um Galaxy Nexus, ambos no Ice Cream Sandwich. Alguma ideia?

Atualizar:

Sim - System.out.println() faz o trabalho. Aqui está a prova:

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

Resultados neste 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
fonte
Hmm, funciona bem para mim com Android 3.2, mas NÃO para 4.0+
PJL
10
Bug gerado
PJL
3
Fico feliz por não ser só eu que estou tendo esse problema. Alguém tem outros hacks além do abaixo?
bencallis,
2
Aprendi duas coisas se showAsActionestiver definido como always. A caixa de pesquisa tem um botão Fechar próprio, mas se estiver definido para ifRoom | collapseActionViewexpandir na barra de ação.
Beraki

Respostas:

153

Eu também encontro esse problema e não tenho escolha a não ser desistir de "oncloselistener". Em vez disso, você pode obter seu menuItem, então setOnActionExpandListener. Em seguida, substitua os métodos não implementados.

@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
fonte
Acredito que estamos falando apenas do SearchView da ActionBar, que é apenas honeycomb +
NKijak
não se preocupe em usar onCloseListener, apenas use este com seu item de menu.
Robert
12
Acho que você pode usar MenuItemCompat.OnActionExpandListener para níveis de API anteriores: developer.android.com/reference/android/support/v4/view/…
Ripityom
2
Resposta completa:if (Build.VERSION.SdkInt > BuildVersionCodes.NMr1) item.SetOnActionExpandListener(this); else MenuItemCompat.SetOnActionExpandListener(item, this);
FindOutIslamNow
61

Para Android API 14+ (ICS e superior), use este código:

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

Para obter mais informações: http://developer.android.com/guide/topics/ui/actionbar.html#ActionView

Ref: onActionCollapse / onActionExpand

Lomza
fonte
31

Para esse problema, pensei em algo assim,

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
fonte
1
O que acontece se você sempre expandiu usando setIconofiedByDefault (false)? Não funciona ... :(
Joan Casadellà
19

Eu tive o mesmo problema no Android 4.1.1. Parece que é um bug conhecido: https://code.google.com/p/android/issues/detail?id=25758

De qualquer forma, como solução alternativa, usei o ouvinte de mudança de estado (quando SearchView é desanexado da barra de ação, ele também é fechado obviamente).

view.addOnAttachStateChangeListener(new OnAttachStateChangeListener() {

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

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

O código acima funcionou bem no meu caso.


Eu posto a mesma resposta aqui: https://stackoverflow.com/a/24573266/2162924

Dario
fonte
Sim, esse bug foi criado logo após eu postar esta pergunta. Veja os comentários da pergunta original.
Michell Bak
Oh ok, veja agora. Mas de qualquer forma, talvez esta solução alternativa com ouvinte de mudança de estado possa ser útil para outros também.
Dario
Embora desapontador que OnCloseListener não funcione como você pensa, esta é realmente uma solução limpa e agradável. Kudos!
welshk91
10

Acabei usando um pequeno hack, que funciona bem para o meu propósito - não tenho certeza se vai funcionar para todos os propósitos. De qualquer forma, estou fazendo uma verificação para ver se a consulta de pesquisa está vazia. Isso não está realmente relacionado ao do SearchView- OnCloseListenermas ainda não funciona!

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

Bem, isso resolveu meu problema:

Item de menu com 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"/>

e em atividade

searchView.setOnCloseListener(new OnCloseListener() {

        @Override
        public boolean onClose() {

            Log.i("SearchView:", "onClose");
            searchView.onActionViewCollapsed();
            return false;
        }
    });
Sushant
fonte
1
Definir o alwaysvalor do showAsActionatributo resolve o problema. O importante é que quando o alwaysvalor está is notpresente em showAsAction, o expandido SearchViewapresenta o botão Fechar (ícone de cruz) apenas se a consulta em SearchViewfor String não nula. O SearchView.onCloseClickedque lida com os eventos do botão Fechar informa esse retorno de chamadaOnCloseListener é chamado apenas se a consulta estiver vazia, se não estiver - é limpo primeiro - mas então, depois de limpar a consulta, o botão Fechar desaparece e não podemos entregar o onCloseretorno de chamada paraOnCloseListener
bpawlowski
1
Só uma dica: este método é chamado quando o usuário fecha a visualização de pesquisa (bastante óbvio, mas demorei algumas vezes para perceber). A primeira vez que o usuário clica no X ele apaga o texto, e não recebi essa atualização, no segundo clique no X ele fecha o SearchView e o onClose é chamado. Espero que ajude!
Federico Alvarez
4

A fim de fazer o OnCloseListener trabalho, certifique-se de que showAsActionestá definido como alwaysno item de menu de pesquisa.

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

Eu encontrei o mesmo problema com onCloseListener não invocar para o SearchView. Com base no problema de bug levantado em 25758 e em algumas postagens que li, para invocar onCloseListener, você precisa definir:

searchView.setIconifiedByDefault(true);

Mas, no meu caso, eu queria ter a visualização de pesquisa aberta e não iconificada o tempo todo. Consigo resolver isso adicionando mais uma linha abaixo:

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

O searchView.setIconified (false) fará com que o searchView seja aberto, apesar de definir o padrão para iconificado como verdadeiro na linha anterior. Dessa forma, consegui ter um SearchView que abre o tempo todo e fazer com que ele invoque onCloseListener.

gkl
fonte
2

Crie o item de menu com o app:showAsActionconjunto para sempre.

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

Ao criar o SearchViewno onCreateOptionsMenumétodo, faça algo semelhante

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

O search.setIconifiedByDefault(true)precisa ser definido como truepara chamar o onClose()método SearchView.OnCloseListener()criado acima.

Ray Hunter
fonte
1

Para MenuItemCompatproblemas, adicionei ViewTreeObserver para rastrear o estado de visibilidade. Você pode verificar minha resposta aqui: https://stackoverflow.com/a/28762632/1633609

Sir NIkolay Cesar The First
fonte
0

O motivo de OnCloseListenernão ser chamado é porque há um bug no código do Android - o listener só é chamado se você também chamar setIconifiedByDefault(true).

Joseph Earl
fonte
7
Acabei de tentar adicionar setIconifiedByDefault (true), mas não é chamado
Giuseppe
@Joseph Earl: Estou tendo um problema semelhante aqui: stackoverflow.com/questions/43702055/… . Alguma ideia ou ideia de como consertar?
AJW
0

já parece um tópico antigo, mas achei que tinha o mesmo problema com a API 18 no começo. Depois de pesquisar no Google, encontrei este tópico, outra hora li o javadoc experimentado e erroneamente por algo que não pretendo entender totalmente no javadoc, o seguinte funciona para mim agora:

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

Joguei um pouco com verdadeiro / falso, isso de alguma forma faz a diferença, e funciona para mim agora. Com sorte, isso poderia economizar o tempo de alguém.

Sean
fonte
0

É uma solução alternativa, mas funcionou para mim

  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
fonte
0
    searchView.setOnCloseListener {
        d("click", "close clicked")
        return@setOnCloseListener false
    }

se você clicar em fechar searchView ->

D / clique: fechar clicado

Oleksandr Yahnenko
fonte
1
Respostas com um blob de código e algumas palavras crípticas não são particularmente claras. Basta usar uma linguagem natural para descrever por que você acha que isso resolve o problema e, em seguida, mostrar a implementação da solução.
0

Eu encontrei esse problema ao tentar detectar a exibição / rejeição do SearchView. Acabei usando um ouvinte diferente e funcionou para o que preciso:

        setOnQueryTextFocusChangeListener { _, hasFocus ->
            if (hasFocus) {
                // SearchView is being shown
            } else {
                // SearchView was dismissed
            }
        }
Psylocke
fonte
0

Usei o botão Fechar SearchView e defini um setOnClickListener nele

searchView.findViewById<ImageView>(R.id.search_close_btn).setOnClickListener {
    searchView.setQuery("", false)
    searchView.clearFocus()
}
Alexandre
fonte
-2

Não há console no Android para fazer login. Em vez disso, use a estrutura de registro do Android:

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

Veja também esta pergunta: Por que "System.out.println" não funciona no Android?

Chris Knight
fonte
2
Não é verdade, funciona muito bem. Por favor, veja minha pergunta atualizada - Eu adicionei uma linha no método onQueryTextChange para provar isso. Também tentei adicionar Log.d (), mas também não exibiu nada.
Michell Bak de
Oh culpa minha! Parece que em algum lugar ao longo do caminho eles decidiram enviar System.out.println para o Log.i. Boa sorte
Chris Knight
-3

Existem dois padrões comuns para SearchView.setOnCloseListener() . Isso é realmente verdade para todos os ouvintes, mas estou abordando sua pergunta especificamente. A primeira maneira é criar uma função de ouvinte e anexá-la a uma variável de membro, e a segunda é fazer a classe implementar a interface e fazer com que o manipulador seja uma função de membro.

A criação de um objeto ouvinte tem a seguinte aparência:

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

A implementação do ouvinte no nível da classe se parece com isto:

public class MyClass implements OnCloseListener {
    private SearchView mSearchView;

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

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

Não vi nenhum exemplo que crie o OnCloseListenerad-hoc, como você fez em sua pergunta.

Sparky
fonte
Ei Sparky, obrigado por comentar sobre isso. Eu realmente não vejo como isso deveria mudar alguma coisa. Um ouvinte aninhado também é uma maneira válida de fazer isso e funciona no Honeycomb, como você pode ver com base nos comentários aqui. Não tive nenhum problema com ouvintes aninhados no ICS além deste - que novamente funciona no Honeycomb.
Michell Bak,
Por ouvintes aninhados, quero dizer classes internas anônimas.
Michell Bak,
Eu concordo que não deveria importar. Estou apenas comentando o que está presente na base de código. Vou olhar e ver se talvez as condições em que onClose foram redefinidas.
Sparky
Não tenho certeza se você entende Java - é chamada de classe interna anônima.
Joseph Earl