如何在MvvmCross 6.x中正确使用TabLayout中的片段 [英] How to properly use Fragments inside TabLayout with MvvmCross 6.x

查看:88
本文介绍了如何在MvvmCross 6.x中正确使用TabLayout中的片段的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试使用MvvmCross 6.1.2使用TabLayout和Fragments做一个非常简单的概念证明.为此,我实现了一个带有TabLayout和ViewPager的活动,该活动应该具有两个选项卡-每个选项卡包含一个只有一个TextView的不同片段.

I'm trying to make a very simple Proof of Concept with TabLayout and Fragments using MvvmCross 6.1.2. For this, I implemented an activity with a TabLayout and a ViewPager, which should have two tabs - each one containing a different fragment with just one TextView.

但是在显示此活动时,我收到了一个异常,然后在运行时崩溃:

But I'm receiving an exception followed by a crash on runtime, when this activity should be displayed:

未在MvxTabLayoutPresentationAttribute类型中配置 演示者字典

The type MvxTabLayoutPresentationAttribute is not configured in the presenter dictionary

代码

这是我的代码的样子,它是按照 Playground示例实现的文档:

AppStart.cs:

public class AppStart : MvxAppStart
{
    private readonly IMvxNavigationService _mvxNavigationService;

    public AppStart(IMvxApplication app, IMvxNavigationService mvxNavigationService)
        : base(app, mvxNavigationService)
    {
        _mvxNavigationService = mvxNavigationService;
    }

    protected override void NavigateToFirstViewModel(object hint = null)
    {
        Mvx.Resolve<IMvxNavigationService>().Navigate<TabLayoutViewModel>();
    }
}

TabLayoutViewModel.cs

public class TabLayoutViewModel: MvxViewModel
{
    public override async Task Initialize()
    {
        await base.Initialize();

        var tasks = new List<Task>();
        tasks.Add(Mvx.Resolve<IMvxNavigationService>().Navigate<FragmentTab1ViewModel>());
        tasks.Add(Mvx.Resolve<IMvxNavigationService>().Navigate<FragmentTab2ViewModel>());
        await Task.WhenAll(tasks);
    }
}

FragmentTab1ViewModel.cs (和FragmentTab2ViewModel.cs同样)

FragmentTab1ViewModel.cs (and FragmentTab2ViewModel.cs likewise)

public class FragmentTab1ViewModel : MvxViewModel
{
    public override Task Initialize()
    {
        return base.Initialize();
    }
}

TabLayoutViewController.cs

[MvxActivityPresentation]
[Activity(Label = "", ScreenOrientation = ScreenOrientation.Portrait, LaunchMode = LaunchMode.SingleTask, Theme = "@style/LoginTheme")]
public class TabLayoutViewController: MvxAppCompatActivity<TabLayoutViewModel>
{
    protected override void OnCreate(Bundle bundle)
    {
        base.OnCreate(bundle);

        SetContentView(Resource.Layout.TabLayoutView);

        var set = this.CreateBindingSet<TabLayoutViewController, TabLayoutViewModel>();

        set.Apply();
    }
}

TabLayoutView.axml

<?xml version="1.0" encoding="utf-8"?>
<android.support.design.widget.CoordinatorLayout 
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:orientation="vertical"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:alwaysDrawnWithCache="false"
    android:background="#f4f4f4"
    android:minWidth="25px"
    android:minHeight="25px">
  <android.support.design.widget.TabLayout
      android:id="@+id/tabsTeste"
      android:layout_width="match_parent"
      android:layout_height="wrap_content"
      android:paddingLeft="16dp"
      app:tabGravity="center"
      app:tabMode="scrollable" />
  <android.support.v4.view.ViewPager
      android:id="@+id/viewpagerTeste"
      android:layout_width="match_parent"
      android:layout_height="match_parent" />
</android.support.design.widget.CoordinatorLayout>

FragmentTab1ViewController.cs (和FragmentTab2ViewController.cs同样)

FragmentTab1ViewController.cs (and FragmentTab2ViewController.cs likewise)

[MvxTabLayoutPresentation(ActivityHostViewModelType = typeof(TabLayoutViewModel), ViewPagerResourceId = Resource.Id.viewpagerTest, TabLayoutResourceId = Resource.Id.tabsTest, Title = "Tab A")]
[Register("smartSolution.coleta.droid.view.FragmentTab1ViewController")]
public class FragmentTab1ViewController : MvxFragment<FragmentTab1ViewModel>
{
    public override Android.Views.View OnCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState)
    {
        base.OnCreateView(inflater, container, savedInstanceState);

        var view = this.BindingInflate(Resource.Layout.FragmentTab1View, null);

        inflater.Inflate(Resource.Layout.FragmentTab1View, container, true);

        var set = this.CreateBindingSet<FragmentTab1ViewController, FragmentTab1ViewModel>();

        set.Apply();

        return view;
    }
}

(FragmentTab1View.axml和FragmentTab2View.axml只是带有TextView的LinearLayouts)

(FragmentTab1View.axml and FragmentTab2View.axml are just LinearLayouts with a TextView)

  1. 引发异常的原因是什么?
  2. 这是使用片段实现TabLayout的推荐方法吗?
  3. 遵循MvvmCross 6.x的良好做法可以解决此问题?

推荐答案

抛出该异常是因为该属性未在PresenterAttributeTypesToActionsDictionary中注册.

That exception is thrown because that attribute is not registered in the AttributeTypesToActionsDictionary of the Presenter.

在代码中,您可以在方法 RegisterAttributeTypes 已注册,但要考虑到它在MvxAppCompatViewPresenter中.此外,在文档指出该属性仅适用于AppCompat.

In the code you can see that in the method RegisterAttributeTypes it's registered but take into account that it is in the MvxAppCompatViewPresenter. Furthermore in the docs it states that that attribute only works on AppCompat.

鉴于您收到该异常,我可以假定正在使用非AppCompat演示者,因此您正在使用MvxAndroidSetup.

Given that you are getting that exception I can assume that the non-AppCompat presenter is being used, therefore you are using MvxAndroidSetup.

要解决此问题,请确保使用的是AppCompat类,尤其是如果您具有强制使用SetupAppCompat版本.

To solve this make sure you are using AppCompat classes, in particular inherit from MvxAppCompatSetup if you have a custom Setup that is where the MvxAppCompatViewPresenter is set. Also make sure you are using MvxAppCompatApplication so if forces you to use the AppCompat version of the Setup.

更新有关对异常MvvmCross.Exceptions.MvxException: ViewPager not found

我认为问题在于您正在导航到Initialize中的子级视图模型,而不是在创建选项卡视图之后执行此操作,因此当您尝试导航至子级视图时,ViewPager可能尚未初始化,因此找不到.

I think that the problem is that you are navigating to the children viewmodels in the Initialize instead of doing this after the tabs view is created so the ViewPager may not be initialized yet when you try to navigate to the children, therefore it is not found.

So as in the Playground Viewmodel you should have a command that calls a method to do the navigation on your ViewModel:

...
ShowInitialViewModelsCommand = new MvxAsyncCommand(ShowInitialViewModels);
...

public IMvxAsyncCommand ShowInitialViewModelsCommand { get; private set; }

...

private async Task ShowInitialViewModels()
{
    var tasks = new List<Task>();
    tasks.Add(Mvx.Resolve<IMvxNavigationService>().Navigate<FragmentTab1ViewModel>());
    tasks.Add(Mvx.Resolve<IMvxNavigationService>().Navigate<FragmentTab2ViewModel>());
    await Task.WhenAll(tasks);
}

并与游乐场视图,则应在TabLayoutViewController中调用该命令:

And as in the Playground View you should call the command in your TabLayoutViewController:

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

    SetContentView(Resource.Layout.TabLayoutView);

    var set = this.CreateBindingSet<TabLayoutViewController, TabLayoutViewModel>();

    set.Apply();

    if (bundle == null)
    {
        ViewModel.ShowInitialViewModelsCommand.Execute();
    }
}

HIH

这篇关于如何在MvvmCross 6.x中正确使用TabLayout中的片段的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆