【问题标题】:Fragment with multiple backstack具有多个 backstack 的片段
【发布时间】:2012-03-24 19:17:10
【问题描述】:

据我了解,每个 Fragment 都有自己的 backstack,并与属于 FragmentActivity 的所有 Fragment 共享。假设您必须管理多个选项卡,并且每个选项卡都可以浏览多个片段。假设您想“记录”每个选项卡的导航历史记录,因此在片段之间切换将允许您返回到您正在查看的片段。有没有可能实现?我是否需要将每个选项卡链接到片段活动?在这种情况下,如何管理 FragmentActivity 之间的切换?

【问题讨论】:

    标签: android fragment


    【解决方案1】:

    没有“标准”的方式来解决这个问题,因为不鼓励这种设计风格。不过,我找到了一种让它发挥作用的方法:您将手动设计导航。

    您的应用程序应该有一个 Activity,即 FragmentActivity。它有一个 FragmentTabHost 将保存您的每个 TabFragment。

    TabFragment 是我创建的抽象类,用于在 TabSpec 中表示您的选项卡。它将管理选项卡内片段的导航和交换。

    然后,您创建的各个片段可以在 TabFragment 对象中交换。代码如下:

    活动

        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,可以将子 Fragment 附加到该 FrameLayout 上。第一次单击选项卡时,它将启动onCreate() 中指定的片段。从另一个选项卡切换回它后,它将恢复上次显示的任何 Fragment。如果需要分层导航,应使用 onBackPressed() 方法在片段中导航。我使用字节属性 (tabContentIndex) 来确定如何导航。如果您添加一个构造函数来获取此 TabFragment 的实例,则 Fragments 可以将自己交换为其他 Fragment。他们将通过访问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 中有导航组件,我认为它遵循相同的方法
    【解决方案2】:

    这不是一个很好的导航方法。我会推荐你​​。查看 Android 设计模式并重新思考您的流程。

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

    看看使用TaskStacks 但这只会在 HoneyComb 上真正起作用。因此,我建议重新考虑您的导航或仅构建一个 HC+ 应用程序。

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

    【讨论】:

    • 有解决方法吗?我需要制作一个基于一个 iOS 应用程序的 Android 应用程序,因此需要它来导航。
    【解决方案3】:

    FragmentTransaction 有一个方法addToBackStack()

    打开新片段this方式:

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

    使用此方法,当用户按下返回按钮时,它会显示当前选项卡的前一个片段,并且当片段堆栈为当前选项卡为空时,它会退出应用程序。

    addToBackStack() 方法将此事务添加到后台堆栈。这意味着事务将在提交后被记住,并在以后从堆栈中弹出时反转其操作。

    【讨论】:

      【解决方案4】:

      现在支持 jetpack-navigation-component 开箱即用。 从版本开始

      navigation-2.4.0-alpha01

      fragment-1.4.0-alpha01

      感谢伊恩。这是他写的很棒的explaination

      或者,如果您不想使用导航组件,您可以使用FragmentManager 中提供的savebackStack()restoreBackStack() 方法,这些方法也在上面的链接中描述。为此,您将使用 fragment-1.4.0-alpha01 依赖项或最新版本。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2012-12-30
        • 2014-09-26
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多