OnCloseListener SearchView не работает


101

Я пытаюсь добавить поддержку SearchViewв ActionBar Android 3.0+, но не могу заставить OnCloseListenerего работать.

Вот мой код:

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

Поиск работает отлично, и все работают, кроме OnCloseListener. В Logcat ничего не печатается. Вот логарифм, когда я нажимаю кнопку «Закрыть»:

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

Я просмотрел документацию и образцы, но ничего не изменилось. Я использую его на Asus Transformer Prime и Galaxy Nexus, оба на Ice Cream Sandwich. Любые идеи?

Обновить:

Да System.out.println() , работает. Вот доказательство:

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

Результаты в этом 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

Хм, у меня нормально работает с Android 3.2, но НЕ с 4.0+
PJL

10
Поднятый баг, 25758
PJL,

3
Я рад, что эта проблема возникла не только у меня. У кого-нибудь есть другие хаки, кроме приведенного ниже?
bencallis 07

2
Я узнал две вещи, если showAsActionустановлен на always. Поле поиска имеет собственную кнопку закрытия , но если она установлена, ifRoom | collapseActionViewона расширяется на панели действий.
Бераки

Ответы:


153

Я тоже сталкиваюсь с этой проблемой, и у меня нет другого выбора, кроме как отказаться от "oncloselistener". Вместо этого вы можете получить свой menuItem setOnActionExpandListener. Затем переопределите нереализованные методы.

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

Я считаю, что мы говорим только о SearchView ActionBar, который представляет собой только соты +
NKijak

не беспокойтесь об использовании onCloseListener, просто используйте его с вашим пунктом меню.
Роберт

12
Думаю, вы можете использовать MenuItemCompat.OnActionExpandListener для более ранних уровней API: developer.android.com/reference/android/support/v4/view/…
Ripityom

2
Полный ответ:if (Build.VERSION.SdkInt > BuildVersionCodes.NMr1) item.SetOnActionExpandListener(this); else MenuItemCompat.SetOnActionExpandListener(item, this);
FindOutIslamNow

61

Для Android API 14+ (ICS и выше) используйте этот код:

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

Чтобы получить больше информации: http://developer.android.com/guide/topics/ui/actionbar.html#ActionView.

Ссылка: onActionCollapse / onActionExpand


31

Для этой проблемы я придумал что-то вроде этого:

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
Что произойдет, если вы всегда расширяли с помощью setIconofiedByDefault (false)? Это не работает ... :(
Joan Casadellà

19

Я столкнулся с такой же проблемой на android 4.1.1. Похоже, это известная ошибка: https://code.google.com/p/android/issues/detail?id=25758

В любом случае, в качестве обходного пути я использовал прослушиватель изменения состояния (когда SearchView отсоединяется от панели действий, он, очевидно, также закрывается).

view.addOnAttachStateChangeListener(new OnAttachStateChangeListener() {

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

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

Приведенный выше код хорошо работал в моем случае.


Я публикую здесь тот же ответ: https://stackoverflow.com/a/24573266/2162924


Да, эта ошибка возникла сразу после того, как я опубликовал этот вопрос. См. Комментарии к исходному вопросу.
Michell Bak

О, хорошо, теперь посмотрим. Но в любом случае, возможно, этот обходной путь со слушателем изменения состояния может быть полезен и для других.
Dario

К сожалению, OnCloseListener не работает так, как вы думаете, но на самом деле это хорошее и чистое решение. Престижность!
welshk91

10

В итоге я использовал небольшой прием, который хорошо подходит для моих целей - не уверен, что он будет работать со всеми целями. В любом случае, я проверяю, пуст ли поисковый запрос. Это не совсем связано с SearchView"s" OnCloseListener- все равно не работает!

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

8

Что ж, это решило мою проблему:

Пункт меню с 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"/>

и в деятельности

searchView.setOnCloseListener(new OnCloseListener() {

        @Override
        public boolean onClose() {

            Log.i("SearchView:", "onClose");
            searchView.onActionViewCollapsed();
            return false;
        }
    });

1
Установка alwaysзначения showAsActionатрибута решает проблему. Важно то, что, когда alwaysзначение is notприсутствует в showAsAction, раскрытый SearchViewпредставляет кнопку закрытия (крестик) только в том случае, если запрос в строке не SearchViewравен нулю. То, SearchView.onCloseClickedчто обрабатывает события кнопки закрытия, сообщает, что обратный вызов OnCloseListenerвызывается только в том случае, если запрос пуст, если это не так - сначала он очищается - но затем, после очистки запроса, кнопка закрытия исчезает, и мы не можем доставить onCloseобратный вызов наOnCloseListener
bpawlowski

1
Просто подсказка: этот метод вызывается, когда пользователь закрывает окно поиска (довольно очевидно, но мне потребовалось несколько раз, чтобы понять). В первый раз, когда пользователь щелкает по X, он стирает текст, а я не получил это обновление, при втором щелчке по X он закрывает SearchView, и вызывается onClose. Надеюсь, поможет!
Федерико Альварес,

4

Для того , чтобы сделать OnCloseListenerработу, убедитесь , что showAsActionустановлен в alwaysв пункте меню поиска.

<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

Я столкнулся с той же проблемой, когда onCloseListener не вызывает SearchView. Изучив проблему с ошибкой , возникшую в 25758 , и некоторые сообщения, которые я читал, для вызова onCloseListener вам необходимо установить:

searchView.setIconifiedByDefault(true);

Но в моем случае я хотел, чтобы окно поиска открывалось, а не значковалось все время. Мне удалось решить эту проблему, добавив еще одну строку ниже:

@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) приведет к открытию searchView, несмотря на то, что в предыдущей строке для значения по умолчанию установлено значение true. Таким образом, мне удалось получить как SearchView, который постоянно открывается, так и вызывать onCloseListener.


2

Создайте пункт меню со app:showAsActionзначением всегда.

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

При создании SearchViewв onCreateOptionsMenuметоде сделайте что-то подобное

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

В search.setIconifiedByDefault(true)необходимо установить для trueвызвать onClose()метод на SearchView.OnCloseListener()созданный выше.



0

Причина, по OnCloseListenerкоторой не вызывается, заключается в том, что в коде Android есть ошибка - слушатель вызывается только в том случае, если вы также вызываетеsetIconifiedByDefault(true) .


7
Я просто попытался добавить setIconifiedByDefault (true), но он не вызывается
Джузеппе

@ Джозеф Эрл: у меня здесь аналогичная проблема: stackoverflow.com/questions/43702055/… . Есть мысли или идеи, как исправить?
AJW

0

Кажется, это уже старый поток, но я думал, что у меня та же проблема API 18 вначале. После того, как погуглил, нашел эту ветку, еще час прочитал javadoc, попробовал и ошибся для чего-то, что я не претендую полностью понять в javadoc, теперь для меня работает следующая работа:

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

Я немного поигрался с истиной / ложью, это каким-то образом имеет значение, и теперь это работает для меня. Надеюсь, это поможет кому-то сэкономить время.


0

Это обходной путь, но у меня сработало

  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
    }

если вы нажмете закрыть searchView ->

D / click: закрыть нажал


1
Ответы с куском кода и некоторыми загадочными словами не особенно ясны. Просто используйте естественный язык, чтобы описать, почему вы думаете, что это решает проблему, а затем покажите реализацию решения.

0

Я столкнулся с этой проблемой при попытке обнаружить отображение / закрытие SearchView. В итоге я использовал другой слушатель, и он работал для того, что мне нужно:

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

0

Я использовал кнопку закрытия SearchView и установил на ней setOnClickListener

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

-2

В Android нет консоли для входа. Вместо этого используйте платформу ведения журнала Android:

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

См. Также этот вопрос: Почему "System.out.println" не работает в Android?


2
Неправда, работает нормально. См. Мой обновленный вопрос - я добавил строку в метод onQueryTextChange, чтобы доказать это. Также попытался добавить Log.d (), но он тоже ничего не отображал.
Мичелл Бак

Ой, как плохо! Похоже, где-то по пути они решили вывести System.out.println в Log.i. Удачи
Крис Найт

-3

Есть два общих шаблона для SearchView.setOnCloseListener() . Это действительно верно для всех слушателей, но я обращаюсь к вашему вопросу конкретно. Первый способ - создать функцию прослушивателя и присоединить ее к переменной-члену, а второй - заставить класс реализовать интерфейс и сделать обработчик функцией-членом.

Создание объекта слушателя выглядит так:

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

Реализация слушателя на уровне класса выглядит так:

public class MyClass implements OnCloseListener {
    private SearchView mSearchView;

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

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

Я не видел примеров, которые бы создавали OnCloseListenerad-hoc, как вы в своем вопросе.


Привет, Спарки, спасибо за комментарий. Я действительно не понимаю, как это должно что-то изменить. Вложенный прослушиватель также является допустимым способом сделать это, и он работает на Honeycomb, как вы можете видеть из комментариев здесь. У меня не было никаких проблем с вложенными слушателями на ICS, кроме этого - который снова работает на Honeycomb.
Мичелл Бак

Под вложенными слушателями я подразумеваю анонимные внутренние классы.
Мичелл Бак

Я согласен, что это не имеет значения. Я комментирую только то, что присутствует в кодовой базе. Я посмотрю и посмотрю, не были ли переопределены условия, в которых onClose.
Sparky

Я не уверен, что вы понимаете Java - это называется анонимным внутренним классом.
Джозеф Эрл
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.