0

我有一个ViewPager托管在Fragment内。作为测试,我用相同的类为如下的三个片段初始化:ViewPager child片段空

mAdapter = new GenericFragmentPagerAdapter(ChildFragmentManager); 
mAdapter.Add(frag1); 
mAdapter.Add(frag2); 
mAdapter.Add(frag3); 

mViewPager = Activity.FindViewById<ViewPager>(Resource.Id.fragment_navigation_viewpager); 
mViewPager.Adapter = mAdapter; 

mTabLayout = Activity.FindViewById<TabLayout>(Resource.Id.tab_layout); 
mTabLayout.SetupWithViewPager(mViewPager); 

由于我Fragment对象将被动态添加到ViewPager,我GenericFragmentPagerAdapter延伸FragmentStatePagerAdapter

Fragment举办ViewPager是我Activity承载一个NavigationView如下内实例:

NavigationFragment fragment = NavigationFragment.NewInstance(); 
SupportFragmentManager.BeginTransaction(). 
      Replace(Resource.Id.activity_main_content_container,fragment). 
      Commit(); 

我的问题是:这三个片段正确添加到ViewPager,但​​和frag3显示为空,而frag2正确显示内容。运行调试器​​和frag3确实得到了正确的实例化,所以我不明白为什么它们应该显示为空。

显然,使用嵌套片段时,适配器应该使用getChildFragmentManager()进行初始化。可悲的是,我仍然使用getSupportFragmentManager()的效果。

我错过了什么,或者有没有办法调试这个问题?

编辑

我设法让正在发生的问题的一个更好的主意。由于某些原因,如果我的片段延伸ListFragmentViewPager得到正确加载并显示其子。但是,如果我使用正常Fragment那么问题就会发生。老实说,我不知道为什么,所以我提供了下面的代码,以防有人想尝试。

MainAcitivty.cs

namespace App 
{ 
    [Activity(Label = "TestActivity", Theme = "@style/FM360MaterialTheme", 
     ConfigurationChanges = Android.Content.PM.ConfigChanges.Orientation | Android.Content.PM.ConfigChanges.ScreenSize)] 
    public class TestActivity : FragmentActivity 
    { 
     TabLayout mTabLayout; 
     ViewPager mViewPager; 
     GenericFragmentPagerAdapter mAdapter; 
     static FMNavigation mFMNavigation; 

     protected override void OnCreate(Bundle savedInstanceState) 
     { 
      base.OnCreate(savedInstanceState); 

      // Create your application here 
      // Set our view from the "startup" layout resource 
      SetContentView(Resource.Layout.fragment_navigation); 

      InitializeNavigation(); 
     } 

     private void InitializeNavigation() 
     { 
      ProgressDialog progressDialog = ProgressDialog.Show(
       this, 
       GetString(Resource.String.Initializing), 
       GetString(Resource.String.one_moment) 
       ); 

      new Thread(new ThreadStart(delegate { 

       // Here the mFMNavigation variable is initialized 
       // because it required downloaded data from the internet. 

       RunOnUiThread(() => 
       { 
        progressDialog.Dismiss(); 

        // If no error occured, initialize UI components. 
        InitializeUserInterface(); 
       }); 
      })).Start(); 
     } 

     private void InitializeUserInterface() 
     { 
      string fragmentTitle = "Test Fragment Title"; 

      // Items that will be inserted inside the adapter. 
      var datasource = mFMNavigation.CurrentItem.Datasource; 

      NavigationListFragment f1 = NavigationListFragment.NewInstance(
       datasource, 
       mFMNavigation, 
       "Title 1"); 

      NavigationListFragment f2 = NavigationListFragment.NewInstance(
       datasource, 
       mFMNavigation, 
       "Title 2"); 

      mAdapter = new GenericFragmentPagerAdapter(SupportFragmentManager); 
      mAdapter.Add(f1); 
      mAdapter.Add(f2); 

      mViewPager = FindViewById<ViewPager>(Resource.Id.fragment_navigation_viewpager); 
      mViewPager.Adapter = mAdapter; 

      mTabLayout = FindViewById<TabLayout>(Resource.Id.tab_layout); 
      mTabLayout.SetupWithViewPager(mViewPager); 
     } 
    } 
} 

GenericFragmentPagerAdapter.cs

using Android.Support.V4.App; 
    using System.Collections.Generic; 

    namespace Adapters 
    { 
     public class GenericFragmentPagerAdapter : FragmentStatePagerAdapter 
     { 
     private List<Fragment> mFragments; 

     public GenericFragmentPagerAdapter (FragmentManager fm) : base(fm) 
     { 
      mFragments = new List<Fragment>(); 
     } 

     public void Add(Fragment fragment) 
     { 
      if (!mFragments.Contains (fragment)) 
       mFragments.Add (fragment); 
     } 

     public void Remove(Fragment fragment) 
     { 
      if (mFragments.Contains (fragment)) 
       mFragments.Remove (fragment); 
     } 

     public void RemoveAt(int position) 
     { 
      if (mFragments.Count <= position) 
       return; 
      mFragments.RemoveAt(position); 
     } 

     public void RemoveUntil(int position) 
     { 
      position++; 
      while (mFragments.Count > position) 
       mFragments.RemoveAt(position); 
     } 

     public override int Count { get { return mFragments.Count; }} 

     public override Fragment GetItem(int position) { return mFragments [position]; } 

     public override int GetItemPosition(Java.Lang.Object item) { return PositionNone; } 

     public override Java.Lang.ICharSequence GetPageTitleFormatted(int position) 
     { 
      Fragment f = mFragments[position]; 
      if (f is NavigationListFragment) 
      { 
       NavigationListFragment listFragment = (NavigationListFragment)f; 
       return new Java.Lang.String(listFragment.FragmentTitle); 
      } 
      return new Java.Lang.String(""); 
     } 
    } 
} 

NavigationListFragment.cs

namespace App.Fragments 
{ 
    public class NavigationListFragment : Fragment 
    { 

     List<FMNavigationListItem> mDatasource; 
     FMNavigation mFMNavigation; 
     string mFragmentTitle; 
     ExpandableListviewAdapter mAdapter; 

     public NavigationListFragment() 
     { 

     } 

     public static NavigationListFragment NewInstance(List<FMNavigationListItem> items, FMNavigation navigation, string fragmentTitle) 
     { 
      NavigationListFragment f = new NavigationListFragment(); 
      f.mFMNavigation = navigation; 
      f.mDatasource = items; 
      f.mFragmentTitle = fragmentTitle; 
      return f; 
     } 

     public override void OnActivityCreated(Bundle savedInstanceState) 
     { 
      base.OnActivityCreated(savedInstanceState); 
      RetainInstance = true; 
      InitializeListView(); 
     } 

     public override View OnCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) 
     { 
      return inflater.Inflate(
       Resource.Layout.fragment_navigation_list, 
       container, 
       false); 
     } 

     /// <summary> 
     /// 
     /// </summary> 
     void InitializeListView() 
     { 
      ExpandableListView listView = Activity.FindViewById<ExpandableListView>(
       Resource.Id.fragment_navigation_list_expandable_listview); 

      // "Remove" listview and set empty state. 
      if (mDatasource == null || mDatasource.Count <= 0) 
      { 
       TextView emptyView = Activity.FindViewById<TextView>(
        Resource.Id.fragment_navigation_list_empty_textview); 
       emptyView.Text = GetString(Resource.String.empty_list_text); 
       listView.Visibility = ViewStates.Gone; 
       return; 
      } 

      // Here we build a list of groupable items based on the 
      // data source given. 
      List<ExpandableItem> groupItems = new List<ExpandableItem>(); 
      foreach (var dataItem in mDatasource) 
      { 
       string className = mFMNavigation.NameOfClassId(dataItem.ClassId); 

       // Attempt to find the group that has the same class name. 
       // If it exists add the data item to the group. Otherwise 
       // create a new group and add the item. 
       ExpandableItem groupItem = groupItems.Find(x => x.GroupTitle.Equals(className)); 
       if (groupItem == null) 
       { 
        ExpandableItem item = new ExpandableItem(); 
        item.GroupTitle = className; 
        item.ChildItems = new List<FMNavigationListItem>(); 
        item.ChildItems.Add(dataItem); 
        groupItems.Add(item); 
        continue; 
       } 
       groupItem.ChildItems.Add(dataItem); 
      } 
      mAdapter = new ExpandableListviewAdapter(Activity, groupItems); 

      listView.SetAdapter(mAdapter); 

      } 



     #region Fragment Properties 
     public string FragmentTitle 
     { 
      get { return mFragmentTitle; } 
     } 
     #endregion 
    } 
} 

ExpandableListviewAdapter.cs

namespace App.Adapters 
{ 
    class ExpandableListviewAdapter : BaseExpandableListAdapter 
    { 
     private Activity mContext; 
     private List<ExpandableItem> mDataItems; 

     public ExpandableListviewAdapter(Activity context, List<ExpandableItem> items) 
      : base() 
     { 
      mContext = context; 
      mDataItems = items; 

      // Sort the groups and all of its child elements alphabetically. 
      SortDataItems(); 
     } 

     void SortDataItems() 
     { 
      // Sort each group alphabetically. 
      mDataItems.Sort(delegate (ExpandableItem e1, ExpandableItem e2) 
      { 
       return e1.GroupTitle.CompareTo(e2.GroupTitle); 
      }); 

      // Iterate over each group of items and sort the 
      // children alphabetically. 
      foreach (var d in mDataItems) 
      { 
       d.ChildItems.Sort(delegate (FMNavigationListItem i1, FMNavigationListItem i2) 
       { 
        return i1.DisplayAttributes[0].CompareTo(i2.DisplayAttributes[0]); 
       }); 
      } 
     } 

     public override View GetChildView(int groupPosition, int childPosition, bool isLastChild, View convertView, ViewGroup parent) 
     { 
      if (convertView == null) 
       convertView = mContext.LayoutInflater.Inflate(Resource.Layout.adapter_expandable_listview_listitem, null); 

      FMNavigationListItem item = mDataItems[groupPosition].ChildItems[childPosition]; 
      convertView.FindViewById<TextView>(Resource.Id.adapter_expandable_listview_listitem_textview1).Text = item.DisplayAttributes[0]; 
      convertView.FindViewById<TextView>(Resource.Id.adapter_expandable_listview_listitem_textview2).Text = item.DisplayAttributes[1]; 
      convertView.FindViewById<TextView>(Resource.Id.adapter_expandable_listview_listitem_textview3).Text = item.DisplayAttributes[2]; 

      ImageButton i = convertView.FindViewById<ImageButton>(Resource.Id.adapter_expandable_listview_listitem_overflow_button); 
      i.Click += OverflowButtonClicked; 
      return convertView; 
     } 

     private void OverflowButtonClicked(object sender, EventArgs e) 
     { 
      Toast.MakeText(
       mContext, 
       "Overflow button clicked!", 
       ToastLength.Short).Show(); 
     } 

     public override View GetGroupView(int groupPosition, bool isExpanded, View convertView, ViewGroup parent) 
     { 
      if (convertView == null) 
       convertView = mContext.LayoutInflater.Inflate(Resource.Layout.adapter_expandable_listview_header, null); 

      // We expand all child objects from the group per default. 
      // Normal default ist that all children are collapsed. 
      ExpandableListView listView = (ExpandableListView)parent; 
      listView.ExpandGroup(groupPosition); 

      // Set the header title to be the group title. 
      ExpandableItem item = mDataItems[groupPosition]; 
      convertView.FindViewById<TextView>(Resource.Id.adapter_expandable_listview_header_textview).Text = item.GroupTitle; 
      return convertView; 
     } 

     public override int GroupCount 
     { 
      get 
      { 
       return mDataItems.Count; 
      } 
     } 

     public override bool HasStableIds 
     { 
      get 
      { 
       return true; 
      } 
     } 

     public override Java.Lang.Object GetChild(int groupPosition, int childPosition) 
     { 
      throw new NotImplementedException(); 
     } 

     public override long GetChildId(int groupPosition, int childPosition) 
     { 
      return childPosition; 
     } 

     public override int GetChildrenCount(int groupPosition) 
     { 
      return mDataItems[groupPosition].ChildItems.Count; 
     } 

     public override bool IsChildSelectable(int groupPosition, int childPosition) 
     { 
      return true; 
     } 

     public override Java.Lang.Object GetGroup(int groupPosition) 
     { 
      throw new NotImplementedException(); 
     } 

     public override long GetGroupId(int groupPosition) 
     { 
      return groupPosition; 
     } 

     public FMNavigationListItem ChildAt(int groupPosition, int childPosition) 
     { 
      return mDataItems[groupPosition].ChildItems[childPosition]; 
     } 
    } 

    /// <summary> 
    /// 
    /// </summary> 
    internal class ExpandableItem 
    { 
     public string GroupTitle; 
     public List<FMNavigationListItem> ChildItems; 
    } 
} 
+0

能否请你分享,可以重现该问题一个基本的演示? –

+0

我仍在试验和尝试一些事情。如果事情变得更清楚,我会让你知道的。 – Ivan

+0

@ ElvisXia-MSFT我可以提供一个测试项目解决方案,还是应该发布重现错误的代码? – Ivan

回答

0

所以我解决了我的问题。如上所述,该问题与FragmentManager无关。我发现当扩展ListFragment类和使用正常的ListViewViewPager完美工作。如果我用ExpandableListView使用正常片段,ViewPager开始表现怪异并显示空的片段(仍然不知道为什么)。

我的解决方案是为正常的ListView创建一个适配器,该适配器支持使用我发现的this blog post作为参考的节头。

这里是我的情况下,任何人适配器需要一个:

SectionedHeaderListViewAdaper。CS

namespace YourNamespace 
{ 
    /// <summary> 
    /// Used to pass groups of objects to the adapter. 
    /// </summary> 
    internal class ExpandableItem 
    { 
     public string HeaderTitle; 
     public List<FMNavigationListItem> ChildItems; 
    } 

    /// <summary> 
    /// Used internally by the adapter. 
    /// </summary> 
    internal class SectionedHeaderListItem 
    { 
     public string HeaderTitle; 
     public FMNavigationListItem Item; 

     public SectionedHeaderListItem(string headerTitle, FMNavigationListItem item) 
     { 
      HeaderTitle = headerTitle; 
      Item = item; 
     } 
    } 

    /// <summary> 
    /// 
    /// </summary> 
    class SectionedHeaderListViewAdaper : BaseAdapter 
    { 
     const int TypeItem = 0; 
     const int TypeSeperator = 1; 

     LayoutInflater mLayoutInflater; 
     List<SectionedHeaderListItem> mDataItems; 
     List<int> mSectionPositions; 

     /// <summary> 
     /// 
     /// </summary> 
     /// <param name="context"></param> 
     /// <param name="items"></param> 
     public SectionedHeaderListViewAdaper(Context context, List<ExpandableItem> items) 
     { 
      mLayoutInflater = (LayoutInflater)context.GetSystemService(Context.LayoutInflaterService); 
      mSectionPositions = new List<int>(); 

      // Sort each item via header title. 
      List<ExpandableItem> dataItems = items; 
      dataItems.Sort(delegate (ExpandableItem e1, ExpandableItem e2) 
      { 
       return e1.HeaderTitle.CompareTo(e2.HeaderTitle); 
      }); 

      // Sort each child item alphabetically. 
      foreach (var d in dataItems) 
      { 
       d.ChildItems.Sort(delegate (FMNavigationListItem i1, FMNavigationListItem i2) 
       { 
        return i1.DisplayAttributes[0].CompareTo(i2.DisplayAttributes[0]); 
       }); 
      } 

      // Merge all items into one big list. 
      mDataItems = new List<SectionedHeaderListItem>(); 
      int index = 0; 
      foreach (var expandableItem in dataItems) 
      { 
       // Represents a section 
       mDataItems.Add(new SectionedHeaderListItem(
        expandableItem.HeaderTitle, 
        null)); 
       mSectionPositions.Add(index); 
       index++; 

       // Now add the child items for the section 
       foreach (var dataItem in expandableItem.ChildItems) 
       { 
        mDataItems.Add(new SectionedHeaderListItem(
         expandableItem.HeaderTitle, 
         dataItem)); 
        index++; 
       } 
      } 
     } 

     public override Java.Lang.Object GetItem(int position) 
     { 
      return position; 
     } 

     public override long GetItemId(int position) 
     { 
      return position; 
     } 

     public FMNavigationListItem ItemAt(int position) 
     { 
      return mDataItems[position].Item; 
     } 

     /// <summary> 
     /// One view for the header and another for 
     /// the normal cells. 
     /// </summary> 
     public override int ViewTypeCount 
     { 
      get 
      { 
       return 2; 
      } 
     } 

     public override int GetItemViewType(int position) 
     { 
      if (mSectionPositions.Contains(position)) 
       return TypeSeperator; 
      return TypeItem; 
     } 

     public override int Count 
     { 
      get 
      { 
       return mDataItems.Count; 
      } 
     } 

     public override View GetView(int position, View convertView, ViewGroup parent) 
     { 
      SectionedHeaderListViewAdaperViewHolder holder = null; 
      int rowType = GetItemViewType(position); 

      // Inflate the correct layout 
      if (convertView == null) 
      { 
       holder = new SectionedHeaderListViewAdaperViewHolder(); 
       switch(rowType) 
       { 
        case TypeItem: 
         convertView = mLayoutInflater.Inflate(
          Resource.Layout.adapter_expandable_listview_listitem, 
          null); 
         break; 
        case TypeSeperator: 
         convertView = mLayoutInflater.Inflate(
          Resource.Layout.adapter_expandable_listview_header, 
          null); 
         break; 
       } 
       convertView.Tag = (SectionedHeaderListViewAdaperViewHolder)convertView.Tag; 
      } 
      else 
      { 
       holder = (SectionedHeaderListViewAdaperViewHolder)convertView.Tag; 
      } 

      //Populate UI components 
      SectionedHeaderListItem item = mDataItems[position]; 
      switch (rowType) 
      { 
       case TypeItem: 
        // Horrible code incomming 
        holder.DispAttsTextViews = new List<TextView>(); 
        holder.DispAttsTextViews.Add(convertView.FindViewById<TextView>(Resource.Id.adapter_expandable_listview_listitem_textview1)); 
        holder.DispAttsTextViews.Add(convertView.FindViewById<TextView>(Resource.Id.adapter_expandable_listview_listitem_textview2)); 
        holder.DispAttsTextViews.Add(convertView.FindViewById<TextView>(Resource.Id.adapter_expandable_listview_listitem_textview3)); 
        holder.DispAttsTextViews[0].Text = item.Item.DisplayAttributes[0]; 
        holder.DispAttsTextViews[1].Text = item.Item.DisplayAttributes[1]; 
        holder.DispAttsTextViews[2].Text = item.Item.DisplayAttributes[2]; 
        break; 
       case TypeSeperator: 
        holder.HeaderTextView = convertView.FindViewById<TextView>(Resource.Id.adapter_expandable_listview_header_textview); 
        holder.HeaderTextView.Text = item.HeaderTitle; 
        break; 
      } 
      return convertView; 
     } 
    } 

    class SectionedHeaderListViewAdaperViewHolder : Java.Lang.Object 
    { 
     public TextView HeaderTextView { get; set; } 
     public List<TextView> DispAttsTextViews { get; set; } 
    } 
} 

adapter_expandable_listview_listitem.xml

<?xml version="1.0" encoding="utf-8"?> 
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" 
    android:orientation="vertical" 
    android:layout_width="match_parent" 
    android:layout_height="wrap_content" 
    android:minWidth="25px" 
    android:minHeight="25px"> 
    <RelativeLayout 
     android:layout_width="match_parent" 
     android:layout_height="wrap_content" 
     android:id="@+id/relativeLayout1" 
     android:layout_marginLeft="16dp" 
     android:layout_marginRight="16dp" 
     android:layout_marginTop="16dp" 
     android:layout_marginBottom="20dp" 
     android:descendantFocusability="blocksDescendants"> 
     <TextView 
      android:text="Rüttenscheider Stern" 
      android:layout_width="wrap_content" 
      android:layout_height="wrap_content" 
      android:id="@+id/adapter_expandable_listview_listitem_textview1" 
      android:textSize="16sp" 
      android:textColor="@color/textColorPrimary" /> 
     <TextView 
      android:text="Essen" 
      android:layout_width="wrap_content" 
      android:layout_height="wrap_content" 
      android:layout_below="@id/adapter_expandable_listview_listitem_textview1" 
      android:id="@+id/adapter_expandable_listview_listitem_textview2" 
      android:textSize="14sp" /> 
     <TextView 
      android:text="Rüttenscheiderstraße" 
      android:layout_width="wrap_content" 
      android:layout_height="wrap_content" 
      android:layout_below="@id/adapter_expandable_listview_listitem_textview2" 
      android:id="@+id/adapter_expandable_listview_listitem_textview3" 
      android:textSize="14sp" /> 
     <ImageButton 
      android:layout_width="wrap_content" 
      android:layout_height="wrap_content" 
      android:layout_alignParentRight="true" 
      android:layout_alignParentTop="true" 
      android:id="@+id/adapter_expandable_listview_listitem_overflow_button" 
      android:src="@drawable/ic_dots_vertical_grey600_18dp" 
      android:background="@null" /> 
    </RelativeLayout> 
    <View 
     android:layout_width="match_parent" 
     android:layout_marginLeft="16dp" 
     android:layout_height="1dp" 
     android:background="@color/material_grey_300" /> 
</LinearLayout> 

adapter_expandable_listview_header

<?xml version="1.0" encoding="utf-8"?> 
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" 
    android:orientation="vertical" 
    android:layout_width="fill_parent" 
    android:layout_height="wrap_content"> 
    <TextView 
     android:id="@+id/adapter_expandable_listview_header_textview" 
     android:layout_width="match_parent" 
     android:text="Header" 
     android:textStyle="bold" 
     android:textSize="14sp" 
     android:textColor="@color/textColorSecondary" 
     android:layout_height="wrap_content" 
     android:layout_margin="16dp" /> 
</LinearLayout>