Как реализовать onBackPressed () во фрагментах? - PullRequest
391 голосов
/ 27 марта 2011

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

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

Ответы [ 40 ]

3 голосов
/ 07 ноября 2018

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

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

3 голосов
/ 07 мая 2017

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

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

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

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

@Override
public void onBackPressed() {

    if (mDrawerLayout.isDrawerOpen(Gravity.LEFT)) {
        closeDrawer();
    } else {
        super.onBackPressed();
    }
}
2 голосов
/ 19 апреля 2019

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

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

interface BackPressHandler {
    fun onBackPressed(): Boolean
}

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

In Fragment:

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

InАктивность:

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()
    }
}
2 голосов
/ 10 августа 2016

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

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

            }
        }
    }
}
1 голос
/ 23 ноября 2015

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

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

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

1 голос
/ 04 мая 2015

Это просто, если у вас есть задание A и вы делаете 3 фрагмента, таких как B, C и D. Теперь, если вы находитесь во фрагменте B или C и onBackPressed, вы хотите переходить на фрагмент D каждый раз.просто переопределить метод onBackPressed() в основном упражнении A, а также при переходе к любому фрагменту затем передать TAG или имя того фрагмента, по которому вы узнали этот фрагмент в основном упражнении 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 голос
/ 02 августа 2016

открытый класс 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.

1 голос
/ 08 июля 2018

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

В вашем 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 голос
/ 13 сентября 2018

Просто сделайте это в 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);
}
1 голос
/ 31 мая 2016

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

В своем действии установите 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();
}
...