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
的代码后,ICS
和 ActionBar<实现的上述部分似乎存在错误/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.
相关文章