ActionBar 选项卡内容重叠

时间:2023-01-14
本文介绍了ActionBar 选项卡内容重叠的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我在 StackOverflow 中发现了大量此类消息.像其他许多人一样,我在切换选项卡时也遇到了选项卡内容重叠的问题.我发现的所有建议都不适用于我的问题.

I found a ton of these messages in StackOverflow. Like those many other people, I have the same problem with tab contents overlapping when switching tabs. None of the advises I found didn't work with my problem.

当我的应用启动时,它会正确显示第一个选项卡的内容.当我单击另一个选项卡时,旧的内容会保留在屏幕上,并且另一个选项卡的内容也会添加到屏幕上.第二次切换标签时,所有内容都消失了.切换标签不会再做任何事情了.

When my app launches, it correctly shows the contents of the first tab. When I click the other tab, the old contents stay on the screen and the other tab's content is added on the screen, too. When switching tabs second time, all the contents disappear. Switching tabs won't do anyhting anymore.

我在这里关注了 Google 的开发者文档.

I followed Google's Developer document here.

我的应用程序有这个 onCreate 方法.该类从支持库 android.support.v7.app 扩展了 ActionBarActivity.

My application has this onCreate method.. The class extends ActionBarActivity from the support libary android.support.v7.app.

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);

    ActionBar actionBar = getSupportActionBar();
    actionBar.setNavigationMode(ActionBar.NAVIGATION_MODE_TABS);
    actionBar.setDisplayShowTitleEnabled(false);

    Tab tab = actionBar.newTab().setText("TAB1").setTabListener(new TabListener<Tab1Class>(this, "tab1", Tab1Class.class));
    actionBar.addTab(tab);

    tab = actionBar.newTab().setText("TAB2").setTabListener(new TabListener<Tab2Class>(this, "tab2", Tab2Class.class));
    actionBar.addTab(tab);
}

我的 TabListener 类是从我链接的页面复制而来的:

My TabListener class is copied from the page I linked:

public class TabListener<T extends Fragment> implements ActionBar.TabListener {
    private Fragment mFragment;
    private final Activity mActivity;
    private final String mTag;
    private final Class<T> mClass;

    public TabListener(Activity activity, String tag, Class<T> clz) {
        mActivity = activity;
        mTag = tag;
        mClass = clz;
    }

    @Override
    public void onTabSelected(Tab tab, FragmentTransaction ft) {
        if(mFragment == null) {
            mFragment = Fragment.instantiate(mActivity, mClass.getName());
            ft.add(android.R.id.content, mFragment, mTag);
        } else {
            ft.attach(mFragment);
        }
    }

    @Override
    public void onTabUnselected(Tab tab, FragmentTransaction ft) {
        if(mFragment != null) {
            ft.detach(mFragment);
        }
    }

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

我用作选项卡内容的两个类都从 android.support.v4.app.Fragment 扩展了 Fragment.他们在 onCreateView 方法中扩充他们的布局.

Both classes I use as the contents of the tabs extend Fragment from android.support.v4.app.Fragment. They inflate their layouts in onCreateView methods.

怎么了?

推荐答案

怎么了?

在快速浏览了 ActionBarActivity 的代码后,ICSActionBar<实现的上述部分似乎存在错误/code>(代码应该适用于 ICS 之前的设备),它还负责处理选项卡.

After a quick look through the code for the ActionBarActivity, there seems to be a bug for the ICS and above part of the implementation of the ActionBar(the code should work for pre ICS devices) which also takes care of the tabs.

在代表 ICS 设备实现的 ActionBarImplICS 类中,似乎 FragmentTransaction 传递给了 onTabUnselected() 回调是完全没用的,因为它不会在侦听器的回调返回后的任何地方提交(事务已提交给 TabListener 的其他两个回调).因此,提交的片段将永远不会从选项卡选择上的布局中分离出来,并且它将保持重叠内容(由于 FrameLayout 包含两个片段).

In the ActionBarImplICS class which represents the implementation for ICS devices it seems the FragmentTransaction passed to the onTabUnselected() callback is completely useless as it isn't committed anywhere after the listener's callback returns(the transaction is committed for the other two callbacks of the TabListener). So a committed fragment will never be detached from the layout on a tab selection and it will stay getting the overlapping content(due to the FrameLayout which holds both fragments).

我已经编写了 TabListener 接口的另一个实现,它只通过一个不受上述错误影响的回调来完成所有工作(onTabSelected()):

I've written another implementation of the TabListener interface which does all of its job from only one of the callbacks which isn't affected by the above bug(onTabSelected()):

public class TabListenerImpl implements ActionBar.TabListener {

    private List<TabInfo> mTabs = new ArrayList<TabInfo>();
    private Context mContext;

    public TabListenerImpl(Context context) {
        mContext = context;
    }

    @Override
    public void onTabReselected(Tab tab, FragmentTransaction ft) {

    }

    @Override
    public void onTabSelected(Tab tab, FragmentTransaction ft) {
        // iterate over all of the tabs, match the tag we have and see if
        // we also have a fragment instance for it. If we don't, create one
        // and add it to the container, if we have an instance simply attach
        // it. Detach every other tag which doesn't match the tag.
        for (TabInfo t : mTabs) {
            if (tab.getTag() == t.tag) {
                if (t.pageFragment == null) {
                    t.pageFragment = Fragment.instantiate(mContext,
                            t.clazz.getName());
                    ft.add(android.R.id.content, t.pageFragment, t.tag);
                } else {
                    ft.attach(t.pageFragment);
                }
            } else {
                if (t.pageFragment != null && !t.pageFragment.isDetached()) {
                    ft.detach(t.pageFragment);
                }
            }
        }
    }

    @Override
    public void onTabUnselected(Tab tab, FragmentTransaction ft) {
        // faulty method
    }

    /**
     * Call this method BEFORE you call the actionBar.addTab() method!
     * 
     * @param tag
     *            a String representing the tag that was set on the tab to
     *            identify itself
     * @param clazz
     *            the class of the Fragment
     */
    public void addTab(String tag, Class<? extends Fragment> clazz) {
        TabInfo ti = new TabInfo();
        ti.clazz = clazz;
        ti.tag = tag;
        mTabs.add(ti);
    }

    // wrapper class
    private class TabInfo {
        Class<? extends Fragment> clazz;
        Fragment pageFragment;
        String tag;
    }

}

然后你可以用作:

TabListenerImpl listener = new TabListenerImpl(this);
Tab tab = actionBar.newTab().setText("TAB1").setTag("TAB1").setTabListener(listener);
listener.addTab("TAB1", Tab1Class.class);
actionBar.addTab(tab);

tab = actionBar.newTab().setText("TAB2").setTag("TAB2").setTabListener(listener);
listener.addTab("TAB2", Tab2Class.class);
actionBar.addTab(tab);

我建议您将容器设置为内容视图(以及选项卡内容),而不是使用 android.R.id.content 容器.请记住,我的实现不负责配置更改.

I would advise you to set a container as the content view(and also for the tab content) and not use the android.R.id.content container. Keep in mind that my implementation doesn't take care of configuration changes.

这篇关于ActionBar 选项卡内容重叠的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持html5模板网!