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

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

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


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

}

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


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

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

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>

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.


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.



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


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.


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

0
    searchView.setOnCloseListener {
        d("click", "close clicked")
        return@setOnCloseListener false
    }

se você clicar em fechar searchView ->

D / clique: fechar clicado


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

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

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


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.


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
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.