Кнопка обратного вызова кнопки Android Fragment

У меня есть некоторые фрагменты в моей деятельности

[1], [2], [3], [4], [5], [6] 

И на кнопке Back Button Нажмите I, чтобы вернуться из [2] в [1], если текущий активный фрагмент [2] или ничего не делать.

Какова наилучшая практика?

EDIT : приложение не должно возвращаться к [2] из [3] … [6]

Когда вы переходите между фрагментами, вызовите addToBackStack() как часть вашего FragmentTransaction :

 FragmentTransaction tx = fragmentManager.beginTransation(); tx.replace( R.id.fragment, new MyFragment() ).addToBackStack( "tag" ).commit(); 

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

 //You need to add the following line for this solution to work; thanks skayred fragment.getView().setFocusableInTouchMode(true); fragment.getView().requestFocus(); fragment.getView().setOnKeyListener( new OnKeyListener() { @Override public boolean onKey( View v, int keyCode, KeyEvent event ) { if( keyCode == KeyEvent.KEYCODE_BACK ) { return true; } return false; } } ); 

Я бы предпочел сделать что-то вроде этого:

 private final static String TAG_FRAGMENT = "TAG_FRAGMENT"; private void showFragment() { final Myfragment fragment = new MyFragment(); final FragmentTransaction transaction = getSupportFragmentManager().beginTransaction(); transaction.replace(R.id.fragment, fragment, TAG_FRAGMENT); transaction.addToBackStack(null); transaction.commit(); } @Override public void onBackPressed() { final Myfragment fragment = (Myfragment) getSupportFragmentManager().findFragmentByTag(TAG_FRAGMENT); if (fragment.allowBackPressed()) { // and then you define a method allowBackPressed with the logic to allow back pressed or not super.onBackPressed(); } } 

Если вы переопределите метод onKey для просмотра фрагмента, который вам понадобится:

  view.setFocusableInTouchMode(true); view.requestFocus(); view.setOnKeyListener(new View.OnKeyListener() { @Override public boolean onKey(View v, int keyCode, KeyEvent event) { Log.i(tag, "keyCode: " + keyCode); if( keyCode == KeyEvent.KEYCODE_BACK && event.getAction() == KeyEvent.ACTION_UP) { Log.i(tag, "onKey Back listener is working!!!"); getFragmentManager().popBackStack(null, FragmentManager.POP_BACK_STACK_INCLUSIVE); return true; } return false; } }); 

Используйте метод addToBackStack при замене одного фрагмента на другой:

 getFragmentManager().beginTransaction().replace(R.id.content_frame, fragment).addToBackStack("my_fragment").commit(); 

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

 @Override public void onBackPressed() { if (getFragmentManager().getBackStackEntryCount() > 0) { getFragmentManager().popBackStack(); } else { super.onBackPressed(); } } 

Если вы хотите обрабатывать аппаратное событие Back key, то вам нужно сделать следующий код в методе onActivityCreated () для фрагмента.

Вам также необходимо проверить событие Action_Down или Action_UP. Если вы не будете проверять, то методKey () вызовет 2 раза.

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

 getView().setFocusableInTouchMode(true); getView().requestFocus(); getView().setOnKeyListener(new OnKeyListener() { @Override public boolean onKey(View v, int keyCode, KeyEvent event) { if (event.getAction() == KeyEvent.ACTION_DOWN) { if (keyCode == KeyEvent.KEYCODE_BACK) { Toast.makeText(getActivity(), "Back Pressed", Toast.LENGTH_SHORT).show(); return true; } } return false; } }); 

Очень хорошо работает для меня.

Самый лучший способ сделать это можно найти здесь: Фрагмент: какой обратный вызов вызывается при нажатии кнопки возврата и его настройке

 public class MyActivity extends Activity { //... //Defined in Activity class, so override @Override public void onBackPressed() { super.onBackPressed(); myFragment.onBackPressed(); } } public class MyFragment extends Fragment { //Your created method public static void onBackPressed() { //Pop Fragments off backstack and do your other checks } } 

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

BackButtonHandlerInterface

 public interface BackButtonHandlerInterface { void addBackClickListener (OnBackClickListener onBackClickListener); void removeBackClickListener (OnBackClickListener onBackClickListener); } 

OnBackClickListener

 public interface OnBackClickListener { boolean onBackClick(); } 

В работе :

 public class MainActivity extends AppCompatActivity implements BackButtonHandlerInterface { private ArrayList<WeakReference<OnBackClickListener>> backClickListenersList = new ArrayList<>(); @Override public void addBackClickListener(OnBackClickListener onBackClickListener) { backClickListenersList.add(new WeakReference<>(onBackClickListener)); } @Override public void removeBackClickListener(OnBackClickListener onBackClickListener) { for (Iterator<WeakReference<OnBackClickListener>> iterator = backClickListenersList.iterator(); iterator.hasNext();){ WeakReference<OnBackClickListener> weakRef = iterator.next(); if (weakRef.get() == onBackClickListener){ iterator.remove(); } } } @Override public void onBackPressed() { if(!fragmentsBackKeyIntercept()){ super.onBackPressed(); } } private boolean fragmentsBackKeyIntercept() { boolean isIntercept = false; for (WeakReference<OnBackClickListener> weakRef : backClickListenersList) { OnBackClickListener onBackClickListener = weakRef.get(); if (onBackClickListener != null) { boolean isFragmIntercept = onBackClickListener.onBackClick(); if (!isIntercept) isIntercept = isFragmIntercept; } } return isIntercept; } } 

В фрагменте :

 public class MyFragment extends Fragment implements OnBackClickListener{ private BackButtonHandlerInterface backButtonHandler; @Override public void onAttach(Activity activity) { super.onAttach(activity); backButtonHandler = (BackButtonHandlerInterface) activity; backButtonHandler.addBackClickListener(this); } @Override public void onDetach() { super.onDetach(); backButtonHandler.removeBackClickListener(this); backButtonHandler = null; } @Override public boolean onBackClick() { //This method handle onBackPressed()! return true or false return false; } } 

  @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){ if (mDrawerLayout.isDrawerOpen(GravityCompat.START)){ mDrawerLayout.closeDrawer(GravityCompat.START); } return true; } return false; } }); } 

Или вы можете использовать getSupportFragmentManager().getBackStackEntryCount() чтобы проверить, что делать:

 @Override public void onBackPressed() { logger.d("@@@@@@ back stack entry count : " + getSupportFragmentManager().getBackStackEntryCount()); if (getSupportFragmentManager().getBackStackEntryCount() != 0) { // only show dialog while there's back stack entry dialog.show(getSupportFragmentManager(), "ConfirmDialogFragment"); } else if (getSupportFragmentManager().getBackStackEntryCount() == 0) { // or just go back to main activity super.onBackPressed(); } } 

Если вы управляете потоком добавления в задний стек каждой транзакции, вы можете сделать что-то подобное, чтобы показать предыдущий фрагмент, когда пользователь нажимает кнопку «назад» (вы также можете нанести кнопку «домой»).

 @Override public void onBackPressed() { if (getFragmentManager().getBackStackEntryCount() > 0) getFragmentManager().popBackStack(); else super.onBackPressed(); } 

Я работаю с SlidingMenu и Fragment, представляю здесь свое дело и надеюсь, что кто-то поможет.

Логика при нажатии клавиши [Назад]:

  1. Когда SlidingMenu показывает, закройте его, больше нечего делать.
  2. Или когда отображается 2-й (или более) фрагмент, вернитесь назад к предыдущему фрагменту и больше нечего делать.
  3. SlidingMenu не показывает, текущий фрагмент равен # 0, делает ли исходная клавиша [Назад].

     public class Main extends SherlockFragmentActivity { private SlidingMenu menu=null; Constants.VP=new ViewPager(this); //Some stuff... @Override public void onBackPressed() { if(menu.isMenuShowing()) { menu.showContent(true); //Close SlidingMenu when menu showing return; } else { int page=Constants.VP.getCurrentItem(); if(page>0) { Constants.VP.setCurrentItem(page-1, true); //Show previous fragment until Fragment#0 return; } else {super.onBackPressed();} //If SlidingMenu is not showing and current Fragment is #0, do the original [Back] key does. In my case is exit from APP } } } 

Это очень хорошее и надежное решение: http://vinsol.com/blog/2014/10/01/handling-back-button-press-inside-fragments/

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

Для некоторых из вас есть, может быть, небольшой недостаток в абстрактном классе …

Вскоре решение из этой ссылки выглядит следующим образом:

 // Abstract Fragment handling the back presses public abstract class BackHandledFragment extends Fragment { protected BackHandlerInterface backHandlerInterface; public abstract String getTagText(); public abstract boolean onBackPressed(); @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); if(!(getActivity() instanceof BackHandlerInterface)) { throw new ClassCastException("Hosting activity must implement BackHandlerInterface"); } else { backHandlerInterface = (BackHandlerInterface) getActivity(); } } @Override public void onStart() { super.onStart(); // Mark this fragment as the selected Fragment. backHandlerInterface.setSelectedFragment(this); } public interface BackHandlerInterface { public void setSelectedFragment(BackHandledFragment backHandledFragment); } } 

И использование в деятельности:

 // BASIC ACTIVITY CODE THAT LETS ITS FRAGMENT UTILIZE onBackPress EVENTS // IN AN ADAPTIVE AND ORGANIZED PATTERN USING BackHandledFragment public class TheActivity extends FragmentActivity implements BackHandlerInterface { private BackHandledFragment selectedFragment; @Override public void onBackPressed() { if(selectedFragment == null || !selectedFragment.onBackPressed()) { // Selected fragment did not consume the back press event. super.onBackPressed(); } } @Override public void setSelectedFragment(BackHandledFragment selectedFragment) { this.selectedFragment = selectedFragment; } } 

Рабочий код:

 package com.example.keralapolice; import android.app.Fragment; import android.app.FragmentManager; import android.app.FragmentManager.OnBackStackChangedListener; import android.content.Intent; import android.os.Bundle; import android.util.Log; import android.view.Gravity; import android.view.KeyEvent; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.widget.Toast; public class ChiefFragment extends Fragment { View view; // public OnBackPressedListener onBackPressedListener; @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle args) { view = inflater.inflate(R.layout.activity_chief, container, false); getActivity().getActionBar().hide(); view.setFocusableInTouchMode(true); view.requestFocus(); view.setOnKeyListener(new View.OnKeyListener() { @Override public boolean onKey(View v, int keyCode, KeyEvent event) { Log.i(getTag(), "keyCode: " + keyCode); if (keyCode == KeyEvent.KEYCODE_BACK) { getActivity().getActionBar().show(); Log.i(getTag(), "onKey Back listener is working!!!"); getFragmentManager().popBackStack(null, FragmentManager.POP_BACK_STACK_INCLUSIVE); // String cameback="CameBack"; Intent i = new Intent(getActivity(), home.class); // i.putExtra("Comingback", cameback); startActivity(i); return true; } else { return false; } } }); return view; } } 

Я думаю, что самый простой способ – создать интерфейс, а в Activity – проверить, имеет ли фрагмент тип интерфейса, и если да, вызовите его метод для обработки pop. Вот интерфейс для реализации в фрагменте.

 public interface BackPressedFragment { // Note for this to work, name AND tag must be set anytime the fragment is added to back stack, eg // getActivity().getSupportFragmentManager().beginTransaction() // .replace(R.id.fragment_container, MyFragment.newInstance(), "MY_FRAG_TAG") // .addToBackStack("MY_FRAG_TAG") // .commit(); // This is really an override. Should call popBackStack itself. void onPopBackStack(); } 

Вот как это реализовать.

 public class MyFragment extends Fragment implements BackPressedFragment @Override public void onPopBackStack() { /* Your code goes here, do anything you want. */ getActivity().getSupportFragmentManager().popBackStack(); } 

И в вашей деятельности, когда вы обрабатываете pop (вероятно, и в onBackPressed, и onOptionsItemSelected), вы можете использовать эту функцию:

 public void popBackStack() { FragmentManager fm = getSupportFragmentManager(); // Call current fragment's onPopBackStack if it has one. String fragmentTag = fm.getBackStackEntryAt(fm.getBackStackEntryCount() - 1).getName(); Fragment currentFragment = getSupportFragmentManager().findFragmentByTag(fragmentTag); if (currentFragment instanceof BackPressedFragment) ((BackPressedFragment)currentFragment).onPopBackStack(); else fm.popBackStack(); } 

Вы можете использовать getActionBar().setDisplayHomeAsUpEnabled() :

 @Override public void onBackStackChanged() { int backStackEntryCount = getFragmentManager().getBackStackEntryCount(); if(backStackEntryCount > 0){ getActionBar().setDisplayHomeAsUpEnabled(true); }else{ getActionBar().setDisplayHomeAsUpEnabled(false); } } 
  rootView.setFocusableInTouchMode(true); rootView.requestFocus(); rootView.setOnKeyListener(new View.OnKeyListener() { @Override public boolean onKey(View v, int keyCode, KeyEvent event) { if (keyCode == KeyEvent.KEYCODE_BACK) { Fragment NameofFragment = new NameofFragment; FragmentTransaction transaction=getFragmentManager().beginTransaction(); transaction.replace(R.id.frame_container,NameofFragment); transaction.commit(); return true; } return false; } }); return rootView; 

Мы создали крошечную библиотеку для обработки обратного нажатия на несколько фрагментов и / или в Activity. Использование так же просто, как добавление зависимости в вашем файле gradle:

 compile 'net.skoumal.fragmentback:fragment-back:0.1.0' 

Пусть ваш фрагмент реализует интерфейс BackFragment :

 public abstract class MyFragment extends Fragment implements BackFragment { public boolean onBackPressed() { // -- your code -- // return true if you want to consume back-pressed event return false; } public int getBackPriority() { return NORMAL_BACK_PRIORITY; } } 

Сообщите своим фрагментам о задних прессах:

 public class MainActivity extends AppCompatActivity { @Override public void onBackPressed() { // first ask your fragments to handle back-pressed event if(!BackFragmentHelper.fireOnBackPressedEvent(this)) { // lets do the default back action if fragments don't consume it super.onBackPressed(); } } } 

Для получения дополнительной информации и других вариантов использования посетите страницу GitHub:

https://github.com/skoumalcz/fragment-back

Добавьте addToBackStack () для фрагментации транзакции, а затем используйте нижеприведенный код для реализации обратной навигации для фрагментов

 getSupportFragmentManager().addOnBackStackChangedListener( new FragmentManager.OnBackStackChangedListener() { public void onBackStackChanged() { // Update your UI here. } }); 

Если вы используете FragmentActivity. Тогда сделайте так

Первый вызов Это внутри вашего фрагмента.

 public void callParentMethod(){ getActivity().onBackPressed(); } 

А затем onBackPressed метод onBackPressed в сторону вашего родительского класса FragmentActivity .

 @Override public void onBackPressed() { //super.onBackPressed(); //create a dialog to ask yes no question whether or not the user wants to exit ... } 

Добавьте этот код в свою активность

@Override

 public void onBackPressed() { if (getFragmentManager().getBackStackEntryCount() == 0) { super.onBackPressed(); } else { getFragmentManager().popBackStack(); } } 

И добавьте эту строку в свой фрагмент перед фиксацией ()

Ft.addToBackStack («Любое имя»);

Для тех, кто использует статический фрагмент

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

 private static MyFragment instance=null; 

В onCreate () MyFragment инициализирует этот экземпляр

  instance=this; 

Также сделать функцию, чтобы получить экземпляр

  public static MyFragment getInstance(){ return instance; } 

Также выполняют функции

 public boolean allowBackPressed(){ if(allowBack==true){ return true; } return false; } //allowBack is a boolean variable that will be set to true at the action //where you want that your backButton should not close activity. In my case I open //Navigation Drawer then I set it to true. so when I press backbutton my //drawer should be get closed public void performSomeAction(){ //.. Your code ///Here I have closed my drawer } 

В вашей деятельности вы можете сделать

 @Override public void onBackPressed() { if (MyFragment.getInstance().allowBackPressed()) { MyFragment.getInstance().performSomeAction(); } else{ super.onBackPressed(); } } 

В классе фрагмента введите этот код для обратного события:

  rootView.setFocusableInTouchMode(true); rootView.requestFocus(); rootView.setOnKeyListener( new OnKeyListener() { @Override public boolean onKey( View v, int keyCode, KeyEvent event ) { if( keyCode == KeyEvent.KEYCODE_BACK ) { FragmentManager fragmentManager = getFragmentManager(); fragmentManager.beginTransaction() .replace(R.id.frame_container, new Book_service_provider()).commit(); return true; } return false; } } ); 

Посмотрев на все решения, я понял, что есть гораздо более простое решение.

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

  @Override public void onBackPressed() { Fragment1 fragment1 = (Fragment1) getFragmentManager().findFragmentByTag(“Fragment1”); if (fragment1 != null) return; if (getFragmentManager().getBackStackEntryCount() > 0){ getFragmentManager().popBackStack(); } } 

Проверка стоп-кадра работает отлично


 @Override public boolean onKeyDown(int keyCode, KeyEvent event) { if (keyCode == KeyEvent.KEYCODE_BACK) { if (getFragmentManager().getBackStackEntryCount() == 1) { // DO something here since there is only one fragment left // Popping a dialog asking to quit the application return false; } } return super.onKeyDown(keyCode, event); } 

В вашем методе oncreateView () вам нужно написать этот код, а в KEYCODE_BACk вы можете написать любую функциональность, которую вы хотите

 View v = inflater.inflate(R.layout.xyz, container, false); //Back pressed Logic for fragment v.setFocusableInTouchMode(true); v.requestFocus(); v.setOnKeyListener(new View.OnKeyListener() { @Override public boolean onKey(View v, int keyCode, KeyEvent event) { if (event.getAction() == KeyEvent.ACTION_DOWN) { if (keyCode == KeyEvent.KEYCODE_BACK) { getActivity().finish(); Intent intent = new Intent(getActivity(), MainActivity.class); startActivity(intent); return true; } } return false; } });