Нажмите кнопку "Назад".
У меня есть некоторые фрагменты в моей деятельности
[1], [2], [3], [4], [5], [6]
И на задней кнопке Нажмите я для возврата из [2] в [1], если текущий активный фрагмент [2] или ничего не делает.
Какова наилучшая практика?
EDIT: приложение не должно возвращаться к [2] из [3]... [6]
Ответы
Ответ 1
Когда вы переходите между фрагментами, вызовите addToBackStack()
как часть вашего FragmentTransaction
:
FragmentTransaction tx = fragmentManager.beginTransation();
tx.replace( R.id.fragment, new MyFragment() ).addToBackStack( "tag" ).commit();
Если вам требуется более подробный контроль (т.е. когда некоторые фрагменты видны, вы хотите отключить обратный ключ), вы можете установить 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;
}
} );
Ответ 2
Я бы предпочел сделать что-то вроде этого:
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();
}
}
Ответ 3
если вы переопределите метод 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;
}
});
Ответ 4
Используйте метод 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();
}
}
Ответ 5
Если вы хотите обрабатывать аппаратное событие 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;
}
});
Работаю очень хорошо для меня.
Ответ 6
Самый лучший способ сделать это можно найти здесь:
Фрагмент: какой обратный вызов вызывается при нажатии кнопки возврата и его настройке
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
}
}
Ответ 7
Создание интерфейсов:
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;
}
}
Ответ 8
@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;
}
});
}
Ответ 9
Или вы можете использовать getSupportFragmentManager().getBackStackEntryCount()
, чтобы проверить, что делать:
@Override
public void onBackPressed() {
logger.d("@@@@@@ back stack entry count : " + getSupportFragmentManager().getBackStackEntryCount());
if (getSupportFragmentManager().getBackStackEntryCount() != 0) {
// only show dialog while there back stack entry
dialog.show(getSupportFragmentManager(), "ConfirmDialogFragment");
} else if (getSupportFragmentManager().getBackStackEntryCount() == 0) {
// or just go back to main activity
super.onBackPressed();
}
}
Ответ 10
Если вы управляете потоком добавления в задний стек каждой транзакции, то вы можете сделать что-то подобное, чтобы показать предыдущий фрагмент, когда пользователь нажимает кнопку "Назад" (вы также можете отобразить домашнюю кнопку).
@Override
public void onBackPressed() {
if (getFragmentManager().getBackStackEntryCount() > 0)
getFragmentManager().popBackStack();
else
super.onBackPressed();
}
Ответ 11
Я работаю с SlidingMenu и Fragment, представляю свое дело здесь и надеюсь, что кто-то поможет.
Логика при нажатии клавиши [Назад]:
- Когда SlidingMenu показывает, закройте его, больше нечего делать.
- Или, когда показывается 2-й (или более) фрагмент, вернитесь назад к предыдущему фрагменту и больше нечего делать.
-
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
}
}
}
Ответ 12
Это очень хорошее и надежное решение: 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;
}
}
Ответ 13
Рабочий код:
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;
}
}
Ответ 14
Я думаю, что самый простой способ - создать интерфейс, а в Activity - проверить, имеет ли этот фрагмент тип интерфейса, и если да, вызовите его метод для обработки pop. Здесь интерфейс для реализации в фрагменте.
public interface BackPressedFragment {
// Note for this to work, name AND tag must be set anytime the fragment is added to back stack, e.g.
// 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();
}
И в вашей деятельности, когда вы обрабатываете поп (вероятно, как в onBackPressed, так и onOptionsItemSelected), поместите стоп-кадр с помощью этого метода:
public void popBackStack() {
FragmentManager fm = getSupportFragmentManager();
// Call current fragment 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();
}
Ответ 15
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;
Ответ 16
Мы создали крошечную библиотеку для обработки обратного нажатия на несколько фрагментов и/или в 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
Ответ 17
Вы можете использовать от getActionBar().setDisplayHomeAsUpEnabled()
:
@Override
public void onBackStackChanged() {
int backStackEntryCount = getFragmentManager().getBackStackEntryCount();
if(backStackEntryCount > 0){
getActionBar().setDisplayHomeAsUpEnabled(true);
}else{
getActionBar().setDisplayHomeAsUpEnabled(false);
}
}
Ответ 18
Добавьте addToBackStack() для фрагментации транзакции, а затем используйте нижеприведенный код для реализации обратной навигации для фрагментов
getSupportFragmentManager().addOnBackStackChangedListener(
new FragmentManager.OnBackStackChangedListener() {
public void onBackStackChanged() {
// Update your UI here.
}
});
Ответ 19
если вы используете FragmentActivity. то сделайте так:
первый вызов Это внутри вашего фрагмента.
public void callParentMethod(){
getActivity().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
...
}
Ответ 20
Добавьте этот код в свою деятельность
@Override
public void onBackPressed() {
if (getFragmentManager().getBackStackEntryCount() == 0) {
super.onBackPressed();
} else {
getFragmentManager().popBackStack();
}
}
И добавьте эту строку в свой фрагмент перед фиксацией()
ft.addToBackStack( "Любое имя" );
Ответ 21
Для тех, кто использует статический фрагмент
В случае, если у вас есть статический фрагмент, это было бы предпочтительнее.
Создайте экземпляр объекта вашего фрагмента
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();
}
}
Ответ 22
в классе фрагмента помещает этот код для обратного события:
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;
}
} );
Ответ 23
Посмотрев на все решения, я понял, что есть гораздо более простое решение.
В вашей деятельности onBackPressed(), на которой размещаются все ваши фрагменты, найдите фрагмент, который вы хотите предотвратить, нажмите. Тогда, если найдено, просто вернитесь. Тогда для этого фрагмента никогда не произойдет popBackStack.
@Override
public void onBackPressed() {
Fragment1 fragment1 = (Fragment1) getFragmentManager().findFragmentByTag("Fragment1");
if (fragment1 != null)
return;
if (getFragmentManager().getBackStackEntryCount() > 0){
getFragmentManager().popBackStack();
}
}
Ответ 24
Проверка работы backstack отлично работает
@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);
}
Ответ 25
В вашем методе 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;
}
});