Android 中 TabHost 中每个 Fragment 的自定义返回堆栈 [英] Custom Back Stack for each Fragment in TabHost in Android

查看:28
本文介绍了Android 中 TabHost 中每个 Fragment 的自定义返回堆栈的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

由于 TabActivity 已被弃用,我尝试将其替换为 Fragments,这在开发者 android 网站中已经提及.但是你们已经知道用片段替换选项卡存在一个问题,因为只有一个活动,即片段活动,每个片段都没有后退堆栈,正如您在其他 SO 问题中看到的那样的开发人员说您需要管理自己的自定义后台堆栈作为解决方案.

Since the TabActivity is deprecated I tried to replace it with Fragments which has been already mentioned in developer android website. But as you guys already know there was an issue about replacing tabs with fragments, since there will be only one activity ,which is Fragment Activity, there is no back stack for each of the fragments and as you can see in the other SO questions most of the developers were saying that you need to manage your own custom back stack as a solution.

我已经创建并实现了我自己的自定义返回堆栈,如下所示,它运行良好,我可以跟踪每个选项卡中的每个片段.

I have created and implemented my own custom back stack as you can see below, it works perfect I can track each fragment in each tab.

Tab1

    Fragment1 > Fragment2 > Fragment3

Tab2

    Fragment5 > Fragment6

根据上面的导航,如果我从 Fragment1 导航到 Fragment 3,然后如果我将选项卡更改为 Tab2 并返回到 Tab1,我仍然可以看到 Fragment3,我什至可以使用我的自定义导航回 Fragment1返回堆栈.

According to navigation above, if I navigate from Fragment1 through Fragment 3 and After that If I change the tab to Tab2 to and come back to Tab1, I can still see the Fragment3 and I can even navigate back to Fragment1 with my custom back stack.

但问题是,当我回到 Tab1 并看到 Fragment3 时,Fragment3 被重新创建,并且在我将选项卡更改为 Tab2 之前我无法看到我留下的更改.

But the issue is, When I come back to Tab1 and see the Fragment3, the Fragment3 is re-created and I can not see the changes as I left behind before I change the tab to Tab2.

这是我的自定义返回堆栈;

Here is my Custom back stack;

public static HashMap<String, Stack<Fragment>> customBackStack;

public static Stack<Fragment> simpleStack;
public static Stack<Fragment> contactStack;
public static Stack<Fragment> customStack;
public static Stack<Fragment> throttleStack;
public static Stack<Fragment> homeStack;

customBackStack = new HashMap<String, Stack<Fragment>>();

homeStack = new Stack<Fragment>();
simpleStack = new Stack<Fragment>();
contactStack = new Stack<Fragment>();
customStack = new Stack<Fragment>();
throttleStack = new Stack<Fragment>();

customBackStack.put("home", homeStack);
customBackStack.put("simple", simpleStack);
customBackStack.put("contacts", contactStack);
customBackStack.put("custom", customStack);
customBackStack.put("throttle", throttleStack);

这里是 onTabChanged 方法;

And here is onTabChanged method;

        public void onTabChanged(String tabId) {
        TabInfo newTab = mTabs.get(tabId);
        if (mLastTab != newTab) {
            FragmentTransaction ft = mActivity.getSupportFragmentManager().beginTransaction();
            if (mLastTab != null) {
                if (mLastTab.fragment != null) {
                    ft.detach(mLastTab.fragment);
                }
            }
            if (newTab != null) {
                if (newTab.fragment == null) {
                    if (!customBackStack.get(tabId).isEmpty()) {
                        Fragment fragment = customBackStack.get(tabId).pop();
                        customBackStack.get(tabId).push(fragment);
                        ft.replace(mContainerId, fragment);
                    }
                } else {
                    if (!customBackStack.get(tabId).isEmpty()) {
                        Fragment fragment = customBackStack.get(tabId).pop();
                        customBackStack.get(tabId).push(fragment);
                        ft.replace(mContainerId, fragment);
                    }
                }
            }

            mLastTab = newTab;
            ft.commit();
            mActivity.getSupportFragmentManager().executePendingTransactions();
        }
    }

这里是 onBackPressed;

And here is onBackPressed;

    public void onBackPressed() {

    Stack<Fragment> stack = customBackStack.get(mTabHost.getCurrentTabTag());

    if (stack.isEmpty()) {
        super.onBackPressed();
    } else {

        Fragment fragment = stack.pop();

        if (fragment.isVisible()) {
            if (stack.isEmpty()) {
                super.onBackPressed();
            } else {
                Fragment frg = stack.pop();
                customBackStack.get(mTabHost.getCurrentTabTag()).push(frg);

                transaction = getSupportFragmentManager().beginTransaction();
                transaction.setCustomAnimations(R.anim.slide_in_left, R.anim.slide_out_right,
                        R.anim.slide_in_right, R.anim.slide_out_left);

                transaction.replace(R.id.realtabcontent, frg).commit();
            }
        } else {
            getSupportFragmentManager().beginTransaction().replace(R.id.realtabcontent, fragment).commit();
        }
    }

}

因此,自定义返回堆栈工作正常,除了更改选项卡之前的最后一个片段在返回选项卡后重新创建,它不像在选项卡活动中那样恢复.

As a result, custom back stack works fine except the last fragment before changing the tab is getting re-created after coming back to the tab, its not resuming as like in tab activity.

知道如何解决吗?

编辑

您可以在此处找到我的示例应用程序作为解决此问题的方法.

You can find my sample Application here as a solution regarding to this issue.

GitHub

推荐答案

我将 googles 示例 tablistener 修改为以下内容:

I modified googles sample tablistener to following:

public static class TabListener<T extends SherlockFragment> implements ActionBar.TabListener {
    private final SherlockFragmentActivity mActivity;
    private final String mTag;
    private final Class<T> mClass;
    private final Bundle mArgs;
    public SherlockFragment mFragment;
    private final Stack<SherlockFragment> mStack;

    public TabListener(SherlockFragmentActivity activity, String tag, Class<T> clz) {
        this(activity, tag, clz, null, null);
    }

    public TabListener(SherlockFragmentActivity activity, String tag, Class<T> clz, Bundle args, Stack<SherlockFragment> stack) {
        mActivity = activity;
        mTag = tag;
        mClass = clz;
        mArgs = args;
        mStack = stack;

        // Check to see if we already have a fragment for this tab, probably
        // from a previously saved state.  If so, deactivate it, because our
        // initial state is that a tab isn't shown.
        mFragment = (SherlockFragment) mActivity.getSupportFragmentManager().findFragmentByTag(mTag);
        if (mFragment != null && !mFragment.isDetached()) {
            FragmentTransaction ft = mActivity.getSupportFragmentManager().beginTransaction();
            ft.detach(mFragment);
            ft.commit();
        }
    }

    public void onTabSelected(Tab tab, FragmentTransaction ft) {
        // we need to reattach ALL fragments thats in the custom stack, if we don't we'll have problems with setCustomAnimation for fragments.
        if (mFragment == null) {
            mFragment = (SherlockFragment) SherlockFragment.instantiate(mActivity, mClass.getName(), mArgs);
            ft.replace(android.R.id.content, mFragment, mTag);
        } else {
            ft.attach(mFragment);
        }
        if(mStack != null) {
            for(SherlockFragment fragment: mStack) {
                ft.attach(fragment);
            }
        }
    }

    public void onTabUnselected(Tab tab, FragmentTransaction ft) {
        if (mFragment != null) {
            ft.detach(mFragment);
        }
        if(mStack != null) {
            for(SherlockFragment fragment: mStack) {
                if(fragment!= null && !fragment.isDetached()) {
                    ft.detach(fragment);
                }
            }
        }
    }

    public void onTabReselected(Tab tab, FragmentTransaction ft) {
    }
}

我重写的 onKeyDown 方法的活动如下:

And the activity onKeyDown methode I override to following:

@Override
public boolean onKeyDown(int keyCode, KeyEvent event) {
    if (keyCode == KeyEvent.KEYCODE_BACK) {
        int index = getSupportActionBar().getSelectedNavigationIndex();
        Stack<SherlockFragment> stack = null;
        SherlockFragment fragment = null;
        String rootTag = null;
        switch(index) {
            case 0:
                stack = mWatersTabListener.mStack;
                fragment = mWatersTabListener.mFragment;
                rootTag = mWatersTabListener.mTag;
                break;
            case 1:
                stack = mHarborTabListener.mStack;
                fragment = mHarborTabListener.mFragment;
                rootTag = mHarborTabListener.mTag;
                break;
        }

        if(stack.isEmpty()) {
            return super.onKeyDown(keyCode, event);
        } else {
            SherlockFragment topFragment = stack.pop();
            FragmentManager fragmentManager = getSupportFragmentManager();

            FragmentTransaction ft = fragmentManager.beginTransaction();

            ft.setCustomAnimations(R.anim.fragment_slide_right_enter,
                    R.anim.fragment_slide_right_exit);

            if(topFragment != null && !topFragment.isDetached()) {
                ft.detach(topFragment);
            }

            if(stack.isEmpty()) {
                ft.replace(android.R.id.content, fragment, rootTag);
                ft.commit();
                return true;
            } else {
                SherlockFragment nextFragment = stack.peek();
                ft.replace(android.R.id.content, nextFragment);
                ft.commit();
                return true;
            }
        }
    }
    return super.onKeyDown(keyCode, event);
}

需要注意的重要事项是,您必须在选择时附加自定义堆栈中的所有片段,并且在未选择时也必须分离所有片段.如果在理解代码片段方面有问题,请询问.

The important things to take note of is that you have to attach all fragments in your custom stack when selected and you have to detach all as well when unselected. If there is problem with understanding the code snippets just ask.

这篇关于Android 中 TabHost 中每个 Fragment 的自定义返回堆栈的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆