Как реализовать функцию onBackPressed() во фрагментах?

Есть ли способ реализовать onBackPressed() в Android Fragment аналогично тому, как это сделано в Android Activity?

Поскольку жизненный цикл Fragment не имеет onBackPressed(). Есть ли какой-нибудь другой альтернативный метод, чтобы обойти onBackPressed() во фрагментах Android 3.0?

Комментарии к вопросу (8)

Я решил таким образом переопределить onBackPressed в деятельности. Все FragmentTransaction "являются" addToBackStack перед коммитом:

@Override
public void onBackPressed() {

    int count = getSupportFragmentManager().getBackStackEntryCount();

    if (count == 0) {
        super.onBackPressed();
        //additional code
    } else {
        getSupportFragmentManager().popBackStack();
    }

}
Комментарии (8)

Я самое лучшее решение

РЕШЕНИЕ # НА JAVA

Создать простой интерфейс :

public interface IOnBackPressed {
    /**
     * If you return true the back press will not be taken into account, otherwise the activity will act naturally
     * @return true if your processing has priority if not false
     */
    boolean onBackPressed();
}

И в вашей деятельности

public class MyActivity extends Activity {
    @Override public void onBackPressed() {
    Fragment fragment = getSupportFragmentManager().findFragmentById(R.id.main_container);
       if (!(fragment instanceof IOnBackPressed) || !((IOnBackPressed) fragment).onBackPressed()) {
          super.onBackPressed();
       }
    } ...
}

Наконец-то в ваш фрагмент:

public class MyFragment extends Fragment implements IOnBackPressed{
   @Override
   public boolean onBackPressed() {
       if (myCondition) {
            //action not popBackStack
            return true; 
        } else {
            return false;
        }
    }
}

РЕШЕНИЕ # КОТЛИН

1 - Создать Интерфейс

interface IOnBackPressed {
    fun onBackPressed(): Boolean
}

2 - подготовка вашей деятельности

class MyActivity : AppCompatActivity() {
    override fun onBackPressed() {
        val fragment =
            this.supportFragmentManager.findFragmentById(R.id.main_container)
        (fragment as? IOnBackPressed)?.onBackPressed()?.not()?.let {
            super.onBackPressed()
        }
    }
}

3 - реализовать в вашей целевой фрагмент

class MyFragment : Fragment(), IOnBackPressed {
    override fun onBackPressed(): Boolean {
        return if (myCondition) {
            //action not popBackStack
            true
        } else {
            false
        }
    }
}
Комментарии (11)

Согласно ответу @HaMMeRed вот псевдокод, как это должно работать. Предположим, что ваша основная активность называется BaseActivity, которая имеет дочерние фрагменты (как в примере с либой SlidingMenu). Вот шаги:

Сначала нам нужно создать интерфейс и класс, который реализует интерфейс, чтобы иметь общий метод.

  1. Создайте интерфейс класса OnBackPressedListener.

    public interface OnBackPressedListener {
        public void doBack();
    }
  2. Создайте класс, реализующий навыки OnBackPressedListener.

    public class BaseBackPressedListener implements OnBackPressedListener {
        private final FragmentActivity activity;
    
        public BaseBackPressedListener(FragmentActivity activity) {
            this.activity = activity;
        }
    
        @Override
        public void doBack() {
            activity.getSupportFragmentManager().popBackStack(null, FragmentManager.POP_BACK_STACK_INCLUSIVE);
        }
    }
  3. С этого момента мы будем работать над нашим кодом BaseActivity и его фрагментами

  4. Создайте частный слушатель поверх класса BaseActivity.

    protected OnBackPressedListener onBackPressedListener;
  5. создайте метод для установки слушателя в BaseActivity.

    public void setOnBackPressedListener(OnBackPressedListener onBackPressedListener) {
        this.onBackPressedListener = onBackPressedListener;
    }
  6. в переопределении onBackPressed реализуйте что-то вроде этого

    @Override
    public void onBackPressed() {
        if (onBackPressedListener != null)
            onBackPressedListener.doBack();
        else
            super.onBackPressed();
  7. в вашем фрагменте в onCreateView вы должны добавить наш слушатель

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
        activity = getActivity();
    
        ((BaseActivity)activity).setOnBackPressedListener(new BaseBackPressedListener(activity));
    
        View view = ... ;
    //что-то с видом
    
        return view;
    }

Вуаля, теперь при щелчке назад во фрагменте вы должны поймать ваш пользовательский метод on back.

Комментарии (6)

Этот работал для меня: https://stackoverflow.com/a/27145007/3934111

@Override
public void onResume() {
    super.onResume();

    if(getView() == null){
        return;
    }

    getView().setFocusableInTouchMode(true);
    getView().requestFocus();
    getView().setOnKeyListener(new View.OnKeyListener() {
        @Override
        public boolean onKey(View v, int keyCode, KeyEvent event) {

            if (event.getAction() == KeyEvent.ACTION_UP && keyCode == KeyEvent.KEYCODE_BACK){
                // handle back button's click listener
                return true;
            }
            return false;
        }
    });
}
Комментарии (4)

Если вам нужна такая функциональность, вам нужно переопределить ее в вашей активности, а затем добавить интерфейс YourBackPressed ко всем вашим фрагментам, который вы вызываете на соответствующем фрагменте всякий раз, когда нажата кнопка "Назад".

Edit: Я'хотел бы дополнить свой предыдущий ответ.

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

LocalBroadcastManager в библиотеке поддержки может помочь с этим, и вы просто посылаете трансляцию в onBackPressed и подписываетесь на ваши фрагменты, которым это важно. Я думаю, что Messaging является более развязанной реализацией и будет лучше масштабироваться, поэтому сейчас это моя официальная рекомендация по реализации. Просто используйте действие Intent's в качестве фильтра для вашего сообщения. Отправьте ваше вновь созданное ACTION_BACK_PRESSED, отправьте его из вашей активности и слушайте его в соответствующих фрагментах.

Комментарии (7)

Все это легко реализовать и не будет функционировать оптимальным образом.

Фрагменты вызова метода onDetach, что будет делать эту работу.

@Override
    public void onDetach() {
        super.onDetach();
        PUT YOUR CODE HERE
    }

ЭТО БУДЕТ ДЕЛАТЬ ЭТУ РАБОТУ.

Комментарии (5)

Просто добавьте addToBackStack во время перехода между фрагментами, как показано ниже:

fragmentManager.beginTransaction().replace(R.id.content_frame,fragment).addToBackStack("tag").commit();

Если вы напишите addToBackStack(null), он обработает это сам, но если вы зададите тег, вы должны обработать его вручную.

Комментарии (3)

поскольку этот вопрос и некоторые ответы в течение пяти лет, позвольте мне поделиться своим решением. Это является продолжением и модернизацией в ответ от @oyenigun

Обновление: В нижней части этой статьи, я добавил альтернативную реализацию, используя абстрактный фрагмент расширения, которая выиграла'т связаны активность вообще, что будет полезным для тех, кто с более сложными фрагмент с участием иерархии вложенных фрагментов, которые требуют различных поведение.

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

Во-первых, определить интерфейс

public interface Backable {
    boolean onBackPressed();
}

Этот интерфейс, который я называю Backable (я'м сторонник именования), имеет один метод onBackPressed (), который должен вернутьлогическое значение. Мы должны применить логическое значение, потому что мы должны знать, если кнопки "назад" пресса "и поглощаемой" задняя событие. Возврат True означает, что он имеет, и никаких дальнейших действий не требуется, в противном случае - "ложь" говорит о том, что по умолчанию действие все равно должно иметь место. Этот интерфейс должен быть это'собственный файл с (желательно в отдельный пакет под названием интерфейсы). Помните, разделяющей классы в пакеты-это хорошая практика.

Во-вторых, найдите верхний фрагмент

Я создал метод, который возвращает объект последний "фрагмент" в резервную стопку. Я использую теги... если вы используете ID и#39;ы, внести необходимые изменения. У меня этот статический метод в служебный класс, который занимается навигацией государства, и т. д... Но, конечно, положить его там, где он лучше всего подходит вам. Для назидания, я'вэ положить мину в класс под названием 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()` переопределить, поставить любую логику нужно. Если вы хотите, чтобы кнопка Обратно в ** не поп-обратно стек (по умолчанию), возвратить правда**, что ваша задняя часть мероприятия была поглощена. В противном случае возвращает false.

И наконец, в ваших действиях...

Переопределить `метод 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();
}

Мы получаем текущий фрагмент в задней стеке, тогда мы делаем проверку на null и определить, если он реализует интерфейс Backable`. Если это произойдет, определить, если событие было поглощено. Если да, мы'вновь выполнена с onBackPressed () и может вернуться. В противном случае, относиться к ней как к нормальной Прессы и вызов супер метод.

Второй вариант, чтобы не привлекать к деятельности

Порой, вы не'т хотим, чтобы деятельность, чтобы справиться с этим на всех, и вы должны обращаться непосредственно внутри фрагмента. Но кто сказал, что вы можете'Т есть фрагменты с пресс-АПИ? Просто расширьте свой фрагмент в новый класс.

Создать абстрактный класс, который расширяет фрагмент и реализует представления.Интерфейс 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 автоматически захватить обратно кликов с помощью зрения.Интерфейс OnKeyListener. Просто вызвать метод абстрактногоonBackButtonPressed () изнутри реализовали метод onKey()с помощью стандартной логики различить нажатие кнопки "Назад". Если вам необходима регистрация нажатий клавиш, кроме кнопки Назад, просто будьте уверены, чтобы назвать "супер" метода при переопределенииonKey()` в ваш фрагмент, иначе вы'МР override поведение в абстракции.

Простой в использовании, просто распространить и внедрить:

public class FragmentChannels extends BackableFragment {

    ...

    @Override
    public void onBackButtonPressed() {
        if (doTheThingRequiringBackButtonOverride) {
            // do the thing
        } else {
            getActivity().onBackPressed();
        }
    }

    ...
}

С onBackButtonPressed()метод в супер классе является абстрактным, раз вы продлить необходимо реализоватьonBackButtonPressed(). Она возвращает значениепустота, потому что это просто необходимо для выполнения действий внутри класса фрагмент, и не нужно реле поглощение пресс-вернемся к активности. **Убедитесь, что** вы называете активностьonBackPressed()` метод, если все, что вы'повторно делать с задней кнопки Не'т требует обработки, в противном случае, кнопки "Назад" будет отключен... а вы Дон'т, что хотите!

Предупреждения Как вы можете видеть, это задает ключ слушателя к корневому представлению фрагмента, и мы'll необходимо, чтобы сфокусировать его. Если там замешаны редактирования текстов (или любой другой фокус-кража видом) в вашем фрагменте, который расширяет этот класс (или другие внутренние фрагменты или представления, которые имеют те же), вы'll необходимо обрабатывать отдельно. Там'ы хорошая статья на расширение полей EditText, чтобы потерять фокус на спину пресс.

Я надеюсь, что кто-то находит это полезным. Удачи в кодировании.

Комментарии (6)

Решение очень простое:

  1. Если у вас есть базовый фрагмент класса, что все фрагменты расширить, а затем добавить этот код, чтобы он'S-класса, иначе создать такой базовый фрагмент класса
 /* 
 * called when on back pressed to the current fragment that is returned
 */
 public void onBackPressed()
 {
    // add code in super class when override
 }
  1. в своем классе активности, переопределить onBackPressed следующим образом:
private BaseFragment _currentFragment;

@Override
public void onBackPressed()
{
      super.onBackPressed();
     _currentFragment.onBackPressed();
}
  1. в вашем классе фрагмент, добавить нужный код:
 @Override
 public void onBackPressed()
 {
    setUpTitle();
 }
Комментарии (1)

`onBackPressed (), потому что фрагмент будет отделяться от активности.

По данным @стерлингового Диаз ответа я думаю, что он прав. Но некоторые ситуации будет неправильно. (исх. Поворот Экрана)

Так что, я думаю, мы могли бы определить, является ли isRemoving() для достижения цели.

Вы можете написать его в onDetach()илиonDestroyView()`. Это работа.

@Override
public void onDetach() {
    super.onDetach();
    if(isRemoving()){
        // onBackPressed()
    }
}

@Override
public void onDestroyView() {
    super.onDestroyView();
    if(isRemoving()){
        // onBackPressed()
    }
}
Комментарии (0)

Вы должны добавить интерфейс к вашему проекту, как показано ниже;

public interface OnBackPressed {

     void onBackPressed();
}

И потом, вы должны реализовать этот интерфейс на вашем фрагменте;

public class SampleFragment extends Fragment implements OnBackPressed {

    @Override
    public void onBackPressed() {
        //on Back Pressed
    }

}

И вы можете запустить это событие onBackPressed под вашу деятельность onBackPressed событие, как показано ниже;

public class MainActivity extends AppCompatActivity {
       @Override
        public void onBackPressed() {
                Fragment currentFragment = getSupportFragmentManager().getFragments().get(getSupportFragmentManager().getBackStackEntryCount() - 1);
                if (currentFragment instanceof OnBackPressed) {  
                    ((OnBackPressed) currentFragment).onBackPressed();
                }
                super.onBackPressed();
        }
}
Комментарии (1)

Ну, я сделал это так, и это работает для меня

Простой интерфейс

FragmentOnBackClickInterface.java

public interface FragmentOnBackClickInterface {
    void onClick();
}

Пример реализации

MyFragment.java

public class MyFragment extends Fragment implements FragmentOnBackClickInterface {

// other stuff

public void onClick() {
       // what you want to call onBackPressed?
}

тогда просто переопределить onBackPressed в деятельности

    @Override
public void onBackPressed() {
    int count = getSupportFragmentManager().getBackStackEntryCount();
    List frags = getSupportFragmentManager().getFragments();
    Fragment lastFrag = getLastNotNull(frags);
    //nothing else in back stack || nothing in back stack is instance of our interface
    if (count == 0 || !(lastFrag instanceof FragmentOnBackClickInterface)) {
        super.onBackPressed();
    } else {
        ((FragmentOnBackClickInterface) lastFrag).onClick();
    }
}

private Fragment getLastNotNull(List list){
    for (int i= list.size()-1;i>=0;i--){
        Fragment frag = list.get(i);
        if (frag != null){
            return frag;
        }
    }
    return null;
}
Комментарии (8)

Если вы использовать EventBus, это, вероятно, гораздо более простое решение :

В вашем фрагменте :

@Override
public void onAttach(Activity activity) {
    super.onAttach(activity);
    EventBus.getDefault().register(this);
}

@Override
public void onDetach() {
    super.onDetach();
    EventBus.getDefault().unregister(this);
}

// This method will be called when a MessageEvent is posted
public void onEvent(BackPressedMessage type){
    getSupportFragmentManager().popBackStack();
}

и в вашем классе деятельности можно определить :

@Override
public void onStart() {
    super.onStart();
    EventBus.getDefault().register(this);
}

@Override
public void onStop() {
    EventBus.getDefault().unregister(this);
    super.onStop();
}

// This method will be called when a MessageEvent is posted
public void onEvent(BackPressedMessage type){
    super.onBackPressed();
}

@Override
public void onBackPressed() {
    EventBus.getDefault().post(new BackPressedMessage(true));
}

BackPressedMessage.java это просто объект POJO-объект

Это супер чистый и нет интерфейс/превосходное качество исполнения.

Комментарии (0)

Это лишь небольшой код, который будет делать трюк:

 getActivity().onBackPressed();

Надеюсь, что это помогает кто-то :)

Комментарии (2)

это мое решение:

В MyActivity.java:

public interface OnBackClickListener {
        boolean onBackClick();
    }

    private OnBackClickListener onBackClickListener;

public void setOnBackClickListener(OnBackClickListener onBackClickListener) {
        this.onBackClickListener = onBackClickListener;
    }

@Override
    public void onBackPressed() {
        if (onBackClickListener != null && onBackClickListener.onBackClick()) {
            return;
        }
        super.onBackPressed();
    }

> и в Отрывок:

((MyActivity) getActivity()).setOnBackClickListener(new MyActivity.OnBackClickListener() {
    @Override
    public boolean onBackClick() {
        if (condition) {
            return false;
        }

        // some codes

        return true;
    }
});
Комментарии (0)

Как насчет использования onDestroyView()?

@Override
public void onDestroyView() {
    super.onDestroyView();
}
Комментарии (2)
public class MyActivity extends Activity {

    protected OnBackPressedListener onBackPressedListener;

    public interface OnBackPressedListener {
        void doBack();
    }

    public void setOnBackPressedListener(OnBackPressedListener onBackPressedListener) {
        this.onBackPressedListener = onBackPressedListener;
    }

    @Override
    public void onBackPressed() {
        if (onBackPressedListener != null)
            onBackPressedListener.doBack();
        else
            super.onBackPressed();
    } 

    @Override
    protected void onDestroy() {
        onBackPressedListener = null;
        super.onDestroy();
    }
}

в вашем фрагменте добавить следующее, Не забудьте внедрить в MainActivity'с интерфейсом.

public class MyFragment extends Framgent implements MyActivity.OnBackPressedListener {
    @Override
    public void onViewCreated(View view, Bundle savedInstanceState) {
        super.onViewCreated(view, savedInstanceState);
         ((MyActivity) getActivity()).setOnBackPressedListener(this);
    }

@Override
public void doBack() {
    //BackPressed in activity will call this;
}

}
Комментарии (0)
@Override
public void onResume() {
    super.onResume();

    getView().setFocusableInTouchMode(true);
    getView().requestFocus();
    getView().setOnKeyListener(new View.OnKeyListener() {
        @Override
        public boolean onKey(View v, int keyCode, KeyEvent event) {
            if (event.getAction() == KeyEvent.ACTION_UP && keyCode == KeyEvent.KEYCODE_BACK) {
                // handle back button
                replaceFragmentToBackStack(getActivity(), WelcomeFragment.newInstance(bundle), tags);

                return true;
            }

            return false;
        }
    });
}
Комментарии (1)

Очень короткий и сладкий ответ:

getActivity().onBackPressed();

Объяснение весь сценарий моем случае:

Я FragmentA в класс MainActivity, Я открываю FragmentB от FragmentA (FragmentB является ребенок или вложенный фрагмент FragmentA)

 Fragment duedateFrag = new FragmentB();
 FragmentTransaction ft  = getFragmentManager().beginTransaction();
 ft.replace(R.id.container_body, duedateFrag);
 ft.addToBackStack(null);
 ft.commit();

Теперь, если вы хотите, чтобы перейти к FragmentA от FragmentB вы можете просто положить getActivity().onBackPressed(); в FragmentB.

Комментарии (4)

Просто выполните следующие действия:

Всегда при добавлении фрагмента,

fragmentTransaction.add(R.id.fragment_container, detail_fragment, "Fragment_tag").addToBackStack(null).commit();

Затем в основной деятельности, переопределить onBackPressed()

if (getSupportFragmentManager().getBackStackEntryCount() > 0) {
    getSupportFragmentManager().popBackStack();
} else {
    finish();
}

Для обработки кнопки "Назад" в вашем приложении,

Fragment f = getActivity().getSupportFragmentManager().findFragmentByTag("Fragment_tag");
if (f instanceof FragmentName) {
    if (f != null) 
        getActivity().getSupportFragmentManager().beginTransaction().remove(f).commit()               
}

Что's это!

Комментарии (0)