首先,谢谢大家这个伟大的社区.

我试图遵循支持演示示例代码来实现选项卡式片段接口.

顶级,我正在尝试实现两个选项卡,将单个片段与每个选项卡关联,并在相应选择每个选项卡时显示片段.

目前,我有两个问题(但我相信它们是相关的……)

1)每个标签的片段彼此重叠.这可能与不正确的片段附加/分离有关.

2)在某处创建了第三个神秘碎片,并与其他碎片重叠

在模拟器(和物理设备)上,您可以看到在选择任一选项卡时有两个片段重叠

当选择tab1时,片段1和未知片段重叠.

当选择tab2时,片段1和片段2重叠.

屏幕截图的链接(上传照片的声誉不够……)

(tab1重叠)http://s8.postimg.org/kv81yz745/tab1_overlapping.png

(tab2重叠)http://s8.postimg.org/3tf7wvs91/tab2_overlapping.png

在这里,为了演示/清晰的目的,我将每个片段中的文本分开.

这些屏幕截图的链接在我的评论/回复中. (上传超过2个链接的声誉不够……)

活动布局(fragment_tabs.xml)

<TabHost
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@android:id/tabhost"
android:layout_width="match_parent"
android:layout_height="match_parent">

<LinearLayout
    android:orientation="vertical"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <TabWidget
        android:id="@android:id/tabs"
        android:orientation="horizontal"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_weight="0"/>

    <FrameLayout
        android:id="@android:id/tabcontent"
        android:layout_width="0dp"
        android:layout_height="0dp"
        android:layout_weight="0"/>

    <FrameLayout
        android:id="@+id/realtabcontent"
        android:layout_width="match_parent"
        android:layout_height="0dp"
        android:layout_weight="1"/>

</LinearLayout>
</TabHost>

源代码

public class TabbedInfoHome extends SherlockFragmentActivity {

TabHost mTabHost;
TabManager mTabManager;

static String tag1name = "simple1";
static String tag2name = "simple2";

static String tab1string = "You are looking at fragment 1";
static String tab2string = "You are looking at fragment 2";


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

    setContentView(R.layout.fragment_tabs); 

    if (savedInstanceState == null) {
        // Do first time initialization -- add initial fragment.
        Fragment frag1 = CountingFragment.newInstance(tab1string);
        Fragment frag2 = CountingFragment.newInstance(tab2string);
        FragmentTransaction ft = getSupportFragmentManager().beginTransaction();

        ft.add(R.id.realtabcontent,frag1,tag1name);
        ft.add(R.id.realtabcontent,frag2,tag2name);

        ft.commit();
    } 
    else {
        mTabHost.setCurrentTabByTag(savedInstanceState.getString("tab"));
    }    

    mTabHost = (TabHost)findViewById(android.R.id.tabhost);
    mTabHost.setup();

    mTabManager = new TabManager(this,mTabHost,R.id.realtabcontent);

    mTabManager.addTab(mTabHost.newTabSpec(tag1name)
                .setIndicator(tag1name),TabbedInfoHome.CountingFragment.class,null);

    mTabManager.addTab(mTabHost.newTabSpec(tag2name)
                .setIndicator(tag2name),null);
}   

@Override
public void onSaveInstanceState(Bundle outState) {
    super.onSaveInstanceState(outState);
    outState.putString("tab",mTabHost.getCurrentTabTag());
}

public static class CountingFragment extends SherlockFragment {
    String displayString;
    String FRAGMENT_TAG = this.getClass().getSimpleName();



    /**
     * Create a new instance of CountingFragment,providing "num"
     * as an argument.
     */
    static CountingFragment newInstance(String todisplay) {
        CountingFragment f = new CountingFragment();

        Bundle args = new Bundle();
        args.putString("string",todisplay);
        f.setArguments(args);
        return f;
    }

     /* When creating,retrieve this instance's number from its arguments. */
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);         
        displayString = getArguments() != null ? getArguments().getString("string") : "no string was passed in!";
    }


    /* The Fragment's UI is just a simple text view showing its
     * instance number. */
    @Override
    public View onCreateView(LayoutInflater inflater,ViewGroup container,Bundle savedInstanceState) {

        View v = inflater.inflate(R.layout.hello_world,container,false);
        View tv = v.findViewById(R.id.text);

        boolean separateStrings = false;

        /* the overlapping is hard to decipher,so
         *  lets illustrate how both fragments are appearing */
        if(separateStrings) {

            String temp;

            /* b/c I only created TWO instances of the CountingFragments object,*  there should only be TWO "displayStrings" to consider...
             */
            if( (displayString.compareto(tab1string) == 0) ) {
                /* user clicked tab 1 */
                temp = "\n\n\n\n" + displayString;
            }
            else if( (displayString.compareto(tab2string) == 0) ) {
                /* user clicked tab2 */
                temp = "\n\n\n\n\n\n\n" + displayString;
            }
            else {
                /* unkNown CountingFragment instance */
                temp = "What am I doing here..??? ";
            }

            ((TextView)tv).setText(temp);

        }
        else {
            /* normal case of the fragment being shown; (but they overlap!) */
            ((TextView)tv).setText(displayString);
        }


        return v;
    }
}

/**
 * This is a helper class that implements a generic mechanism for
 * associating fragments with the tabs in a tab host.  It relies on a
 * trick.  normally a tab host has a simple API for supplying a View or
 * Intent that each tab will show.  This is not sufficient for switching
 * between fragments.  So instead we make the content part of the tab host
 * 0dp high (it is not shown) and the TabManager supplies its own dummy
 * view to show as the tab content.  It listens to changes in tabs,and takes
 * care of switch to the correct fragment shown in a separate content area
 * whenever the selected tab changes.
 */
public static class TabManager implements TabHost.OnTabchangelistener {
    private final FragmentActivity mActivity;
    private final TabHost mTabHost;
    private final int mContainerId;
    private final HashMap<String,TabInfo> mTabs = new HashMap<String,TabInfo>();
    TabInfo mLastTab;

    static final class TabInfo {
        private final String tag;
        private final Class<?> clss;
        private final Bundle args;
        private Fragment fragment;

        TabInfo(String _tag,Class<?> _class,Bundle _args) {
            tag = _tag;
            clss = _class;
            args = _args;
        }
    }

    static class DummyTabFactory implements TabHost.TabContentFactory {
        private final Context mContext;

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

        @Override
        public View createTabContent(String tag) {
            View v = new View(mContext);
            v.setMinimumWidth(0);
            v.setMinimumHeight(0);
            return v;
        }
    }

    public TabManager(FragmentActivity activity,TabHost tabHost,int containerId) {
        mActivity = activity;
        mTabHost = tabHost;
        mContainerId = containerId;
        mTabHost.setonTabChangedListener(this);
    }

    public void addTab(TabHost.TabSpec tabSpec,Class<?> clss,Bundle args) {

        tabSpec.setContent(new DummyTabFactory(mActivity));
        String tag = tabSpec.getTag();

        TabInfo info = new TabInfo(tag,clss,args);

        // 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.
        info.fragment = mActivity.getSupportFragmentManager().findFragmentByTag(tag);


        if (info.fragment != null ) {  // && !info.fragment.isDetached()) {
            Log.d("addingTab","we already have a fragment for this tab. tabInfo.fragment.id: " + info.fragment.getId());
            FragmentTransaction ft = mActivity.getSupportFragmentManager().beginTransaction();
            ft.detach(info.fragment);
            ft.commit();
            mActivity.getSupportFragmentManager().executePendingTransactions();
        }

        // associate the tabSpec tag with a particular TabInfo object
        mTabs.put(tag,info);
        mTabHost.addTab(tabSpec);
    }

    @Override
    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) {
                    newTab.fragment = Fragment.instantiate(mActivity,newTab.clss.getName(),newTab.args);

                    ft.add(mContainerId,newTab.fragment,newTab.tag);
                } else {
                    ft.attach(newTab.fragment);
                }
            }

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

}

解决方法

经过几天的实验,我得到了正常的工作.

在我的TabbedInfoHome类的onCreate方法中,当第一次创建片段的新实例(savedInstanceState == null)时,我使用this.getSupportFragmentManager()强制执行FragmentTransaction中的挂起事务.executePendingTransactions()

这个解释是基于http://developer.android.com/reference/android/app/FragmentManager.html#executePendingTransactions()的文档

After a FragmentTransaction is committed with FragmentTransaction.commit(),it is scheduled to be executed asynchronously > on the process’s main thread. If you want to immediately executing any such pending operations,you can call this function.

我仍然有一个悬而未决的问题是,缺少即时待决交易的执行情况如何体现在原始问题中看到的行为中.

换句话说…… this.getSupportFragmentManager().executePendingTransactions()的LACK如何解释重叠的片段?

编辑的代码如下;一行补充

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

setContentView(R.layout.fragment_tabs); 

if (savedInstanceState == null) {
    // Do first time initialization -- add initial fragment.
    Fragment frag1 = CountingFragment.newInstance(tab1string);
    Fragment frag2 = CountingFragment.newInstance(tab2string);
    FragmentTransaction ft = getSupportFragmentManager().beginTransaction();

    ft.add(R.id.realtabcontent,tag1name);
    ft.add(R.id.realtabcontent,tag2name);

    ft.commit();
    this.getSupportFragmentManager().executePendingTransactions();      // <----- This is the key 
} 
else {
    mTabHost.setCurrentTabByTag(savedInstanceState.getString("tab"));
}    

mTabHost = (TabHost)findViewById(android.R.id.tabhost);
mTabHost.setup();

mTabManager = new TabManager(this,R.id.realtabcontent);

mTabManager.addTab(mTabHost.newTabSpec(tag1name)
            .setIndicator(tag1name),null);

mTabManager.addTab(mTabHost.newTabSpec(tag2name)
            .setIndicator(tag2name),null);
}

Android的;切换标签时片段重叠的更多相关文章

  1. android – 尝试commitAllowingStateLoss时的FragmentManager NullPointerException

    上下文:我有一个带片段的活动和3个InnerFragments.当调用FragmentonDestroy()时,我想从FragmentManager中删除内部片段.onDestroy()的代码如下.问题:FragmentManager抛出NullPointerException,可能是在调用commitAllowingStateLoss()时.我不明白为什么.堆栈跟踪:解决方法FragmentMa

  2. android – Slider Menu片段中的可交换选项卡

    我已经通过引用thistutorial实现了导航抽屉,现在我想要做的是在片段内显示滑动标签.即当我点击导航抽屉中的一个项目时,让我们说第一个项目,它应显示该项目的滑动标签.如果item1是Events,当我点击它时,它应该显示滑动标签.但我面临以下问题:–>如何在片段内实现视图寻呼机?

  3. android – setRetainInstance(true)setCustomAnimations(…)=每个方向更改的动画?

    >为什么我仍然可以获得添加片段的动画?>其他配置发生变化时会发生什么?

  4. android – 来自Fragment的getActionBar和AppCompatLibrary

    我正在寻找使用AppCompatLibrary和API8从Fragment获取ActionBar实例的最简单方法.已经尝试过像但没有运气.解决方法试着施展它:

  5. android – onActivityCreated总是被调用?

    有人可以提供一些链接来做解释生命周期行为的文档吗?>究竟什么是Fragmentrestart()?>Android可以决定删除不可见的片段但是保留包含它们的活动吗?注1:我测试过,由于活动重新创建而添加了Fragment时调用了onActivityCreated,并且在活动完全启动并激活后手动添加片段时也是如此.注2:我正在使用23.3.0支持版本进行测试.某些行为是否有可能从以前的版本发生变化?我相信Android操作系统杀死唯一可管理的量子是一个过程.对于Fragment,您可以查看FragmentA

  6. android – Fragment,保存onSaveInstanceState上的大型数据列表(如何防止TransactionTooLargeException)

    如何存储(和恢复)我的Fragment状态.在ViewPager中的片段上使用setRetainInstance是否可以?解决方法为了保留大块数据,Google建议使用保留实例的Fragment.想法是创建没有视图的空片段和所有必需的字段,否则这些字段将被保存在Bundle中.添加setRetainInstance;到Fragment的onCreate方法.而不是将数据保存在Activity的onDestroy上的Fragment中并将它们加载到onCreate上.以下是活动的例子:片段的例子:

  7. Android在FragmentPagerAdapter中的Fragment中设置TextView文本

    更新:那么做这样的事情?

  8. android – 如何在TabHost中获取Tab的内容?

    我有一个Activity定义为:基本上它是一个带有TextViews作为内容的TabHost.我正在使用createTabContent()动态构建这些TextViews的选项卡和内容.这很好.但在某些情况下,我需要更改其中一些TextView的内容.我确信我的问题是我对AndroidSDK缺乏经验的结果,但我找不到迭代TabHost并获取每个TextView的内容的方法.我所取得的“最接近”的方法是:但这样做是将“linea”附加到选项卡的名称(指示符).我想将它添加到该选项卡的内容,但我找不到一种方法

  9. android – AsyncTask,Fragments,Views和Backstacks

    我一直在使用这种模式.这是一个非常人为的AsyncTask进度指示器示例:方向更改它可以正常工作,但我注意到当我从backstack中弹出片段时,片段非空,fragment.getView()为null.这显然会导致崩溃.你们用什么方法?我似乎无法在网上找到完美的解决方案.重要提示,这是一个片段,我调用setRetainInstance;在onActivityCreated(…

  10. 带有动画的Android Fragment Transaction会导致白色闪烁

    我有两个片段.片段A最初在视图中.当用户按下按钮时,使用以下方法将片段B动画到视图中.当我弹出片段B时,它会在视图中向下移动,但在完成时屏幕会闪烁白色.不确定是什么导致这种情况,似乎只发生在kit-kat而不是棒棒糖上.正在使用的动画是向上滑动并向下滑动在xml中定义的动画.解决方法对我来说,这个崩溃动画的bottomBarNavigation,NavigationDrawer以及当我使用替换片段

随机推荐

  1. bluetooth-lowenergy – Altbeacon库无法在Android 5.0上运行

    昨天我在Nexus4上获得了Android5.0的更新,并且altbeacon库停止了检测信标.似乎在监视和测距时,didEnterRegion和didRangeBeaconsInRegion都没有被调用.即使RadiusNetworks的Locate应用程序现在表现不同,一旦检测到信标的值,它们就不再得到更新,并且通常看起来好像信标超出了范围.我注意到的一点是,现在在logcat中出现以下行“B

  2. android – react-native动态更改响应者

    我正在使用react-native进行Android开发.我有一个视图,如果用户长按,我想显示一个可以拖动的动画视图.我可以使用PanResponder实现这一点,它工作正常.但我想要做的是当用户长按时,用户应该能够继续相同的触摸/按下并拖动新显示的Animated.View.如果您熟悉Google云端硬盘应用,则它具有类似的功能.当用户长按列表中的任何项目时,它会显示可拖动的项目.用户可以直接拖

  3. android – 是否有可能通过使用与最初使用的证书不同的证书对其进行签名来发布更新的应用程序

    是否可以通过使用与最初使用的证书不同的证书进行签名来发布Android应用程序的更新?我知道当我们尝试将这样的构建上传到市场时,它通常会给出错误消息.但有没有任何出路,比如将其标记为主要版本,指定市场中的某个地方?解决方法不,你不能这样做.证书是一种工具,可确保您是首次上传应用程序的人.所以总是备份密钥库!

  4. 如何检测Android中是否存在麦克风?

    ..所以我想在让用户访问语音输入功能之前检测麦克风是否存在.如何检测设备上是否有麦克风.谢谢.解决方法AndroidAPI参考:hasSystemFeature

  5. Android – 调用GONE然后VISIBLE使视图显示在错误的位置

    我有两个视图,A和B,视图A在视图B上方.当我以编程方式将视图A设置为GONE时,它将消失,并且它正下方的视图将转到视图A的位置.但是,当我再次将相同的视图设置为VISIBLE时,它会在视图B上显示.我不希望这样.我希望视图B回到原来的位置,这是我认为会发生的事情.我怎样才能做到这一点?编辑–代码}这里是XML:解决方法您可以尝试将两个视图放在RelativeLayout中并相对于彼此设置它们的位置.

  6. android – 获得一首歌的流派

    我如何阅读与歌曲相关的流派?我可以读这首歌,但是如何抓住这首歌的流派,它存放在哪里?解决方法检查此代码:

  7. android – 使用textShadow折叠工具栏

    我有一个折叠工具栏的问题,在展开状态我想在文本下面有一个模糊的阴影,我使用这段代码:用:我可以更改textColor,它可以工作,但阴影不起作用.我为阴影尝试了很多不同的值.是否可以为折叠文本投射阴影?

  8. android – 重用arm共享库

    我已经建立了armarm共享库.我有兴趣重用一个函数.我想调用该函数并获得返回值.有可能做这样的事吗?我没有任何头文件.我试过这个Android.mk,我把libtest.so放在/jni和/libs/armeabi,/lib/armeabi中.此时我的cpp文件编译,但现在是什么?我从objdump知道它的名字编辑:我试图用这个android.mk从hello-jni示例中添加prebuild库:它工作,但libtest.so相同的代码显示以下错误(启动时)libtest.so存在于libhello-j

  9. android – 为NumberPicker捕获键盘’Done’

    我有一个AlertDialog只有一些文本,一个NumberPicker,一个OK和一个取消.(我知道,这个对话框还没有做它应该保留暂停和恢复状态的事情.)我想在软键盘或其他IME上执行“完成”操作来关闭对话框,就像按下了“OK”一样,因为只有一个小部件可以编辑.看起来处理IME“Done”的最佳方法通常是在TextView上使用setonEditorActionListener.但我没有任何Te

  10. android – 想要在调用WebChromeClient#onCreateWindow时知道目标URL

    当我点击一个带有target=“_blank”属性的超链接时,会调用WebChromeClient#onCreateWindow,但我找不到新的窗口将打开的新方法?主页url是我唯一能知道的东西?我想根据目标网址更改应用行为.任何帮助表示赞赏,谢谢!

返回
顶部