it-swarm.com.ru

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

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

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

381
Android_programmer_camera

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

@Override
public void onBackPressed() {

    int count = getSupportFragmentManager().getBackStackEntryCount();

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

}
272
Hw.Master

Я думаю, что лучшее решение

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
        }
    }
}
104
Maxime Jallu

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

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

  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 = ... ;
    //stuff with view
    
        return view;
    }
    

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

91
deadfish

Это сработало для меня: 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;
        }
    });
}
74
Rodrigo Rodrigues

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

Правка: я хотел бы добавить свой предыдущий ответ.

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

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

63
HaMMeReD

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

У фрагментов есть вызов метода onDetach, который сделает эту работу.

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

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

43
Sterling Diaz

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

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

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

22
Rudi

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

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

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

Сначала определите интерфейс

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, вернуть ноль. Мы проверим нулевое значение позже ...

В-третьих, реализовать фрагментарно

Реализуйте интерфейс 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 , что ваше заднее событие было поглощено. В противном случае верните 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();
}

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

Второй вариант - не задействовать действие

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

Создайте абстрактный класс, который расширяет Fragment и реализует интерфейс 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. Убедитесь, что вы вызываете метод Activity onBackPressed(), если все, что вы делаете с кнопкой возврата, не требует обработки, в противном случае кнопка возврата будет инвалид ... а ты этого не хочешь!

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

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

19
mwieczorek

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

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

 /* 
 * called when on back pressed to the current fragment that is returned
 */
 public void onBackPressed()
 {
    // add code in super class when override
 }

2) В вашем классе Activity переопределите onBackPressed следующим образом:

private BaseFragment _currentFragment;

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

3) В классе Your Fragment добавьте нужный код:

 @Override
 public void onBackPressed()
 {
    setUpTitle();
 }
13
IdoT

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

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

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<Fragment> 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<Fragment> list){
    for (int i= list.size()-1;i>=0;i--){
        Fragment frag = list.get(i);
        if (frag != null){
            return frag;
        }
    }
    return null;
}
7
Błażej

onBackPressed() вызывает отсоединение фрагмента от Activity.

Согласно ответу @Sterling Diaz, я думаю, что он прав. НО какая-то ситуация будет неправильной. (напр. поворот экрана)

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

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

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

@Override
public void onDestroyView() {
    super.onDestroyView();
    if(isRemoving()){
        // onBackPressed()
    }
}
7
林奕忠

Это всего лишь небольшой код, который сделает свое дело:

 getActivity().onBackPressed();

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

7
Shahid Sarwar

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

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

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

@Override
public void onDestroyView() {
    super.onDestroyView();
}
6
The Finest Artist

Если вы используете 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

Это очень чисто и нет проблем с интерфейсом/реализацией.

6
Akshat

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

в 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;
    }
});
5
Hamidreza Samadi
@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;
        }
    });
}
4
Gururaj Hosamani

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

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

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

Это оно!

3
Divya

В жизненном цикле действия всегда кнопка Android назад относится к транзакциям FragmentManager, когда мы использовали FragmentActivity или AppCompatActivity.

Для обработки backstack нам не нужно обрабатывать его подсчет backstack или что-то помечать, но мы должны сохранять фокус при добавлении или замене фрагмента. Пожалуйста, найдите следующие фрагменты, чтобы обработать кнопки возврата,

    public void replaceFragment(Fragment fragment) {

        FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();
        if (!(fragment instanceof HomeFragment)) {
            transaction.addToBackStack(null);
        }
        transaction.replace(R.id.activity_menu_fragment_container, fragment).commit();
    }

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

if (!(fragment instanceof HomeFragment)) {
            transaction.addToBackStack(null);
}

Теперь вы можете увидеть ранее добавленный фрагмент на acitvity и приложение выйдет при достижении HomeFragment. Вы также можете посмотреть на следующие фрагменты.

@Override
public void onBackPressed() {

    if (mDrawerLayout.isDrawerOpen(Gravity.LEFT)) {
        closeDrawer();
    } else {
        super.onBackPressed();
    }
}
3
Deva

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

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.

3
Parsania Hardik

Не реализуйте метод ft.addToBackStack (), чтобы при нажатии кнопки "Назад" ваша деятельность была завершена.

proAddAccount = new ProfileAddAccount();
FragmentManager fragmentManager = getSupportFragmentManager();
FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
fragmentTransaction.replace(R.id.fragment_container, proAddAccount);
//fragmentTransaction.addToBackStack(null);
fragmentTransaction.commit();
3
Muhammad Aamir Ali

Согласно примечания к выпуску AndroidX , androidx.activity 1.0.0-alpha01 выпущен и представляет ComponentActivity, новый базовый класс существующих FragmentActivity и AppCompatActivity. И этот релиз приносит нам новую функцию:

Теперь вы можете зарегистрировать OnBackPressedCallback через addOnBackPressedCallback для получения обратных вызовов onBackPressed() без необходимости переопределять метод в своей деятельности.

2
TonnyL

Лучшее решение,

import Android.support.v4.app.Fragment;
import Android.support.v4.app.FragmentManager;
import Android.support.v7.app.AppCompatActivity;

public class BaseActivity extends AppCompatActivity {
    @Override
    public void onBackPressed() {

        FragmentManager fm = getSupportFragmentManager();
        for (Fragment frag : fm.getFragments()) {
            if (frag == null) {
                super.onBackPressed();
                finish();
                return;
            }
            if (frag.isVisible()) {
                FragmentManager childFm = frag.getChildFragmentManager();
                if (childFm.getFragments() == null) {
                    super.onBackPressed();
                    finish();
                    return;
                }
                if (childFm.getBackStackEntryCount() > 0) {
                    childFm.popBackStack();
                    return;
                }
                else {

                    fm.popBackStack();
                    if (fm.getFragments().size() <= 1) {
                        finish();
                    }
                    return;
                }

            }
        }
    }
}
2
Shervin Gharib

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

В своей активности задайте OnPageChangeListener для ViewPager, чтобы вы знали, когда пользователь находится во второй активности. Если он во втором задании, создайте логическое true следующим образом:

    mSectionsPagerAdapter = new SectionsPagerAdapter(getSupportFragmentManager());
    // Set up the ViewPager with the sections adapter.
    mViewPager = (ViewPager) findViewById(R.id.pager);
    mViewPager.setAdapter(mSectionsPagerAdapter);
    mViewPager.setCurrentItem(0);
    mViewPager.addOnPageChangeListener(new OnPageChangeListener() {

        @Override
        public void onPageSelected(int position) {
            // TODO Auto-generated method stub
                mSectionsPagerAdapter.instantiateItem(mViewPager, position);
                if(position == 1)
                    inAnalytics = true;
                else if(position == 0)
                    inAnalytics = false;
        }

        @Override
        public void onPageScrolled(int position, float arg1, int arg2) {
            // TODO Auto-generated method stub
        }

        @Override
        public void onPageScrollStateChanged(int arg0) {
            // TODO Auto-generated method stub

        }
    });

Теперь проверяйте логическое значение при каждом нажатии кнопки "Назад" и установите текущий элемент на свой первый фрагмент:

@Override
public void onBackPressed() {
    if(inAnalytics)
        mViewPager.setCurrentItem(0, true);
    else 
        super.onBackPressed();
}
1
zeeshan khan

Хорошо, ребята, я наконец-то нашел хорошее решение.

В вашем onCreate () в вашей деятельности, где содержатся ваши фрагменты, добавьте прослушиватель изменений в backstack следующим образом:

    fragmentManager.addOnBackStackChangedListener(new FragmentManager.OnBackStackChangedListener() {
        @Override
        public void onBackStackChanged() {
            List<Fragment> f = fragmentManager.getFragments();
            //List<Fragment> f only returns one value
            Fragment frag = f.get(0);
            currentFragment = frag.getClass().getSimpleName();
        }
    });

(Кроме того, добавление моего fragmenManager объявлено в действиях O. Теперь при каждом изменении фрагмента текущий фрагмент String становится именем текущего фрагмента. Затем в действиях onBackPressed () вы можете управлять действиями кнопки "Назад" следующим образом:

    @Override
    public void onBackPressed() {

    switch (currentFragment) {
        case "FragmentOne":
            // your code here
            return;
        case "FragmentTwo":
            // your code here
            return;
        default:
            fragmentManager.popBackStack();
            // default action for any other fragment (return to previous)
    }

}

Я могу подтвердить, что этот метод работает для меня.

1
Haider Malik

Вы можете зарегистрировать фрагмент в действии, чтобы справиться с прессой:

interface BackPressRegistrar {
    fun registerHandler(handler: BackPressHandler)
    fun unregisterHandler(handler: BackPressHandler)
}

interface BackPressHandler {
    fun onBackPressed(): Boolean
}

использование:

Во фрагменте:

private val backPressHandler = object : BackPressHandler {
    override fun onBackPressed(): Boolean {
        showClosingWarning()
        return false
    }
}

override fun onResume() {
    super.onResume()
    (activity as? BackPressRegistrar)?.registerHandler(backPressHandler)
}

override fun onStop() {
    (activity as? BackPressRegistrar)?.unregisterHandler(backPressHandler)
    super.onStop()
}

В деятельности:

class MainActivity : AppCompatActivity(), BackPressRegistrar {


    private var registeredHandler: BackPressHandler? = null
    override fun registerHandler(handler: BackPressHandler) { registeredHandler = handler }
    override fun unregisterHandler(handler: BackPressHandler) { registeredHandler = null }

    override fun onBackPressed() {
        if (registeredHandler?.onBackPressed() != false) super.onBackPressed()
    }
}
1
Francis

Это просто, если у вас есть действие A и вы делаете 3 фрагмента, таких как B, C и D. Теперь, если вы находитесь во фрагменте B или C и onBackPressed, вы хотите перемещаться во фрагмент D каждый раз. Затем вам нужно просто переопределить функцию onBackPressed() метод в основной Деятельности A, а также когда вы переходите к любому фрагменту, затем передаете TAG или name того фрагмента, по которому вы распознали этот фрагмент в основной Деятельности A.

Я привожу пример того, с помощью которого вы можете легко понять это ....

if (savedInstanceState == null) {

   getSupportFragmentManager().beginTransaction().add(R.id.container, new C_fragment(),"xyz").commit();

}

или если вы переходите от фрагмента B к фрагменту C .. и при повторном нажатии вы хотите перейти на фрагмент D ... как показано ниже

btn.setOnClickListener(new View.OnClickListener() {

    @Override
    public void onClick(View view) {

        getActivity().getSupportFragmentManager().beginTransaction().add(R.id.container, new C_frament(), "xyz").commit();
        ((ActionBarActivity) getActivity()).getSupportActionBar().setTitle("Fragment C");
    }
});

Теперь вам нужно просто переопределить метод onBackPressed () в основной деятельности .... как показано ниже ..

@Override
public void onBackPressed() {
    FragmentManager fragmentManager =getSupportFragmentManager();
    if (((C_fragment) getSupportFragmentManager().findFragmentByTag("xyz")) != null && ((C_fragment) getSupportFragmentManager().findFragmentByTag("xyz")).isVisible()) {
        Fragment fragment = new D_Fragment();
        fragmentManager.beginTransaction().replace(R.id.container, fragment).commit();
        getSupportActionBar().setTitle("D fragment ");
    } else {
        super.onBackPressed();
    }
}
1
Abhishek Raghuvanshi

Я использовал другой подход следующим образом:

  • Шина событий Отто для связи между Деятельностью и ее Фрагментами
  • Стек в Деятельности, содержащий пользовательские обратные действия, завернутые в Runnable, который определяет вызывающий фрагмент
  • Когда onBackPressed вызывается в управляющей операции, он вызывает самое последнее пользовательское обратное действие и выполняет свое Runnable. Если в стеке ничего нет, вызывается значение по умолчанию super.onBackPressed()

Полный подход с примером кода включен здесь в качестве ответа на этот другой SO вопрос .

1
aoemerson

открытый класс MyActivity расширяет 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;
}

}
1
joelvarma

на mainActivity

protected DrawerHomeActivity.OnBackPressedListener onBackPressedListener;

public interface OnBackPressedListener {
    void doBack();
}

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

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


    }
    else
        super.onBackPressed();



}

на фрагменте осуществляют базовую активность/фрагмент, подобный

implements DrawerHomeActivity.OnBackPressedListener

DraweHomeActivity моя основная деятельность написать

((DrawerHomeActivity) getActivity()).setOnBackPressedListener(this);

и создать метод doBack

@Override
public void doBack() {
    //call base fragment 
    }
0
Mahesh Pandit

Просто сделайте это в onKeyUp ():

@Override
public boolean onKeyUp(int keyCode, KeyEvent event) {

    if (keyCode == KeyEvent.KEYCODE_BACK) {
        // do something
        return true;  // return true if back handled, false otherwise
    }

    return super.onKeyUp(keyCode, event);
}
0
b0b

У меня была та же проблема, и я создал для нее нового слушателя и использовал его в своих фрагментах.

1 - Ваша деятельность должна иметь интерфейс слушателя и список слушателей в нем

2 - Вы должны реализовать методы для добавления и удаления слушателей

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

public class MainActivity ... {

    /**
     * Back press listener list. Used for notifying fragments when onBackPressed called
     */
    private Stack<BackPressListener> backPressListeners = new Stack<BackPressListener>();


    ...

    /**
     * Adding new listener to back press listener stack
     * @param backPressListener
     */
    public void addBackPressListener(BackPressListener backPressListener) {
        backPressListeners.add(backPressListener);
    }

    /**
     * Removing the listener from back press listener stack
     * @param backPressListener
     */
    public void removeBackPressListener(BackPressListener backPressListener) {
        backPressListeners.remove(backPressListener);
    }


    // Overriding onBackPressed to check that is there any listener using this back press
    @Override
    public void onBackPressed() {

        // checks if is there any back press listeners use this press
        for(BackPressListener backPressListener : backPressListeners) {
            if(backPressListener.onBackPressed()) return;
        }

        // if not returns in the loop, calls super onBackPressed
        super.onBackPressed();
    }

}

4 - Ваш фрагмент должен реализовывать интерфейс для обратной печати

5 - Вам необходимо добавить фрагмент в качестве прослушивателя для повторного нажатия

6 - Вы должны вернуть true из onBackPressed, если фрагмент использует эту обратную печать

7 - ВАЖНО - Вы должны удалить фрагмент из списка на Дестрой

public class MyFragment extends Fragment implements MainActivity.BackPressListener {


    ...

    @Override
    public void onAttach(Activity activity) {
        super.onCreate(savedInstanceState);

        // adding the fragment to listener list
        ((MainActivity) activity).addBackPressListener(this);
    }

    ...

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

        // removing the fragment from the listener list
        ((MainActivity) getActivity()).removeBackPressListener(this);
    }

    ...

    @Override
    public boolean onBackPressed() {

        // you should check that if this fragment is the currently used fragment or not
        // if this fragment is not used at the moment you should return false
        if(!isThisFragmentVisibleAtTheMoment) return false;

        if (isThisFragmentUsingBackPress) {
            // do what you need to do
            return true;
        }
        return false;
    }
}

Вместо ArrayList используется стек, чтобы можно было начинать с последнего фрагмента. Также может возникнуть проблема при добавлении фрагментов в задний стек. Таким образом, вы должны проверить, что фрагмент виден или нет при использовании обратного нажатия. В противном случае один из фрагментов будет использовать событие, а последний фрагмент не будет закрыт при обратном нажатии.

Я надеюсь, что это решает проблему для всех.

0
eluleci

Простой способ обработки onBackPressed () во фрагментах

Шаг 1: Создание статического логического значения в действии.

public static Fragment_one;

Шаг 2: On MainActivity (действие, содержащее фрагмент) в методе On Create, объявить

Fragment_one=true;

Шаг 3: Переопределить onBackPressed () в MainActivity

@Override
public void onBackPressed() {

    if(Fragment_one) {
     //Back key pressed on fragment one

    }else {
      //Back key pressed on fragment two
    }
}

Шаг 4: В фрагменте метод onCreateView объявляет

MainActivity.Fragment_one=true;

Шаг 5 В методе frag_two onCreateView объявить

MainActivity.Fragment_one=false;

Примечание: Этот метод может быть применим только к двум фрагментам.

0
Elaiya

Fragment: Сделать BaseFragment, разместив метод:

 public boolean onBackPressed();

активность:

@Override
public void onBackPressed() {
    List<Fragment> fragments = getSupportFragmentManager().getFragments();
    if (fragments != null) {
        for (Fragment fragment : fragments) {
            if (!fragment.isVisible()) continue;

            if (fragment instanceof BaseFragment && ((BaseFragment) fragment).onBackPressed()) {
                return;
            }
        }
    }

    super.onBackPressed();
}

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

0
Alécio Carvalho