Android Fragment处理后退按钮按下

时间:2011-11-03 08:54:23

标签: android android-fragments

我的活动中有一些片段

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

在后退按钮按下如果当前活动片段为[2],我必须从[2]返回到[1],否则不执行任何操作。

这样做的最佳做法是什么?

编辑:申请人不得从[3] ... [6]

返回[2]

24 个答案:

答案 0 :(得分:365)

在片段之间进行转换时,请将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;
    }
} );

答案 1 :(得分:256)

我宁愿做这样的事情:

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

答案 2 :(得分:101)

如果您覆盖片段视图的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;
            }
        });

答案 3 :(得分:74)

将一个片段替换为另一个片段时,使用 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();
    }
}

答案 4 :(得分:42)

如果你想要处理硬件Back键事件,而不是你必须在片段的onActivityCreated()方法中执行以下代码。

您还需要检查Action_Down或Action_UP事件。如果你不检查那么onKey()方法会调用2次。

此外,如果您的rootview(getView())不包含焦点,那么它将无法工作。如果您再次单击任何控件,则需要使用getView()将焦点放在rootview上.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;
            }
        });

为我工作得非常好。

答案 5 :(得分:25)

这里可以找到最理想的方法: Fragment: which callback invoked when press back button & customize it

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

答案 6 :(得分:18)

创建界面:

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

}

答案 7 :(得分:10)

e.keycode == '65'

答案 8 :(得分:5)

我们创建了一个小型库,用于处理跨多个片段和/或活动的背压。用法就像在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

答案 9 :(得分:5)

或者您可以使用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();
        }
    }

答案 10 :(得分:4)

如果您管理每个事务添加到后台堆栈的流程,那么您可以执行类似这样的操作,以便在用户按下后退按钮时显示上一个片段(您也可以映射主页按钮)。

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

答案 11 :(得分:4)

工作代码:

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

答案 12 :(得分:4)

我正在使用SlidingMenu和Fragment,在这里展示我的案例并希望帮助某人。

按下[Back]键时的逻辑:

  1. 当SlidingMenu显示时,请关闭它,不再需要做任何事情。
  2. 当第二个(或更多)片段显示时,滑回上一个片段,不再做任何事情。
  3. SlidingMenu未显示,当前片段为#0,原来的[Back]键是否为。

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

答案 13 :(得分:3)

这是一个非常好且可靠的解决方案: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;
    }
}

答案 14 :(得分:3)

我认为最简单的方法是创建一个接口,并在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();
}

在你的Activity中,当你处理pop(可能在onBackPressed和onOptionsItemSelected中)时,使用这个方法弹出backstack:

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

答案 15 :(得分:3)

在查看所有解决方案后,我意识到有一个更简单的解决方案。

在托管所有片段的活动的onBackPressed()中,找到要阻止的片段。然后,如果找到,只需返回。然后popBackStack永远不会发生这个片段。

  @Override
public void onBackPressed() {

        Fragment1 fragment1 = (Fragment1) getFragmentManager().findFragmentByTag(“Fragment1”);
        if (fragment1 != null)
            return;

        if (getFragmentManager().getBackStackEntryCount() > 0){
            getFragmentManager().popBackStack();

        }
}

答案 16 :(得分:3)

#include <stdio.h>

答案 17 :(得分:2)

对于那些使用静态片段的人

如果您有静态片段,那么最好。 制作片段的实例对象

private static MyFragment instance=null;
在MyFragment的onCreate()中初始化该实例

  instance=this;

还创建一个获取Instance

的函数
 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();
    }
}

答案 18 :(得分:1)

如果您正在使用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
  ...
}

答案 19 :(得分:1)

在您的活动中添加此代码

@覆盖

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

在commit()

之前在Fragment中添加此行

ft.addToBackStack(&#34;任何名称&#34;);

答案 20 :(得分:1)

将addToBackStack()添加到片段事务,然后使用下面的代码实现片段的反向导航

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

答案 21 :(得分:1)

片段类中的

将此代码放在后面的事件中:

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

答案 22 :(得分:0)

检查后台堆栈是否完美


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

答案 23 :(得分:-2)

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