我正在使用兼容性库将应用程序转换为使用片段。现在,目前我有许多活动(ABCD),它们相互链接,D 有一个“确定”按钮,当按下该按钮时调用完成,然后通过 onActivityResult()
冒泡以另外破坏 C 和 B。
对于我之前的 Honycomb 片段版本,每个活动实际上都是片段 Af Bf Cf Df 的包装器。所有活动都是通过 startActivityForResult()
启动的,并且每个片段中的 onActivityResult()
都可以愉快地调用 getActivity().finish()
我遇到的问题是在我的 Honeycomb 版本中,我只有一个活动 A,并且使用 FragmentManager
加载片段 Bf、Cf、Df。
我不明白的是当按下“确定”以删除片段 Df、Cf 和 Bf 时在 Df 中做什么?
我尝试让片段从堆栈中弹出,但这导致了异常。 onActivityResult()
没用,因为我没有使用 startActivityForResult()
加载片段。
我在想这个完全错误的方式吗?我是否应该实现某种与父片段或活动通信的侦听器,以便使用事务管理器进行弹出?
虽然它可能不是最好的方法,但我能想到的最接近的等效方法是支持/兼容性库
getActivity().getSupportFragmentManager().beginTransaction().remove(this).commit();
或者
getActivity().getFragmentManager().beginTransaction().remove(this).commit();
否则。
此外,您可以使用 backstack 并弹出它。但是请记住,片段可能不在后台堆栈上(取决于将它放在那里的片段事务..),或者它可能不是最后一个进入堆栈的片段,因此弹出堆栈可能会删除错误的片段......
您可以使用下面的方法,它工作正常:
getActivity().getSupportFragmentManager().popBackStack();
popBackStack()
是在删除片段后要将操作栏标题设置回之前状态时唯一有效的解决方案。否则,我不需要将 stackoverflow.com/questions/13472258/… 中的高评价解决方案和此处的此解决方案结合起来,以便在各种用例之后始终设置正确的操作栏标题。如后按、删除、添加替换等。
我不明白的是当按下“确定”以删除片段 Df、Cf 和 Bf 时在 Df 中做什么?
第 1 步:让 Df 告诉 D“哟!我们点击确定!”通过在活动本身或活动提供的接口实例上调用方法。
第 2 步:让 D 通过 FragmentManager
删除片段。
托管活动 (D) 是知道活动中还有哪些其他片段的活动(相对于其他活动中的内容)。因此,可能影响片段混合的片段内事件应该传播到活动,这将使适当的编排移动。
finish()
就足够了。
onDestroy()
方法添加到您的片段并查看它是否被调用。
正如 CommonsWare 所说,您应该让 Activity 处理添加和删除片段,使用监听器。这是一个例子:
public class MyActivity extends FragmentActivity implements SuicidalFragmentListener {
// onCreate etc
@Override
public void onFragmentSuicide(String tag) {
// Check tag if you do this with more than one fragmen, then:
getSupportFragmentManager().popBackStack();
}
}
public interface SuicidalFragmentListener {
void onFragmentSuicide(String tag);
}
public class MyFragment extends Fragment {
// onCreateView etc
@Override
public void onAttach(Activity activity) {
super.onAttach(activity);
try {
suicideListener = (SuicidalFragmentListener) activity;
} catch (ClassCastException e) {
throw new RuntimeException(getActivity().getClass().getSimpleName() + " must implement the suicide listener to use this fragment", e);
}
}
@Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
// Attach the close listener to whatever action on the fragment you want
addSuicideTouchListener();
}
private void addSuicideTouchListener() {
getView().setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
suicideListener.onFragmentSuicide(getTag());
}
});
}
}
在 Activity/AppCompatActivity 中:
@Override
public void onBackPressed() {
if (mDrawerLayout.isDrawerOpen(GravityCompat.START)) {
// if you want to handle DrawerLayout
mDrawerLayout.closeDrawer(GravityCompat.START);
} else {
if (getFragmentManager().getBackStackEntryCount() == 0) {
super.onBackPressed();
} else {
getFragmentManager().popBackStack();
}
}
}
然后调用片段:
getActivity().onBackPressed();
或像其他答案中所述,在片段中调用它:
getActivity().getSupportFragmentManager().beginTransaction().remove(this).commit();
如果您使用的是新的导航组件,则很简单
findNavController().popBackStack()
它会为你完成所有的 FragmentTransaction。
查看 DialogFragment 是否满足您的需求。 DialogFragment 有一个dismiss() 方法。在我看来更干净。
我为此创建了简单的方法
popBackStack(getSupportFragmentManager());
比把它放在我的 ActivityUtils 类中
public static void popBackStack(FragmentManager manager){
FragmentManager.BackStackEntry first = manager.getBackStackEntryAt(0);
manager.popBackStack(first.getId(), FragmentManager.POP_BACK_STACK_INCLUSIVE);
}
工作很棒,玩得开心!
创建时:
//Add comment fragment
container = FindViewById<FrameLayout>(Resource.Id.frmAttachPicture);
mPictureFragment = new fmtAttachPicture();
var trans = SupportFragmentManager.BeginTransaction();
trans.Add(container.Id, mPictureFragment, "fmtPicture");
trans.Show(mPictureFragment); trans.Commit();
这就是我在点击事件 1 中隐藏片段的方式
//Close fragment
var trans = SupportFragmentManager.BeginTransaction();
trans.Hide(mPictureFragment);
trans.AddToBackStack(null);
trans.Commit();
然后将其显示回 int 事件 2
var trans = SupportFragmentManager.BeginTransaction();
trans.Show(mPictureFragment); trans.Commit();
如果你需要从 backstack 历史中的第四个片段弹回到第一个片段,使用标签!!!
当您添加第一个片段时,您应该使用如下内容:
getFragmentManager.beginTransaction.addToBackStack("A").add(R.id.container, FragmentA).commit()
或者
getFragmentManager.beginTransaction.addToBackStack("A").replace(R.id.container, FragmentA).commit()
当你想显示片段 B、C 和 D 时,你可以使用:
getFragmentManager.beginTransaction.addToBackStack("B").replace(R.id.container, FragmentB, "B").commit()
和其他字母......
回到Fragment
A,只要调用popBackStack(0, "A")
,是的,使用你添加时指定的标志,注意它必须与命令addToBackStack()
中的标志相同,而不是命令replace中使用的标志或添加。
别客气 ;)
在同一片段内关闭片段
getActivity().onBackPressed();
科特林 -
requireActivity().onBackPressed()
parentFragmentManager.apply {
val f = this@MyFragment
beginTransaction().hide(f).remove(f).commit()
}
为什么不只是:
getActivity().finish();