简体   繁体   English

从不在 backstack 顶部的 backstack 中删除特定片段

[英]Remove specefic fragment from backstack that is not on top of backstack

Short Version:精简版:

I have 5 fragments all added to a container by replace method( A -> B -> C -> D -> E ), now I want to remove 3rdfragment from my backStack(C) and stay in the current page, how to do it?我通过替换方法( A -> B -> C -> D -> E )将 5 个片段全部添加到容器中,现在我想从我的 backStack(C) 中删除 3rdfragment 并留在当前页面,怎么办它?

The problem:问题:

I have 3 fragments, FragmentA , FragmentB , and FragmentC , and user navigates from A to B then C .我有 3 个片段, FragmentAFragmentBFragmentC ,用户从A to B then C导航A to B then C In FragmentC when user performs an action (I call it ActionX ) I need to remove FragmentB from my fragment manager BackStack (while user still is in FragmentC) and I don't want user to notice anything, just when he presses back on phone different fragment shows (so if ActionX happened when user pressed back fragmentA shows, if not FragmentB shows)在 FragmentC 中,当用户执行一个操作(我称之为ActionX )时,我需要从我的片段管理器BackStack删除FragmentB (而用户仍然在 FragmentC 中)并且我不希望用户注意到任何事情,只是当他按下手机不同时片段显示(因此,如果用户按下时发生 ActionX,则片段 A 显示,如果不显示 FragmentB)

This is how I show my fragments (I set fragment name for name and tag to find them when I need)这就是我显示fragments (我为名称和标签设置片段名称以在需要时找到它们)

public void showFragment(Fragment fragment) {
        FragmentTransaction fragmentTransaction = getSupportFragmentManager().beginTransaction();
        String tag = fragment.getClass().getSimpleName();
        fragmentTransaction.replace(R.id.fragment_container, fragment, tag);
        fragmentTransaction.addToBackStack(tag);
        fragmentTransaction.commit();
}

I tried solutions mentiond in some SO threads (like this ) but they only work on top fragment in stack or they suggest to not FragmentB (which I cant because I don't know what will user do), also finding and removing FragmentB from stack does not work.我尝试了一些 SO 线程中提到的解决方案(像这样),但它们只适用于堆栈中的顶部片段,或者他们建议不要使用 FragmentB(我不能这样做,因为我不知道用户会做什么),还从堆栈中查找和删除 FragmentB不起作用。 One solution is to override my Activity's onBackPressed and check if ActionX happend and pop my backStack twice.一种解决方案是覆盖我的 Activity 的 onBackPressed 并检查 ActionX 是否发生并两次弹出我的 backStack。

what I tried:我试过的:

  1. this don't work (fragmentBInStack is not null but when I remove it nothing happens)这不起作用(fragmentBInStack 不为​​空,但是当我删除它时什么也没有发生)
val fragmentBInStack = manager.findFragmentByTag(FragmentB::class.java.simpleName)
fragmentBInStack?.let {
    manager.beginTransaction().remove(it).commit()
}
  1. this code removes both FragmentC and FragmentB and shows FragmentA (I want to stay in FragmentC) if I user 0 instad of POP_BACK_STACK_INCLUSIVE it only pops FragmentC and shows FragmentB此代码删除FragmentC和FragmentB和表演FragmentA都(我想留在FragmentC),如果我的用户0的instad POP_BACK_STACK_INCLUSIVE只弹出FragmentC和表演FragmentB
manager.popBackStack(FragmentB::class.java.simpleName, FragmentManager.POP_BACK_STACK_INCLUSIVE)

this is some sample code of what I want to do这是我想要做的一些示例代码

class FragmentC : Fragment() {
    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        super.onViewCreated(view, savedInstanceState)
        view.findViewById<View>(R.id.action_x).setOnClickListener {

            //here I want to remove FragmentB from back Stack and stay in FragmentC, just later when user presses back I want to show FragmentA
            val manager = activity!!.supportFragmentManager
            val fragmentBInStack = manager.findFragmentByTag(FragmentB::class.java.simpleName)
            fragmentBInStack?.let {
                manager.beginTransaction().remove(it).commit()
            }
        }
    }

Ok, first of all, you have to add your fragments in seperate transaction, and change replace to add好的,首先,您必须在单独的事务中添加片段,并将replace更改为add

supportFragmentManager
    .beginTransaction()
    .add(R.id.fragment_container, fragment2, tag2)
    .addToBackStack(tag2)
    .commit()

Then you remove fragment as you do:然后你像你一样删除片段:

val fragment2 = supportFragmentManager.findFragmentByTag(tag2)!!
supportFragmentManager.beginTransaction().remove(fragment2).commit()

The last step is just to popBackStack:最后一步就是popBackStack:

supportFragmentManager.popBackStack()

I can suggest the following approach: use the same instance of ViewModel (use ViewModelProvider of activity to create view model instance) with ActionX event LiveData in FragmentB and FragmentC .我可以建议以下方法:使用相同的ViewModel实例(使用ViewModelProvider的活动来创建视图模型实例)与FragmentBFragmentC ActionX 事件LiveData In FragmentC the value of LiveData is set, while FragmentB observes live data changes.FragmentC中设置了LiveData的值,而FragmentB观察实时数据变化。

Here is the source code.这是源代码。

1. view model 1.查看模型

class InterFragmentViewModel : ViewModel() {
    val actionXLiveData = MutableLiveData<Boolean>()
}

2. FragmentC 2.片段C

class FragmentC : AppCompatDialogFragment() {

    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        super.onViewCreated(view, savedInstanceState)
        view.findViewById<View>(R.id.action_x).setOnClickListener {
            ViewModelProvider(requireActivity()).get(InterFragmentViewModel::class.java)
                .actionXLiveData.value = true
        }
    }
}

3. FragmentB 3.片段B

class FragmentB : AppCompatDialogFragment() {

    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        super.onViewCreated(view, savedInstanceState)

        ViewModelProvider(requireActivity()).get(InterFragmentViewModel::class.java)
            .actionXLiveData.observe(viewLifecycleOwner, Observer {
            parentFragmentManager.popBackStack()
        })

    }
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM