@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;
}
});
}
37
我认为最好的解决方案是
JAVA SOLUTION
创建简单的界面:
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;
}
}
}
KOTLIN SOLUTION
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
}
}
}
我创建了一个返回的方法后堆栈中的最后一个 Fragment 对象 . 我使用标签...如果您使用ID 's, make the necessary changes. I have this static method in a utility class that deals with navigation states, etc... but of course, put it where it best suits you. For edification, I' ve将我的名字放在一个名为 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;
}
@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();
}
public class FragmentChannels extends BackableFragment {
...
@Override
public void onBackButtonPressed() {
if (doTheThingRequiringBackButtonOverride) {
// do the thing
} else {
getActivity().onBackPressed();
}
}
...
}
Fragment f = getActivity().getSupportFragmentManager().findFragmentByTag("Fragment_tag");
if (f instanceof FragmentName) {
if (f != null)
getActivity().getSupportFragmentManager().beginTransaction().remove(f).commit()
}
而已!
251
好吧,我这样做了,它对我有用
简单的界面
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;
}
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();
}
}
1
如果您使用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();
}
在您的Activity类中,您可以定义:
@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对象
这是超级干净的,没有接口/实现麻烦 .
13
使用onDestroyView()怎么样?
@Override
public void onDestroyView() {
super.onDestroyView();
}
0
这只是一个小代码,可以解决这个问题:
getActivity().onBackPressed();
希望它可以帮助别人:)
2
这是我的解决方案:
在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;
}
});
7
@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;
}
});
}
Fragment duedateFrag = new FragmentB();
FragmentTransaction ft = getFragmentManager().beginTransaction();
ft.replace(R.id.container_body, duedateFrag);
ft.addToBackStack(null);
ft.commit();
@Override
public void onBackPressed() {
if (mDrawerLayout.isDrawerOpen(Gravity.LEFT)) {
closeDrawer();
} else {
super.onBackPressed();
}
}
1
它很简单,如果你有一个活动A并且你制作了3个片段,如B,C和D.Now如果你在片段B或C和 onBackPressed 你想每次都在片段D上移动 . 那么你必须只是覆盖 onBackPressed() 主Activity A中的方法,当你跳转到任何片段然后传递该片段的 TAG or name 时,您通过该片段识别主Activity 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();
}
}
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();
}
});
@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)
}
}
我可以确认这种方法适合我 .
0
我有同样的问题,我为它创建了一个新的监听器,并在我的片段中使用 .
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 - 如果片段使用此反压,则应从onBackPressed返回true
7 - 重要 - 您必须从列表onDestroy中删除该片段
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;
}
}
30 回答
我以这种方式解决了在Activity中覆盖
onBackPressed
的问题 . 在提交之前FragmentTransaction
都是addToBackStack
:根据@HaMMeRed的回答,这里是伪代码应该如何工作 . 假设您的主要活动名为
BaseActivity
,它具有子片段(如SlidingMenu lib示例中所示) . 以下是步骤:首先我们需要创建接口和类来实现其接口以具有泛型方法
OnBackPressedListener
OnBackPressedListener
技能的类从现在开始,我们将处理我们的代码
BaseActivity
及其片段在 class 上创建私人监听器
BaseActivity
BaseActivity
中设置监听器onBackPressed
实现类似的东西在
onCreateView
的片段中瞧,现在当你点击片段时,你应该 grab 你的自定义背面方法 .
这对我有用:https://stackoverflow.com/a/27145007/3934111
我认为最好的解决方案是
JAVA SOLUTION
创建简单的界面:
在你的活动中
最后在你的片段中:
KOTLIN SOLUTION
1 - 创建界面
2 - 准备您的活动
3 - 在目标片段中实施
如果您想要这种功能,则需要在活动中覆盖它,然后在所有片段中添加
YourBackPressed
接口,只要按下后退按钮,就会调用相关片段 .编辑:我想追加我之前的回答 .
如果我今天要这样做,我会使用广播,或者如果我希望其他面板同时更新到主/主内容面板,则可以使用有序广播 .
支持库中的LocalBroadcastManager可以为此提供帮助,您只需在
onBackPressed
中发送广播并订阅您关注的片段 . 我认为Messaging是一个更加分离的实现,并且可以更好地扩展,所以它现在是我的官方实现建议 . 只需使用Intent
的操作作为邮件的过滤器 . 发送新创建的ACTION_BACK_PRESSED
,从您的活动中发送它并在相关片段中收听它 .这些都不容易实现,也不会以最佳方式运行 .
片段有一个方法调用onDetach来完成这项工作 .
这将是工作 .
只需在您的片段之间转换时添加
addToBackStack
,如下所示:如果您编写
addToBackStack(null)
,它将自行处理它,但如果您提供标记,则应手动处理 .由于这个问题和一些答案已经超过五年了,让我分享一下我的解决方案 . 这是对@oyenigun的回答的后续和现代化
UPDATE: 在本文的底部,我添加了一个使用抽象Fragment扩展的替代实现,它根本不涉及Activity,这对于任何具有更复杂的片段层次结构的人来说都是有用的,这些片段层次结构涉及需要不同反向行为的嵌套片段 .
我需要实现这个,因为我使用的一些片段具有较小的视图,我想用后退按钮解除,例如弹出的小信息视图等,但这对于需要覆盖行为的任何人都有好处 . 片段内的后退按钮 .
First, define an Interface
这个接口,我称之为
Backable
(我是命名约定的坚持者),它有一个必须返回boolean
值的方法onBackPressed()
. 我们需要强制执行一个布尔值,因为我们需要知道后退按钮是否有"absorbed"返回事件 . 返回true
表示它有,并且不需要进一步操作,否则,false
表示仍然必须执行默认的后退操作 . 该接口应该是它自己的文件(最好是在一个名为interfaces
的独立包中) . 请记住,将类分成包是很好的做法 .Second, find the top fragment
我创建了一个返回的方法后堆栈中的最后一个
Fragment
对象 . 我使用标签...如果您使用ID 's, make the necessary changes. I have this static method in a utility class that deals with navigation states, etc... but of course, put it where it best suits you. For edification, I' ve将我的名字放在一个名为NavUtils
的类中 .确保后堆栈计数大于0,否则可能会在运行时抛出
ArrayOutOfBoundsException
. 如果它不是't greater than 0, return null. We' ll稍后检查一个空值...Third, Implement in a Fragment
在需要覆盖后退按钮行为的任何片段中实现
Backable
接口 . 添加实现方法 .在
onBackPressed()
覆盖中,放置您需要的任何逻辑 . 如果您希望后退按钮弹出后退堆栈(默认行为),请返回 true ,表示您的后退事件已被吸收 . 否则,返回false .Lastly, in your Activity...
覆盖
onBackPressed()
方法并将此逻辑添加到它:我们在后面的堆栈中获取当前片段,然后我们进行空检查并确定它是否实现了我们的
Backable
接口 . 如果是,请确定事件是否被吸收 . 如果是这样,我们已完成onBackPressed()
并可以返回 . 否则,将其视为正常的背压并调用超级方法 .Second Option to not involve the Activity
有时,您根本不希望Activity处理此问题,您需要在片段中直接处理它 . 但谁说你 can't 有片段与背压API?只需将您的片段扩展到一个新类 .
创建一个扩展Fragment并实现
View.OnKeyListner
接口的抽象类...如您所见,任何扩展
BackableFragment
的片段都会使用View.OnKeyListener
界面自动捕获返回的点击次数 . 只需在实现的onKey()
方法中使用标准逻辑调用抽象onBackButtonPressed()
方法,即可识别后退按钮 . 如果你需要注册后退按钮以外的关键点击,只需确保在覆盖片段中的onKey()
时调用super
方法,否则你将覆盖抽象中的行为 .简单易用,只需扩展和实现:
由于超类中的
onBackButtonPressed()
方法是抽象的,因此一旦扩展,就必须实现onBackButtonPressed()
. 它返回void
因为它只需要在片段类中执行一个动作,并且不需要将按下的吸收传递回Activity . Make sure 如果您需要处理的话,您可以调用ActivityonBackPressed()
方法,否则后退按钮将被禁用...而您不希望这样!Caveats 正如您所看到的,这会将关键侦听器设置为片段的根视图,我们需要单独处理它 . 关于extending an EditText的一篇好文章将失去对新闻的关注 .
我希望有人觉得这很有用 . 快乐的编码 .
解决方案很简单:
1)如果你有一个所有片段都扩展的基础片段类,那么将这个代码添加到它的类中,否则创建这样一个基础片段类
2)在Activity类中,重写onBackPressed,如下所示:
3)在Fragment类中,添加所需的代码:
Just follow these steps: 总是在添加片段时
然后在主要活动中,覆盖
onBackPressed()
要处理应用中的后退按钮,
而已!
好吧,我这样做了,它对我有用
简单的界面
FragmentOnBackClickInterface.java
示例实现
MyFragment.java
然后在活动中覆盖onBackPressed
onBackPressed()
原因片段与活动分离 .根据@Sterling Diaz的回答,我认为他是对的 . 但有些情况会出错 . (例如旋转屏幕)
所以,我认为我们可以检测是否
isRemoving()
实现目标 .你可以写在
onDetach()
或onDestroyView()
. 这是工作 .您应该像下面一样为项目添加界面;
然后,您应该在片段上实现此接口;
你可以在你的活动onBackPressed事件下触发这个onBackPressed事件,如下所示;
如果您使用EventBus,它可能是一个更简单的解决方案:
在您的Activity类中,您可以定义:
BackPressedMessage.java只是一个POJO对象
这是超级干净的,没有接口/实现麻烦 .
使用onDestroyView()怎么样?
这只是一个小代码,可以解决这个问题:
希望它可以帮助别人:)
这是我的解决方案:
不要实现ft.addToBackStack()方法,以便当您按下后退按钮时,您的活动将完成 .
简短而甜蜜的回答:
我的案例的整个场景的解释:
我在MainActivity中有FragmentA,我从FragmentA打开FragmentB(FragmentB是FragmentA的子片段或嵌套片段)
现在,如果你想从FragmentB转到FragmentA,你可以简单地将
getActivity().onBackPressed();
放在FragmentB中 .最佳方案,
在活动生命周期中,当我们使用FragmentActivity或AppCompatActivity时,总是android后退按钮处理FragmentManager事务 .
要处理后台堆栈,我们不需要处理其后台堆栈计数或标记任何内容,但我们应该在添加或替换片段时保持焦点 . 请找到以下代码片段来处理后退按钮的情况,
在这里,我不会为我的home片段添加堆栈,因为它是我的应用程序的主页 . 如果将addToBackStack添加到HomeFragment,那么应用程序将等待删除活动中的所有片段,然后我们将获得空白屏幕,因此我保持以下条件,
现在,您可以看到之前在活动中添加的片段,app将在到达HomeFragment时退出 . 您还可以查看以下代码段 .
它很简单,如果你有一个活动A并且你制作了3个片段,如B,C和D.Now如果你在片段B或C和
onBackPressed
你想每次都在片段D上移动 . 那么你必须只是覆盖onBackPressed()
主Activity A中的方法,当你跳转到任何片段然后传递该片段的 TAG or name 时,您通过该片段识别主Activity A中的片段 .我举一个例子,你可以很容易地理解......
或者如果你正在从片段B移动到片段C ......并且在背面按下你想要进入片段D ...如下所示
现在你必须在主活动中覆盖onBackPressed()方法....如下所示..
我使用了另一种方法如下:
Otto event bus在活动及其碎片之间进行通信
活动中的堆栈,包含调用片段定义的
Runnable
中包含的自定义后退操作当在控制活动中调用
onBackPressed
时,它会弹出最近的自定义后退操作并执行其Runnable
. 如果堆栈中没有任何内容,则调用默认的super.onBackPressed()
包含示例代码的完整方法包含here作为this other SO question的答案 .
公共类MyActivity扩展Activity {
}
在你的片段中添加以下内容,不要忘记实现mainactivity的界面 .
我知道现在为时已晚,但我上周遇到了同样的问题 . 没有一个答案对我有帮助 . 然后我正在玩代码,这很有效,因为我已经添加了片段 .
在您的活动中,为
ViewPager
设置OnPageChangeListener
,以便您知道用户何时处于第二个活动中 . 如果他在第二个活动中,请按如下方式创建一个布尔true
:现在,每当按下后退按钮时检查布尔值,并将当前项设置为第一个片段:
好的,我终于找到了一个很好的解决方案 .
在您的活动中的onCreate()中,您的片段会添加一个backstack更改侦听器,如下所示:
(同样添加我的fragmenManager在活动中声明O现在每次更改片段时,当前片段String将成为当前片段的名称 . 然后在活动onBackPressed()中,您可以控制后退按钮的操作,如下所示:
我可以确认这种方法适合我 .
我有同样的问题,我为它创建了一个新的监听器,并在我的片段中使用 .
1 - 您的活动应该有一个监听器接口和一个监听器列表
2 - 您应该实现添加和删除侦听器的方法
3 - 您应该覆盖onBackPressed方法以检查是否有任何侦听器使用了反压
4 - 您的片段必须实现背压接口
5 - 您需要将片段添加为背压的监听器
6 - 如果片段使用此反压,则应从onBackPressed返回true
7 - 重要 - 您必须从列表onDestroy中删除该片段
使用Stack而不是ArrayList能够从最新的片段开始 . 将片段添加到后台堆栈时也可能存在问题 . 因此,在使用背压时,您需要检查片段是否可见 . 否则其中一个片段将使用该事件,并且最新片段将不会在后退时关闭 .
我希望这能解决每个人的问题 .
在mainActivity上
片段实现基本活动/片段之类的
DraweHomeActivity是我的基础活动写作
并创建方法doBack
Fragment: 使BaseFragment放置一个方法:
Activity:
您的活动将在附加的和可见的片段上运行,并在每个片段上调用 onBackPressed() 并在其中一个返回'true'(意味着它已被处理,因此没有进一步的操作)时中止 .