TabHost中的ViewPager将片段作为页面

时间:2013-10-01 15:45:58

标签: android android-viewpager fragment

我在这里有一个奇怪的情况。我有一个FragmentActivity,其TabHost有5个标签。在其中两个标签中,我有ViewPager。说这些标签是“Tab-A”和“Tab-B”,现在Tab-A在其ViewPager内有3个片段,而Tab-B有2个。所有这些片段都不同。我使用自定义FragmentPagerAdapter来填充ViewPagers。奇怪的是,当我从Tab-A / Tab-B切换到另一个标签并回到它时,ViewPager不再显示片段,或者显示一个或两个片段但不显示3.甚至更多,有时是片段(并非所有)来自Tab-A的ViewPager显示出Tab-B的ViewPager,即使它们使用2个不同的适配器。

通过搜索SO我得到的理解是,这可能是由于Fragments的嵌套(因为ViewPager在片段中,其页面也是片段)。我尝试过传递FragmentPagerAdapter getChildFragmentManager()而不是getFragmentManager()。但在这种情况下,当我切换到另一个选项卡并返回到Tab-A / Tab-B时,应用程序崩溃(参见下面的日志)。

我正在粘贴下面的代码。 FragmentActivity

的布局
<?xml version="1.0" encoding="utf-8"?>
<android.support.v4.widget.DrawerLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/drawer_layout"
android:layout_width="match_parent"
android:layout_height="match_parent">
<!-- The main content view -->
<FrameLayout 
    android:id="@+id/content_frame"
    android:layout_width="match_parent"
    android:layout_height="match_parent">
<TabHost
    android:id="@android:id/tabhost" 
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    >
    <LinearLayout android:orientation="vertical"
        android:layout_width="fill_parent" 
        android:layout_height="fill_parent">

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

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

        <TabWidget android:id="@android:id/tabs"
            android:layout_width="fill_parent" 
            android:layout_height="wrap_content"
            android:layout_weight="0"  />
    </LinearLayout>
</TabHost> 
</FrameLayout>
<!-- The navigation drawer -->
<ListView android:id="@+id/left_drawer"
    android:layout_width="240dp"
    android:layout_height="match_parent"
    android:layout_gravity="start"
    android:choiceMode="singleChoice"
    android:background="@android:color/darker_gray"/>
</android.support.v4.widget.DrawerLayout>

在活动中我为每个标签维护一个单独的片段堆栈。这是在标签交换机上添加或显示片段的方式

/*Comes here when user switch tab, or we do programmatically*/
TabHost.OnTabChangeListener listener    =   new TabHost.OnTabChangeListener() {
  public void onTabChanged(String tabId) {
    /*Set current tab..*/
    mCurrentTab =   tabId;

    if(mStacks.get(tabId).size() == 0){
      /*
       *    First time this tab is selected. So add first fragment of that tab.
       *    Dont need animation, so that argument is false.
       *    We are adding a new fragment which is not present in stack. So add to stack is true.
       */
      if(tabId.equals(TABTAGS.MessageTab))
      {
          FragmentInbox_ MessageFragment=new FragmentInbox_();
          pushFragments(tabId, MessageFragment, false,true);
      }
      else if(tabId.equals(TABTAGS.VIPTab))
      {
          VIPOffers_ VIPTab=new VIPOffers_();
          Bundle b=new Bundle();
          b.putInt("mode", 1);
          VIPTab.setArguments(b);
          pushFragments(tabId, VIPTab, false,true);
      }
      else if(tabId.equals(TABTAGS.DatingTab))
      {
          FragmentDating_ datingTab=new FragmentDating_();

          pushFragments(tabId, datingTab, false,true);
      }
      else if(tabId.equals(TABTAGS.VenueTab))
      {
        Fragment_EventPager_ venueTab=new Fragment_EventPager_();
        pushFragments(tabId, venueTab, false,true);
      }
    }
    else 
    {
      /*
       *    We are switching tabs, and target tab is already has atleast one fragment. 
       *    No need of animation, no need of stack pushing. Just show the target fragment
       */
      pushFragments(tabId, mStacks.get(tabId).lastElement(), false,false);
    }
  }
};

这是在标签中添加新片段或从

中删除的方式
public void pushFragments(String tag, Fragment fragment,boolean shouldAnimate, boolean shouldAdd){
  if(shouldAdd)
      mStacks.get(tag).push(fragment);
  FragmentManager   manager         =   getSupportFragmentManager();
  FragmentTransaction ft            =   manager.beginTransaction();
  if(shouldAnimate)
      ft.setCustomAnimations(R.anim.slide_in_right, R.anim.slide_out_left);
  ft.replace(R.id.realtabcontent, fragment);
  ft.commit();
}


public void popFragments(){
  /*    
   *    Select the second last fragment in current tab's stack.. 
   *    which will be shown after the fragment transaction given below 
   */
  Fragment fragment =   mStacks.get(mCurrentTab).elementAt(mStacks.get(mCurrentTab).size() - 2);

  /*pop current fragment from stack.. */
  mStacks.get(mCurrentTab).pop();

  /* We have the target fragment in hand.. Just show it.. Show a standard navigation animation*/
  FragmentManager   manager         =   getSupportFragmentManager();
  FragmentTransaction ft            =   manager.beginTransaction();
  ft.setCustomAnimations(R.anim.slide_in_left, R.anim.slide_out_right);
  ft.replace(R.id.realtabcontent, fragment);
  ft.commit();
}   


@Override
public void onBackPressed() 
{
    if(mStacks.get(mCurrentTab).size() == 1){
        super.onBackPressed();  // or call finish..
    }else{
        popFragments();
    }
}

以下是具有Fragment

ViewPager的布局
<?xml version="1.0" encoding="utf-8"?>
<android.support.v4.view.ViewPager
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/profile_pager"
android:layout_width="match_parent"
android:layout_height="match_parent" >

 <android.support.v4.view.PagerTabStrip
    android:id="@+id/pager_header"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:layout_gravity="top"
    android:background="@color/bar_back"
    android:textColor="@android:color/holo_blue_light" />

</android.support.v4.view.ViewPager>

这是设置ViewPager的适配器的方式。(我使用Android Annotation库)

@AfterViews
void InitiateViews()
{
    getActivity().getActionBar().setDisplayShowCustomEnabled(false);
    getActivity().getActionBar().setTitle("Dating");
    getActivity().getActionBar().setIcon(R.drawable.nav_dating);
    setHasOptionsMenu(true);

    Pager.setOffscreenPageLimit(2);
    SearchPagerAdapter adapter=new SearchPagerAdapter(getFragmentManager());
    Pager.setAdapter(adapter);
}

最后是FragmentPagerAdapter

public class SearchPagerAdapter extends FragmentPagerAdapter{

ArrayList<Fragment>  Fragments;
final int PAGE_COUNT=3;
public SearchPagerAdapter(FragmentManager fm) 
{
    super(fm);
    // TODO Auto-generated constructor stub
    Fragments=new ArrayList<Fragment>();
    Fragments.add(new FragmentBasicSearch_());
    Fragments.add(new FragmentSearchSealed_());
    Fragments.add(new Fragment_Username_Search_());
}

@Override
public Fragment getItem(int pos) {
    // TODO Auto-generated method stub
    if(Fragments==null)
    {
        Fragments=new ArrayList<Fragment>();
        Fragments.add(new FragmentBasicSearch_());
        Fragments.add(new FragmentSearchSealed_());
        Fragments.add(new Fragment_Username_Search_());

    }

    if(pos<PAGE_COUNT)
    {
        Log.d("PF", "get pager fragment");
        return Fragments.get(pos);
    }

    return null;
}

@Override
public CharSequence getPageTitle(int position) {
    // TODO Auto-generated method stub
    switch (position)
    {
        case 0:
            return "BASIC SEARCH";

        case 1:
            return "SEALED SECTION SEARCH";

        case 2:
            return "UERNAME SEARCH";

    }
    return super.getPageTitle(position);
}

@Override
public int getCount() {
    // TODO Auto-generated method stub
    return PAGE_COUNT;
}

}

以下是我通过传递Logcat FragmentPagerAdapter

获得的ChildFragmentManager输出
10-01 17:16:33.103: E/AndroidRuntime(3093): FATAL EXCEPTION: main
10-01 17:16:33.103: E/AndroidRuntime(3093): java.lang.IllegalStateException: No activity
10-01 17:16:33.103: E/AndroidRuntime(3093):     at android.support.v4.app.FragmentManagerImpl.moveToState(FragmentManager.java:1091)
10-01 17:16:33.103: E/AndroidRuntime(3093):     at android.support.v4.app.FragmentManagerImpl.moveToState(FragmentManager.java:1086)
10-01 17:16:33.103: E/AndroidRuntime(3093):     at android.support.v4.app.FragmentManagerImpl.dispatchActivityCreated(FragmentManager.java:1877)
10-01 17:16:33.103: E/AndroidRuntime(3093):     at android.support.v4.app.Fragment.performActivityCreated(Fragment.java:1492)
10-01 17:16:33.103: E/AndroidRuntime(3093):     at android.support.v4.app.FragmentManagerImpl.moveToState(FragmentManager.java:947)
10-01 17:16:33.103: E/AndroidRuntime(3093):     at android.support.v4.app.FragmentManagerImpl.moveToState(FragmentManager.java:1104)
10-01 17:16:33.103: E/AndroidRuntime(3093):     at android.support.v4.app.BackStackRecord.run(BackStackRecord.java:682)
10-01 17:16:33.103: E/AndroidRuntime(3093):     at android.support.v4.app.FragmentManagerImpl.execPendingActions(FragmentManager.java:1460)
10-01 17:16:33.103: E/AndroidRuntime(3093):     at android.support.v4.app.FragmentManagerImpl$1.run(FragmentManager.java:440)
10-01 17:16:33.103: E/AndroidRuntime(3093):     at android.os.Handler.handleCallback(Handler.java:605)
10-01 17:16:33.103: E/AndroidRuntime(3093):     at android.os.Handler.dispatchMessage(Handler.java:92)
10-01 17:16:33.103: E/AndroidRuntime(3093):     at android.os.Looper.loop(Looper.java:137)
10-01 17:16:33.103: E/AndroidRuntime(3093):     at android.app.ActivityThread.main(ActivityThread.java:4441)
10-01 17:16:33.103: E/AndroidRuntime(3093):     at java.lang.reflect.Method.invokeNative(Native Method)
10-01 17:16:33.103: E/AndroidRuntime(3093):     at java.lang.reflect.Method.invoke(Method.java:511)
10-01 17:16:33.103: E/AndroidRuntime(3093):     at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:784)
10-01 17:16:33.103: E/AndroidRuntime(3093):     at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:565)
10-01 17:16:33.103: E/AndroidRuntime(3093):     at dalvik.system.NativeStart.main(Native Method)

任何帮助或建议都将受到高度赞赏。

0 个答案:

没有答案