2017-01-04 3 views
1

Ich versuche Tabs durch MvvmCross in Xamarin zu implementieren. Ich habe MvxTabActivity in Android und MvxTabBarViewController in IOS gefunden. Beide funktionieren gut. Das Problem ist MvxTabActivity ist obselete. Gibt es Alternativen für MvxTabActivity?MvvmCross: Registerkarte Implementierung in Android

Ich fand eine andere Möglichkeit, dies zu implementieren, die TabLayout und einen ViewPager verwendet. Die Lösung fordert die Verwendung von Fragmenten in einem Fragment. Ich habe den Code für diesen Ansatz eingefügt. Das Problem hier ist, die Registerkarten zu wischen, alle Daten in vorherigen Registerkarten sind verloren. Ich habe versucht, RetainInstance = true zu verwenden, die folgende Ausnahme gab: "Kann Fragmente, die in anderen Fragmenten verschachtelt sind, nicht beibehalten."

Produktbeschreibung Aktivität:

[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(); 
     } 
    } 
} 

Nutrition Kategorie anzeigen Fragment:

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); 
    } 
} 

Kategorie Tabs Adapter:

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; } 
    } 
} 

Kategorie anzeigen Fragment

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; 
    } 
} 

Ich bin neu in Xamarin und MvvmCross, so konnte nur mit so viel Forschung kommen. Jede Lösung für beide Ansätze wäre eine große Hilfe.

P.S. Dies ist meine erste Frage zu Stackoverflow.

+0

Mögliches Duplikat von [Tabs in der Aktionsleiste mit mvvmcross] (http://stackoverflow.com/questions/20271805/tabs-in-the-actionbar-with-mvvmcross) – Demitrian

+0

Damit sind die Registerkarten sichtbar, aber die Beim Wischen zwischen 3 oder mehr Tabs gehen Daten verloren. –

Antwort

0

Ich denke, Sie müssen den MvxCachingFragmentStatePagerAdapter verwenden, der im MvvmCross.Droid.Support.V4 Nuget-Paket ist. Dann verbinden Sie es mit SetupWithViewPager() mit Ihrem 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); 
     } 
+0

Wenn Sie obigen Code beim Einrichten des Ansichtspagers verwenden, erhalten Sie: Android.Support.V4.App.Fragment + InstantiationException. Ausnahmebedingungsnachricht: Fragment kann nicht instanziiert werden nutritionrecommendor.droid.views.fragments.CategoryView: Stellen Sie sicher, dass der Klassenname existiert, öffentlich ist und einen leeren Konstruktor hat, der öffentlich ist –

+0

Haben Sie sichergestellt, dass der Klassenname existiert, öffentlich ist und hat einen leeren Konstruktor, der öffentlich ist? Andernfalls muss ich Ihre Implementierung des obigen Codes und der darin enthaltenen Fragmente sehen. –

+0

Ja, das habe ich auch überprüft. Wenn ich 2 Tabs verwende, gibt es keinen Datenverlust beim Wischen. Sobald jedoch die Anzahl der Tabs erhöht wird, kommt es zum Datenverlust. –

0

Ihre Tabs werden jedes Mal neu erstellt, weil Sie FragmentStatePagerAdapter statt FragmentPagerAdapter verwenden. Aus den Dokumenten, FragmentPagerAdapter:

Diese Version des Pagers ist am besten für die Verwendung, wenn eine Handvoll typischerweise statischer Fragmente gibt es bis hin zu ausgelagert, wie eine Reihe von Registerkarten. Das Fragment jeder Seite, die der Benutzer besucht, wird im Speicher gespeichert, obwohl seine Ansichtshierarchie zerstört werden kann, wenn sie nicht sichtbar ist. Dies kann dazu führen, dass eine erhebliche Menge an Speicher verwendet wird, da sich die Instanzen des Fragments auf einer beliebigen Menge an Zustand halten können.Für größere Sätze von Seiten, betrachten Sie FragmentStatePagerAdapter.

FragmentStatePagerAdapter:

Diese Version des Pagers ist nützlicher, wenn es eine große Anzahl der Seiten ist, eher wie eine Listenansicht arbeiten. Wenn Seiten für den Benutzer nicht sichtbar sind, kann ihr gesamtes Fragment zerstört werden, wobei nur der gespeicherte Zustand dieses Fragments gespeichert wird . Dies ermöglicht es dem Pager, sich an viel weniger Speicher im Zusammenhang mit jeder besuchten Seite im Vergleich zu FragmentPagerAdapter auf Kosten von möglicherweise mehr Aufwand zu halten, wenn zwischen den Seiten wechseln. So

FragmentPagerAdapter verwenden, aber ich denke, es wird auf der Activity Ebene sein, und nicht ein Fragment innerhalb eines Fragments.