以编程方式返回到 backstack 中的上一个片段
Posted
技术标签:
【中文标题】以编程方式返回到 backstack 中的上一个片段【英文标题】:Programmatically go back to the previous fragment in the backstack 【发布时间】:2012-06-07 11:30:25 【问题描述】:假设我有一个以编程方式添加片段的活动:
private void animateToFragment(Fragment newFragment, String tag)
FragmentTransaction ft = getFragmentManager().beginTransaction();
ft.replace(R.id.fragment_container, newFragment, tag);
ft.addToBackStack(null);
ft.commit();
返回上一个可见片段的最佳方法是什么?
我找到了Trigger back-button functionality on button click in android,但我认为模拟后键事件不是正确的方法(我也无法让它工作):
dispatchKeyEvent(new KeyEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_BACK));
调用finish()
只会关闭我不感兴趣的活动。
有没有更好的方法来解决这个问题?
【问题讨论】:
【参考方案1】:看看getFragmentManager().popBackStack()
的方法(有几种可供选择)
http://developer.android.com/reference/android/app/FragmentManager.html#popBackStack()
【讨论】:
getFragmentManager().popBackStackImmediate();
成功了。谢谢。
我会把这个方法放在哪里呢?在我的标签监听器中?
没有看到代码,很难说……但是它应该进入当你想要“关闭”当前片段并返回到前一个片段时执行的代码部分。
getSupportFragmentManager() 怎么样
不要忘记在您的代码中添加“addToBackStack("tag")”。 "fragmentManager.beginTransaction().replace(R.id.content_frame,fragment).addToBackStack("tag").commit();"如果你写 addToBackStack(null) ,它会自己处理它,但如果你给一个标签,你应该手动处理它。【参考方案2】:
要详细说明提供的其他答案,这是我的解决方案(放置在 Activity 中):
@Override
public void onBackPressed()
FragmentManager fm = getFragmentManager();
if (fm.getBackStackEntryCount() > 0)
Log.i("MainActivity", "popping backstack");
fm.popBackStack();
else
Log.i("MainActivity", "nothing on backstack, calling super");
super.onBackPressed();
【讨论】:
为什么会这样。在片段示例developer.android.com/training/basics/fragments/index.html 中,它们没有覆盖 onbackpressed 事件,但它们能够回栈片段。我用过 trasaction.addToBackStack(null);但什么也没发生。你能解释一下为什么吗? @MurtazaHussain 如果您需要这方面的帮助,您可能应该问一个新问题。如果不查看更多代码,很难了解发生了什么。 在我的情况下,当堆栈中只有第一个片段时,我必须执行fm.getBackStackEntryCount() > 1
才能回调活动。
Android 已经为您做到了:"当后台堆栈上有 FragmentTransaction 对象并且用户按下返回按钮时,FragmentManager 会从后台堆栈中弹出最近的事务并执行反向操作(例如,如果事务添加了片段,则将其删除)。” (Source)【参考方案3】:
当我们更新/添加片段时,
应该包括.addToBackStack()
。
getSupportFragmentManager().beginTransaction()
.add(detailFragment, "detail") // Add this transaction to the back stack (name is an optional name for this back stack state, or null).
.addToBackStack(null)
.commit();
之后如果我们提供getFragments.popBackStackImmediate()
,如果我们添加/更新片段,则返回true,并返回当前屏幕。
【讨论】:
【参考方案4】:Android 导航架构组件。
以下代码适用于我:
findNavController().popBackStack()
【讨论】:
当您使用自定义设计的工具栏时,此方法会派上用场。像魅力一样工作。 如果您使用的是 navController,我认为您必须使用此方法 - 我首先尝试了片段管理器(上面的答案),后来尝试使用 navController 导航时出现崩溃。【参考方案5】:如果我没有将 addToBackStack() 添加到我的片段事务中,这些答案将不起作用,但是您可以使用:
getActivity().onBackPressed();
从你的任何片段往回退一步;
【讨论】:
requireActivity().onBackPressed()
对于 Kotlin【参考方案6】:
将这些行添加到您的 onBackPressed() 方法中。如果您在后堆栈上有任何片段,popBackStackImmediate() 方法将使您回到上一个片段 `
if(getFragmentManager().getBackStackEntryCount() > 0)
getFragmentManager().popBackStackImmediate();
else
super.onBackPressed();
`
【讨论】:
【参考方案7】:当您想在主片段中按下后关闭应用程序时,此解决方案非常适合基于底部栏的片段导航。
另一方面,当您打开在我的代码中定义为“DetailedPizza”的辅助片段(片段中的片段)时,它将返回主片段的先前状态。干杯!
背面的活动里面放这个:
Fragment home = getSupportFragmentManager().findFragmentByTag("DetailedPizza");
if (home instanceof FragmentDetailedPizza && home.isVisible())
if (getFragmentManager().getBackStackEntryCount() != 0)
getFragmentManager().popBackStack();
else
super.onBackPressed();
else
//Primary fragment
moveTaskToBack(true);
然后像这样启动另一个片段:
Fragment someFragment = new FragmentDetailedPizza();
FragmentTransaction transaction = getFragmentManager().beginTransaction();
transaction.replace(R.id.container_body, someFragment, "DetailedPizza");
transaction.addToBackStack("DetailedPizza");
transaction.commit();
【讨论】:
【参考方案8】:Kotlin 答案
-
首先,调用片段管理器。
之后,使用 onBackPressed()
方法。
使用 Kotlin 在 Android Studio 4.0 中编码:
fragmentManager?.popBackStack()
【讨论】:
【参考方案9】:使用以下代码以编程方式返回上一个片段。
if ( getFragmentManager().getBackStackEntryCount() > 0)
getFragmentManager().popBackStack();
return;
super.onBackPressed();
【讨论】:
【参考方案10】:要使该片段再次出现,只需将该片段添加到您想要返回的 backstack 中,例如:
button.setOnClickListener(new View.OnClickListener()
@Override
public void onClick(View v)
Fragment fragment = new LoginFragment();
//replacing the fragment
if (fragment != null)
FragmentTransaction ft = ((FragmentActivity)getContext()).getSupportFragmentManager().beginTransaction();
ft.replace(R.id.content_frame, fragment);
ft.addToBackStack("SignupFragment");
ft.commit();
);
在上述情况下,我在按下Button button
时打开LoginFragment
,此时用户在SignupFragment
。因此,如果addToBackStack(TAG)
被调用,其中TAG = "SignupFragment"
,那么当在LoginFragment
中按下后退按钮时,我们会回到SignUpFragment
。
编码愉快!
【讨论】:
我认为,TAG 不影响,甚至可能为 null。【参考方案11】:通过在最后一个片段上添加fragment_tran.addToBackStack(null)
,我可以返回最后一个片段。
添加新片段:
view.findViewById(R.id.changepass).setOnClickListener(new View.OnClickListener()
@Override
public void onClick(View v)
FragmentTransaction transaction = getActivity().getSupportFragmentManager().beginTransaction();
transaction.replace(R.id.container, new ChangePassword());
transaction.addToBackStack(null);
transaction.commit();
);
【讨论】:
【参考方案12】:我来到这里寻找或相同的想法,同时我想出了自己的,我相信这不是那么糟糕,如果与 ViewPager 一起工作。
所以我所做的就是重写包含 viewPager 的父活动中的 onBackPressed 方法,并将其设置为始终返回负 1 位置,直到到达第一个片段,然后关闭活动。
@Override
public void onBackPressed()
if(viewPager.getCurrentItem()>0)
viewPager.setCurrentItem(viewPager.getCurrentItem()-1);
else
super.onBackPressed();
this.close();
private void close()
this.finish();
这可能有一个缺点,就像它每次只返回一个方向,所以如果有标签并且你切换位置并跳过片段,它可能效果不佳,(从 0 到 2,然后按回会把你放在 1,而不是 0)
在我的情况下,viewPager 中有 2 个片段,没有标签,它可以很好地完成工作。
【讨论】:
类似问题已得到解答。 ***.com/questions/10863572/…【参考方案13】:以下 Kotlin 代码对我有用
1.在使用多个片段的简单 Activity 类中添加
override fun onBackPressed()
if (supportFragmentManager.backStackEntryCount > 0)
Log.i(TAG, "=============onBackPressed - Popping backstack====")
supportFragmentManager.popBackStack()
else
Log.i(TAG, "=============onBackPressed called because nothing on backstack====")
super.onBackPressed()
2.在 BottomNavigationView 使用多个片段的 Activity 类中添加
override fun onBackPressed()
Log.e(TAG, "=============onBackPressed")
val navController = findNavController(R.id.nav_host_fragment)
when (navController.currentDestination!!.id)
R.id.navigation_comments, R.id.navigation_my_posts ->
menuItemPosition = 0
navController.navigate(R.id.navigation_home)
Log.i(TAG, "=============onBackPressed - Popping backstack with First fragment ====")
else ->
Log.i(TAG, "=============onBackPressed called because nothing on backstack====")
super.onBackPressed()
【讨论】:
【参考方案14】:试试下面的代码:
@Override
public void onBackPressed()
Fragment myFragment = getSupportFragmentManager().findFragmentById(R.id.container);
if (myFragment != null && myFragment instanceof StepOneFragment)
finish();
else
if (getSupportFragmentManager().getBackStackEntryCount() > 0)
getSupportFragmentManager().popBackStack();
else
super.onBackPressed();
【讨论】:
以上是关于以编程方式返回到 backstack 中的上一个片段的主要内容,如果未能解决你的问题,请参考以下文章
从 UIDocumentBrowserViewController 中的 UserDefaults 以编程方式打开文档
当我们在android中使用backstack返回上一个片段时,上一个片段正在重新启动
导航到 Jetpack Navigation 中的另一个 Fragment 后将 DialogFragment 保留在 backstack 中