情景我想要实现的目标:
我的代码:
protected override void OnCreate(Bundle savedInstanceState)
{
...
var listFrag = new ListFragment();
var infoFrag = new InfoFragment();
var trans = FragmentManager.BeginTransaction();
trans.Add(Resource.Id.listFrame, listFrag);
trans.Add(Resource.Id.detailsFrame, infoFrag);
trans.Commit();
...
}
public void OnItemSelected(int id)
{
var detailsFrag = DetailFragment.NewInstance(id);
var trans = FragmentManager.BeginTransaction();
trans.Replace(Resource.Id.detailsFrame, detailsFrag);
if (FragmentManager.BackStackEntryCount == 0)
{
trans.AddToBackStack(null);
}
trans.Commit();
}
我的问题:
在按下后退按钮后,infoFrag与之前的detailFrag重叠!为什么呢?
答案 0 :(得分:11)
你可以这样做:
if (getSupportFragmentManager().getBackStackEntryCount() > 0) {
getSupportFragmentManager().popBackStack(getSupportFragmentManager().getBackStackEntryAt(0).getId(), getSupportFragmentManager().POP_BACK_STACK_INCLUSIVE);
} else {
super.onBackPressed();}
在你的活动中,你要保留第一个片段。
你的第一个片段中不应该有addToBackStack。但是,其余的,是的。
答案 1 :(得分:6)
问题是您backing
的交易有两个步骤:
infoFrag
detailsFrag
(这是已添加的第一个详细信息容器)(我们知道因为文档This is essentially the same as calling remove(Fragment) for all currently added fragments that were added with the same containerViewId and then add(int, Fragment, String) with the same arguments given here.
)
因此,每当系统恢复时,一个事务正在恢复这两个步骤,并且它没有对添加到它的最后一个detailFrag
说什么,所以它不会对它做任何事情。
我可以根据你的情况考虑两种可能的工作方式:
将您的活动引用到最后使用的detailsFrag并使用BackStackChange监听器,只要值从1更改为0(您必须跟踪以前的值),您还会删除剩下的一个片段
在每个点击监听器上,您必须popBackStackImmediatly()(删除上一个事务)和addToBackStack()
所有事务。在此变通方法中,您还可以使用一些setCustomAnimation魔法来确保它在屏幕上看起来都很漂亮(例如,使用0到0持续时间1的alpha动画,以避免先前的片段出现并再次消失。
PS。我同意片段管理器/事务应该对它处理.replace()动作的堆栈的方式更加聪明,但这就是它的方式。
修改强>
正在发生的事情是这样的(我正在为细节添加数字以使其更清晰)。
请记住.replace() = .remove().add()
Transaction.remove(info).add(detail1).addToBackStack(null) // 1st time
Transaction.remove(detail1).add(detail2) // 2nd time
Transaction.remove(detail2).add(detail3) // 3rd time
Transaction.remove(detail3).add(detail4) // 4th time
现在我们在布局上有详细信息4:
< Press back button >
System pops the back stack and find the following back entry to be reversed
remove(info).add(detail1);
so the system makes that transaction backward.
tries to remove detail1 (is not there, so it ignores)
re-add(info) // OVERLAP !!!
所以问题是系统没有意识到有一个detail4,并且事务是.replace()它应该替换那里的任何内容。
答案 2 :(得分:6)
Budius非常好的解释。我阅读了他的建议并实施了类似的导航,我想与其他人分享。
而不是像这样替换片段:
Transaction.remove(detail1).add(detail2)
Transaction.remove(detail2).add(detail3)
Transaction.remove(detail3).add(detail4)
我在活动布局文件中添加了一个片段容器布局。它可以是LinearLayout
,RelativeLayot
或FrameLayout
等。所以在创建活动中我有这个:
transaction.replace(R.id.HomeInputFragment, mainHomeFragment).commit();
mainHomeFragment
是我想按下后退按钮时要返回的片段,例如infoFrag
。然后,在我进行每次下一次交易之前:
fragmentManager.popBackStackImmediate();
transaction.replace(R.id.HomeInputFragment, frag2).addToBackStack(null).commit();
或
fragmentManager.popBackStackImmediate();
transaction.replace(R.id.HomeInputFragment, frag3).addToBackStack(null).commit();
通过这种方式,您无需跟踪当前显示的片段。
答案 3 :(得分:0)
您可以覆盖onBackPressed并将事务提交到初始片段。
答案 4 :(得分:0)
我猜测但是:
您已添加该事务以将带有1st detailsFrag的infoFrag替换为backstack。
但是你用1st detailsFrag替换1st detailsFrag。
此时单击返回时,片段管理器无法使用infoFrag干净地替换1st detailsFrag,因为1st detailsFrag已被删除并替换。
是否预期重叠行为我不知道。
我建议调试Android核心代码,看看它在做什么。
我不确定你是否可以在没有覆盖Activity::onBackPressed()
的情况下实现,并且自己将所有交易添加到后台堆中。