MvvmCross:Android中的Tab实现

时间:2017-01-04 05:34:30

标签: android-fragments xamarin xamarin.android mvvmcross

我正在尝试通过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的第一个问题。

2 个答案:

答案 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级别,而不是片段中的片段。