оскільки це питання та деякі відповіді мають більше п'яти років, дозвольте мені поділитися своїм рішенням. Це супроводження та модернізація відповіді від @oyenigun
ОНОВЛЕННЯ:
У нижній частині цієї статті я додав альтернативну реалізацію, використовуючи абстрактне розширення фрагмента, яке взагалі не буде задіяти активність, що було б корисно для всіх, хто має більш складну ієрархію фрагментів, що включає вкладені фрагменти, які вимагають різної поведінки ззаду.
Мені потрібно було це здійснити, оскільки деякі фрагменти, які я використовую, мають менші погляди, які я хотів би відхилити за допомогою кнопки "назад", наприклад, невеликі інформаційні перегляди, що спливають тощо, але це добре для тих, кому потрібно змінити поведінку задня кнопка всередині фрагментів.
Спочатку визначте інтерфейс
public interface Backable {
boolean onBackPressed();
}
Цей інтерфейс, який я називаю Backable
(я стикер для іменування конвенцій), має єдиний метод, onBackPressed()
який повинен повернути boolean
значення. Нам потрібно застосувати булеве значення, тому що нам потрібно буде знати, чи натиснення кнопки "назад" "поглинуло" задню подію. Повернення true
означає, що воно має, і подальша дія не потрібна, інакше false
говорить про те, що зворотна дія за замовчуванням все ж має відбутися. Цей інтерфейс повинен бути власним файлом (бажано, в окремому пакеті з назвою interfaces
). Пам'ятайте, розділення класів на пакети - це хороша практика.
По-друге, знайдіть верхній фрагмент
Я створив метод, який повертає останній Fragment
об’єкт у задній стек. Я використовую теги ... якщо ви використовуєте ідентифікатори, внесіть необхідні зміни. Цей статичний метод у мене є в класі утиліт, який займається умовами навігації тощо ... але, звичайно, розміщуйте його там, де він найкраще підходить вам. Для зведення я поставив моє в клас під назвою NavUtils
.
public static Fragment getCurrentFragment(Activity activity) {
FragmentManager fragmentManager = activity.getFragmentManager();
if (fragmentManager.getBackStackEntryCount() > 0) {
String lastFragmentName = fragmentManager.getBackStackEntryAt(
fragmentManager.getBackStackEntryCount() - 1).getName();
return fragmentManager.findFragmentByTag(lastFragmentName);
}
return null;
}
Переконайтеся, що кількість зворотних стеків перевищує 0, інакше ArrayOutOfBoundsException
під час виконання може бути кинуто зображення. Якщо вона не перевищує 0, поверніть null. Пізніше ми перевіримо нульове значення ...
По-третє, реалізація у фрагменті
Реалізуйте Backable
інтерфейс у будь-якому фрагменті, де потрібно змінити поведінку кнопки "назад". Додайте спосіб реалізації.
public class SomeFragment extends Fragment implements
FragmentManager.OnBackStackChangedListener, Backable {
...
@Override
public boolean onBackPressed() {
// Logic here...
if (backButtonShouldNotGoBack) {
whateverMethodYouNeed();
return true;
}
return false;
}
}
У onBackPressed()
виправданому порядку введіть необхідну логіку. Якщо ви хочете, щоб кнопка "назад" не відображала задній стек (поведінка за замовчуванням), поверніть true , щоб ваша подія назад була поглинена. В іншому випадку поверніть хибне.
І нарешті, у вашій діяльності ...
Замініть onBackPressed()
метод і додайте до нього цю логіку:
@Override
public void onBackPressed() {
// Get the current fragment using the method from the second step above...
Fragment currentFragment = NavUtils.getCurrentFragment(this);
// Determine whether or not this fragment implements Backable
// Do a null check just to be safe
if (currentFragment != null && currentFragment instanceof Backable) {
if (((Backable) currentFragment).onBackPressed()) {
// If the onBackPressed override in your fragment
// did absorb the back event (returned true), return
return;
} else {
// Otherwise, call the super method for the default behavior
super.onBackPressed();
}
}
// Any other logic needed...
// call super method to be sure the back button does its thing...
super.onBackPressed();
}
Ми отримуємо поточний фрагмент у задній стеці, потім робимо нульову перевірку та визначаємо, чи реалізує він наш Backable
інтерфейс. Якщо так, визначте, чи подія була поглинена. Якщо так, ми закінчили onBackPressed()
і можемо повернутися. В іншому випадку, ставтеся до цього як до звичайного зворотного преса і зателефонуйте до супер методу.
Другий варіант не включати діяльність
Часом ви взагалі не хочете, щоб Діяльність обробляла це, і вам потрібно обробляти його безпосередньо у фрагменті. Але хто каже, що ви не можете мати фрагменти з API заднього натискання? Просто розкладіть свій фрагмент до нового класу.
Створіть абстрактний клас, який розширює фрагмент та реалізує View.OnKeyListner
інтерфейс ...
import android.app.Fragment;
import android.os.Bundle;
import android.view.KeyEvent;
import android.view.View;
public abstract class BackableFragment extends Fragment implements View.OnKeyListener {
@Override
public void onViewCreated(View view, Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
view.setFocusableInTouchMode(true);
view.requestFocus();
view.setOnKeyListener(this);
}
@Override
public boolean onKey(View v, int keyCode, KeyEvent event) {
if (event.getAction() == KeyEvent.ACTION_UP) {
if (keyCode == KeyEvent.KEYCODE_BACK) {
onBackButtonPressed();
return true;
}
}
return false;
}
public abstract void onBackButtonPressed();
}
Як бачимо, будь-який фрагмент, який розширюється BackableFragment
, автоматично фіксує кліки назад за допомогою View.OnKeyListener
інтерфейсу. Просто зателефонуйте абстрактному onBackButtonPressed()
методу зсередини реалізованого onKey()
методу, використовуючи стандартну логіку для виявлення натискання кнопки "назад". Якщо вам потрібно зареєструвати натискання клавіш, окрім кнопки "назад", просто переконайтеся, що зателефонуйте super
методу, коли onKey()
перейдете на його фрагмент, інакше ви перекриєте поведінку в абстракції.
Простий у використанні, просто розширити та впровадити:
public class FragmentChannels extends BackableFragment {
...
@Override
public void onBackButtonPressed() {
if (doTheThingRequiringBackButtonOverride) {
// do the thing
} else {
getActivity().onBackPressed();
}
}
...
}
Оскільки onBackButtonPressed()
метод у суперкласі абстрактний, після його розширення необхідно реалізувати onBackButtonPressed()
. Він повертається, void
тому що йому просто потрібно виконати дію в класі фрагменту, і не потрібно ретрансляцію поглинання преси назад до Activity. Переконайтеся, що ви зателефонували до onBackPressed()
методу " Активність", якщо все, що ви робите за допомогою кнопки "Назад", не потребує обробки, інакше кнопка "назад" буде відключена ... і ви цього не хочете!
Застереження
Як ви бачите, це встановлює ключового слухача на кореневий вигляд фрагмента, і нам потрібно буде зосередити його. Якщо у вашому фрагменті є тексти редагування (або будь-які інші погляди на крадіжку фокусу), які розширюють цей клас (або інші внутрішні фрагменти чи представлення, які мають однакові), вам потрібно буде обробити це окремо. Існує хороша стаття про розширення EditText, щоб втратити фокус на зворотному натисканні.
Сподіваюся, хтось вважає це корисним. Щасливе кодування.