我正在尝试通过Xamarin中的MvvmCross实现制表符。我在Android中遇到了MvxTabActivity,在IOS中遇到了MvxTabBarViewController。两者都运作良好。问题是MvxTabActivity很常见。 MvxTabActivity还有其他选择吗?
我找到了另一种实现它的方法,它使用TabLayout和ViewPager。 该解决方案要求在片段内使用片段。我已经粘贴了这种方法的代码。这里的问题是在滑动选项卡时,先前选项卡中的所有数据都将丢失。 我尝试使用RetainInstance = true,这给出了以下异常:“无法保留嵌套在其他片段中的fragements。”
产品详情活动:
的
的[Activity(Label = "ProductDetailView")]
public class ProductDetailView : MvxAppCompatActivity<ProductDetailViewModel>
{
private FrameLayout _mainFrame;
protected override void OnCreate(Bundle savedInstanceState)
{
base.OnCreate(savedInstanceState);
SetContentView(Resource.Layout.product_detail_view);
if (FindViewById<FrameLayout>(Resource.Id.frame_Detail) != null)
{
var frag = new NutritionCategoryView();
frag.ViewModel = ViewModel.NutritionCategoryModel;
var trans = SupportFragmentManager.BeginTransaction();
trans.Replace(Resource.Id.frame_Detail, frag);
trans.AddToBackStack(null);
trans.Commit();
}
}
}
的
营养类别查看片段:
的
的 public class NutritionCategoryView : MvxFragment
{
public NutritionCategoryViewModel vm
{
get { return (NutritionCategoryViewModel) ViewModel; }
}
private TabLayout _tablayout;
private ViewPager _viewPager;
public override View OnCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState)
{
this.EnsureBindingContextIsSet(inflater);
var view = this.BindingInflate(Resource.Layout.nutrition_category_view, container, false);
SetViewPager(view);
return view;
}
private void SetViewPager(View view)
{
_viewPager = view.FindViewById<Android.Support.V4.View.ViewPager>(Resource.Id.viewpager);
if (_viewPager != null)
{
var fragments = new List<CategoryTabsAdapter.FragmentInfo>
{
new CategoryTabsAdapter.FragmentInfo
{
FragmentType = typeof(CategoryView),
Title = "Proximates",
ViewModel = vm.Category1
},
new CategoryTabsAdapter.FragmentInfo
{
FragmentType = typeof(CategoryView),
Title = "Minerals",
ViewModel = vm.Category2
},
new CategoryTabsAdapter.FragmentInfo
{
FragmentType = typeof(CategoryView),
Title = "Fats",
ViewModel = vm.Category3
},
new CategoryTabsAdapter.FragmentInfo
{
FragmentType = typeof(CategoryView),
Title = "Vitamins",
ViewModel = vm.Category4
}
};
_viewPager.Adapter = new CategoryTabsAdapter(Activity, ChildFragmentManager, fragments);
}
_tablayout = view.FindViewById<TabLayout>(Resource.Id.sliding_tabs);
_tablayout.SetBackgroundColor(Android.Graphics.Color.Black);
_tablayout.SetupWithViewPager(_viewPager);
}
}
的
类别标签适配器:
的
的public class CategoryTabsAdapter : FragmentStatePagerAdapter
{
private readonly Context _context;
public IEnumerable<FragmentInfo> Fragments { get; private set; }
public CategoryTabsAdapter(Context context, FragmentManager fragmentManager, IEnumerable<FragmentInfo> fragments) : base(fragmentManager)
{
_context = context;
Fragments = fragments;
}
public override int Count
{
get { return Fragments.Count(); }
}
public override Fragment GetItem(int position)
{
var fragmentInfo = Fragments.ElementAt(position);
var fragment = Fragment.Instantiate(_context, Java.Lang.Class.FromType(fragmentInfo.FragmentType).Name);
((MvxFragment)fragment).ViewModel = fragmentInfo.ViewModel;
return fragment;
}
public override ICharSequence GetPageTitleFormatted(int position)
{
return new Java.Lang.String(Fragments.ElementAt(position).Title);
}
public class FragmentInfo
{
public string Title { get; set; }
public Type FragmentType { get; set; }
public IMvxViewModel ViewModel { get; set; }
}
}
的
类别视图片段
的
的public class CategoryView : MvxFragment<CategoryViewModel>
{
public override View OnCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState)
{
this.EnsureBindingContextIsSet(inflater);
var view = this.BindingInflate(Resource.Layout.category_view, container, false);
//Exception caused here :
//RetainInstance = true;
return view;
}
}
的
我是Xamarin和MvvmCross的新手,所以只能提出这么多的研究。任何一种方法的任何解决方案都会有很大的帮助。
P.S。这是我关于Stackoverflow的第一个问题。
答案 0 :(得分:1)
我认为您需要使用MvvmCross.Droid.Support.V4 Nuget包中的MvxCachingFragmentStatePagerAdapter。然后使用SetupWithViewPager()将其连接到TabLayout。
var viewPager = view.FindViewById<ViewPager>(Resource.Id.viewpager);
if (viewPager != null)
{
var fragments = new List<MvxCachingFragmentStatePagerAdapter.FragmentInfo>
{
new MvxCachingFragmentStatePagerAdapter.FragmentInfo(
"TitleA",
typeof (YourFragmentA),
typeof (YourViewModelA)),
new MvxCachingFragmentStatePagerAdapter.FragmentInfo(
"TitleB",
typeof (YourFragmentB),
typeof (YourViewModelB)),
new MvxCachingFragmentStatePagerAdapter.FragmentInfo(
"TitleC",
typeof (YourFragmentC),
typeof (YourViewModelC))
};
viewPager.Adapter = new MvxCachingFragmentStatePagerAdapter(Activity, ChildFragmentManager, fragments);
viewPager.OffscreenPageLimit = fragments.Count;
var tabLayout = view.FindViewById<TabLayout>(Resource.Id.tabs);
tabLayout.SetupWithViewPager(viewPager);
}
答案 1 :(得分:0)
每次都会重新创建标签,因为您使用的是FragmentStatePagerAdapter
而不是FragmentPagerAdapter
。从文档中FragmentPagerAdapter
:
此版本的寻呼机最适合在少数人使用时使用 通常会有更多静态片段被分页,例如一组 标签。用户访问的每个页面的片段将保留在其中 内存,虽然它的视图层次结构可能在不可见时被销毁。 这可能导致自片段以来使用大量内存 实例可以保持任意数量的状态。对于较大的集合 的页面,请考虑FragmentStatePagerAdapter。
FragmentStatePagerAdapter
:
当有大量的寻呼机时,此版本的寻呼机更有用 页面,更像列表视图。当页面不可见时 用户,他们的整个片段可能会被破坏,只保留 保存了该片段的状态。这允许寻呼机保持很多 与每个访问页面相关联的内存较少 FragmentPagerAdapter的代价可能是更多的开销 在页面之间切换。
所以请使用FragmentPagerAdapter
,但我认为它必须处于Activity
级别,而不是片段中的片段。