多个回退栈的碎片化

12
据我所了解,每个Fragment都有自己的后退栈,并且这个后退栈与属于FragmentActivity的所有Fragment共享。假设您需要管理多个选项卡,每个选项卡可以浏览多个片段。假设您想要为每个选项卡“记录”导航历史记录,以便在片段之间切换时,可以返回到您正在查看的片段。这是否有可能实现?我需要将每个选项卡连接到一个片段活动吗?在这种情况下,如何管理FragmentActivity之间的切换?
4个回答

7

针对这种设计风格,没有固定方法,因为它不被鼓励。然而,我找到了一种方法使其正常工作:您需要手动设计您的导航菜单。

您的应用程序应该有一个活动(Activity),即FragmentActivity。它具有一个FragmentTabHost来容纳每个TabFragments(选项卡碎片)。

TabFragment是我创建的抽象类,用于代表TabSpec中的选项卡。它将管理选项卡内部的导航和碎片切换。

然后,您创建的各个碎片可以在TabFragment对象内进行切换。以下是代码:

活动(Activity)

    public class MainActivity extends FragmentActivity {

            private FragmentTabHost tabHost;

//(TabFragment)s will set this property when created so the Activity can communicate with it
            public TabFragment activeFragment;

            @Override
            public void onCreate(Bundle savedInstanceState){
                super.onCreate(savedInstanceState);
                setContentView(R.layout.main);

        //create tabHost based on .xml layout
                tabHost = (FragmentTabHost)findViewById(R.id.tabhost);
                tabHost.setup(this, getSupportFragmentManager(), R.id.tabcontent);

        //add each of your tabs to the tabHost. These are all (TabFragment)s
                tabHost.addTab(tabHost.newTabSpec("New Tab").setIndicator("New Tab"),
                      ExampleTabFragment.class, null);
            }

    /*override the onBackPressed method, so that your application does not close every 
time the user navigates back. Instead, calls the activeFragment to determine behavior*/
            @Override
            public void onBackPressed() {
                activeFragment.onBackPressed();
            }

    //method for TabFragment to call when the user navigates out of the app
            public void close(){
                super.onBackPressed();
            }
        }

TabFragment

    public abstract class TabFragment extends Fragment {

        @Override
        public void onResume(){

//sets the property in the Activity so we can reference this from it.
            ((MainActivity) getActivity()).activeFragment=this;
            super.onResume();
        }

//this will be the method called when the back button is pressed. It will navigate.
        public abstract void onBackPressed();

    }

TabFragment的实例 在TabFragment的实例中应该有一个FrameLayout,可以将子Fragments附加到其中。第一次点击选项卡时,它将启动在onCreate()中指定的Fragment。从另一个选项卡切换回来后,它将恢复上次显示的任何Fragment。如果需要进行分层导航,则应使用onBackPressed()方法返回到前面的Fragments。我使用了一个字节属性(tabContentIndex)来确定如何导航。如果添加一个以此TabFragment实例为参数的构造函数,Fragments可以互相交换。它们将通过访问start(Example)Fragment()方法来实现这一点。请记住,“返回”按钮最终必须退出应用程序。

public class NewTrailTabContent extends TabFragment {

    //to determine what child Fragment is active
    byte tabContentIndex;

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
            Bundle savedInstanceState) {

//a simple FrameLayout in this case. Child Fragments will be attached.
        return inflater.inflate(R.layout.example_fragment, container,
                false);
    }

    @Override
    public void onCreate(Bundle savedInstanceState) {

//The tab starts with this Fragment
        startDiologFragment();
        super.onCreate(savedInstanceState);
    }

    public void startExampleFragment(){

/*Fragment's constructor allows us to reference the parent to navigate. In effect, this 
Fragment will be able to call these navigation methods.*/
        ExampleFragment newFragment = new ExampleFragment(this);
        FragmentManager fragmentManager = getChildFragmentManager();
        FragmentTransaction fragmentTransaction = fragmentManager
                .beginTransaction();

//this Resource is the FrameLayout
        fragmentTransaction.replace(R.id.example_contentpane,
                newFragment);
        fragmentTransaction.commit();

//this is set so the onBackPressed() method knows how to operate.
        tabContentIndex =0;
    }

    public void startTestFragment(){

        Fragment testFragment = new TestFragment(this);
        FragmentManager fragmentManager = getChildFragmentManager();
        FragmentTransaction fragmentTransaction = fragmentManager
                .beginTransaction();
        fragmentTransaction.replace(R.id.example_contentpane,
                testFragment);
        fragmentTransaction.commit();

//different contentIndex
        tabContentIndex = 1;
    }

//this method called by the Activity
    @Override 
    public void onBackPressed() {

//this will close the app because we are at the top of the hierarchy
        if(tabContentIndex==0){
            ((MainActivity)getActivity()).close();

//this will switch to the original content fragment.
        }else if(tabContentIndex==1||tabContentIndex==2){
            startExampleFragment();
        }
    }
}

这看起来像是谷歌官方回答,我们现在在Android中有了导航组件,我认为它遵循相同的方法。 - Pulkit

1

FragmentTransaction有一个方法addToBackStack()

以这种方式打开新碎片this

FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();
transaction.replace(R.id.fragment_container, newFragment);
transaction.addToBackStack(null);
transaction.commit();

使用此方法,当用户按下返回按钮时,它会显示当前选项卡的先前片段,并且当当前选项卡的片段堆栈为空时,它会退出应用程序。 addToBackStack()方法将此事务添加到后退堆栈中。这意味着事务将在提交后记住,并在稍后从堆栈中弹出时撤消其操作。

1

那不是一个好的导航方法。我建议你看看Android设计模式并重新思考你的流程。

但是,如果不编写自己的FragmentManager,你需要拥有多个FragmentActivities

考虑使用TaskStacks,但这只适用于HoneyComb。因此,我建议重新考虑你的导航或仅构建一个HC+应用程序。

我知道我没有给你太多代码来解决你的问题。但是请好好阅读Android Navigation,它解释了时间和祖先导航,这是从Android 3.0+开始“官方”添加的。


有什么解决办法吗?我需要制作一个模仿iOS应用程序的Android应用程序,并且需要它导航相同。 - brainmurphy1

0

现在,jetpack-navigation-component 已经内置支持此功能。 从版本开始

navigation-2.4.0-alpha01

fragment-1.4.0-alpha01

感谢Ian。这里有他的一篇很棒的解释

或者,如果你不想使用Navigation Component,你可以使用FragmentManager中可用的savebackStack()restoreBackStack()方法。这些方法也在上面的链接中描述了。为此,您需要使用fragment-1.4.0-alpha01依赖项或最新版本。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接