Как обрабатывать видимость значков ActionBar при использовании SearchView

Что ж, я хочу:

  • Инициализировать ActionBar со всеми элементами, кроме «searchSettings»;
  • При щелчке по значку поиска появляются параметры поиска, а остальные значки исчезают;
  • При закрытии поиска EditText (нажатие кнопки «Назад» на устройстве или кнопки «Назад» на ActionBar) ActionBar возвращается в исходное состояние (появляются все значки, кроме «searchSettings»).

Мой фактический код следующий:

(Я импортировал android.support.v7.widget.SearchView вместо android.widget.SearchView. Когда я использовал android.widget.SearchView, это работало нормально, но другие вещи не работали)

private MenuItem searchIteam, searchSettings;
private SearchView searchView;

@Override
public boolean onCreateOptionsMenu(final Menu menu) {

    MenuInflater inflater = getMenuInflater();
    inflater.inflate(R.menu.menu_main, menuMain);
    searchItem = menu.findItem(R.id.search);
    searchSettings = menu.findItem(R.id.action_searchSettings);
    searchView = (SearchView)MenuItemCompat.getActionView(item);
    searchSettings.setVisible(false); // hide searchSettings Item when Menu is created

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

        @Override
        public boolean onQueryTextChange(String newText) {
            (...)

            return false;
        }
    });

    // Detect SearchView icon clicks
    searchView.setOnSearchClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            setItemsVisibility(menuMain, item, false);
            searchSettings.setVisible(true);
        }
    });
    // Detect SearchView close
    searchView.setOnCloseListener(new SearchView.OnCloseListener() {
        @Override
        public boolean onClose() {
            supportInvalidateOptionsMenu(); //shouldn't this reload the Action Bar as it was when onCreate?
            return true;
        }
    });

    return super.onCreateOptionsMenu(menu);

}

private void setItemsVisibility(Menu menu, MenuItem exception, boolean visible) {
    for (int i=0; i<menu.size(); ++i) {
        MenuItem item = menu.getItem(i);
        if (item != exception) item.setVisible(visible);
    }
}

@Override
public boolean onOptionsItemSelected(MenuItem item) {
    int id = item.getItemId();

    if (id == android.R.id.home) {
        onBackPressed();
    }

    return super.onOptionsItemSelected(item);
}

@Override
public void onBackPressed() {
    supportInvalidadeOptionsMenu();
    super.onBackPressed();
}

Этот код не работает, когда я нажимаю «назад» в первый раз, он только закрывает EditText поиска, а значки не меняются. Если я снова нажму «назад», действие поднимется на уровень выше, но я вижу, что значки становятся в начале (получают то, что должны, когда я нажимал «назад» в первый раз) за некоторое время до закрытия действия ...

--- ИЗМЕНИТЬ ---

В настоящее время, если я нажму значок Search ActionBar, а затем начну несколько раз нажимать кнопку «Назад», произойдет следующее:

  • 1-е нажатие: клавиатура прячется, но поиск EditText все еще открыт;
  • 2-е нажатие: поиск завершается (поиск EditText закрывается и отображается содержимое обычной активности);
  • 3-е нажатие: действие закрывается.

Затем, для целей тестирования, я сделал это:

boolean pressed1, pressed2, pressed3;

searchView.setOnSearchClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            pressed1 = false;
            pressed2 = false;
            pressed3 = false;
            setItemsVisibility(menuMain, item, false);
            searchSettings.setVisible(true);
        }
    });

@Override
public void onBackPressed() {
    if (!pressed1) {
        pressed1 = true;
    }
    else if(!pressed2) {
        pressed2 = true;
    }
    else if(!pressed3) {
        pressed3 = true;
        supportInvalidateOptionsMenu();
    }
    else {
        super.onBackPressed();
    }
}

И вот что происходит:

  • 1-е нажатие: клавиатура прячется, но поиск EditText все еще открыт;
  • 2-е нажатие: поиск завершается (поиск EditText закрывается и отображается содержимое обычной активности);
  • 3-е нажатие: ничего не происходит;
  • 4-е нажатие: ничего не происходит;
  • 5-е нажатие: панель действий перезагружается, как я хотел;
  • 6-е нажатие: активность закрывается;

--- ИЗМЕНИТЬ 2 ---

Затем я изменился на это:

@Override
public void onBackPressed() {
    if (!pressed1) {
        pressed1 = true;
        onBackPressed();
    }
    else if(!pressed2){
        pressed2 = true;
        onBackPressed();
    }
    else if(!pressed3){
        pressed3 = true;
        supportInvalidateOptionsMenu();
    }
    else {
        super.onBackPressed();
    }
}

Сейчас происходит следующее:

  • 1-е нажатие: клавиатура прячется, но поиск EditText все еще открыт;
  • 2-е нажатие: поиск завершается (поиск EditText закрывается и отображается содержимое обычной активности);
  • 3-е нажатие: ActionBar перезагружается, как я хотел;
  • 4-е нажатие: действие закрывается;

--- РЕДАКТИРОВАТЬ 3 --- (РЕШЕНИЕ) ---

Я предполагаю, что методы setOnSearchClickListener и setOnCloseListener взяты из android.widget.SearchView... Поскольку вместо этого я импортировал android.support.v7.widget.SearchView, я изменил их на:

MenuItemCompat.setOnActionExpandListener(searchItem,
            new MenuItemCompat.OnActionExpandListener() {
                @Override
                public boolean onMenuItemActionExpand(MenuItem menuItem) {
                    setItemsVisibility(menu, searchItem, false);
                    return true;
                }
                @Override
                public boolean onMenuItemActionCollapse(MenuItem menuItem) {
                    supportInvalidateOptionsMenu();
                    return true;
                }
            });

Теперь все работает нормально (:


person T. Lima    schedule 15.06.2017    source источник


Ответы (1)


Надеюсь, я вас правильно понял: при первом нажатии НАЗАД клавиатура скрывается. При втором нажатии НАЗАД приложение закрывается.

Если это так, то все работает нормально. Потому что это то, что должен делать super.onBackPressed(). Он попытается скрыть клавиатуру, если она отображается. Если нет, он попытается перейти к предыдущему действию. Если его нет, приложение закроется.

Итак, что вам нужно сделать, это поиграть с методом onBackPressed(). По сути, вам не обязательно вызывать метод super, если вы уверены, что должны делать.

@Override
public void onBackPressed() {
    if ( isSearching) {
        supportInvalidadeOptionsMenu();
        isSearching = false;     
    } else {
        super.onBackPressed();
    }
}

Итак, теперь, когда вы никогда не нажимаете кнопку НАЗАД, действие проверяет, является ли поиск, и решает повторно отобразить панель действий или выполнить свои обычные действия, как обычно.

Вам нужно будет добавить некоторую логику, чтобы установить логический флаг isSearching, например, установить для isSearching значение true при нажатии кнопки «Поиск».

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

person CristianoYL    schedule 15.06.2017
comment
Спасибо, Крис! Но, боюсь, вы ошиблись... При первом нажатии «Назад» клавиатура скрывается (ок, это нормально), после этого при первом нажатии «Назад» поиск завершается, а значки — нет. перезагрузить... Я уже пытался вручную установить видимость вместо использования supportInvalidateOptionsMenu(), и это все еще не работает ;(. Если я использую ваш метод, он работает, нажав «Назад» еще раз после всего этого... Это не пойдет вернуться к предыдущему действию, но не работает и при первом нажатии =/ - person T. Lima; 16.06.2017
comment
Это потому, что вы вызвали super.onBackPressed(), и метод super закроет приложение, если вы не сделаете это, как я вам говорю. super.onBackPressed() вызывается КАЖДЫЙ РАЗ, когда вы нажимаете кнопку «Назад» в своем коде, и это проблема. - person CristianoYL; 16.06.2017
comment
Вам нужно сообщить методу onBackPressed(), что именно должно произойти. если отображается клавиатура, используйте super.onBackPressed(), в противном случае, если выполняется поиск, повторно визуализируйте панель действий, не вызывайте super.onBackPressed(), иначе вызывайте super.onBackPressed(). И вы должны перейти к предыдущей активности в этом случае. - person CristianoYL; 16.06.2017
comment
После всего этого, я не знаю почему, для перезагрузки панели действий по-прежнему требуется 2 нажатия назад =/ - person T. Lima; 16.06.2017
comment
Пожалуйста, проверьте порядок ваших операторов if в методе onBackPressed(), возможно, вы не нажмете нужное предложение перед возвратом. Если у вас все еще есть проблема, пожалуйста, опубликуйте свой код. - person CristianoYL; 16.06.2017
comment
Пожалуйста, взгляните на мой Edit и Edit 2 - person T. Lima; 16.06.2017
comment
рад, что вы нашли решение, но вызов onBackPressd() внутри onBackPressed не имеет смысла. Это рекурсивный вызов. И я сделал ошибку, скрывая клавиатуру, на самом деле она не попала в метод onBackPressed(). Таким образом, первое нажатие НАЗАД всегда скрывало клавиатуру и больше ничего не делало. - person CristianoYL; 16.06.2017
comment
Я вызвал onBackPressed() внутри onBackPressed, чтобы имитировать следующее нажатие кнопки «Назад», просто для тестирования... Я не заметил, что первое нажатие просто закроет клавиатуру... Спасибо за помощь, сэр! - person T. Lima; 16.06.2017