Как правильно использовать фрагменты внутри TabLayout с MvvmCross 6.x - PullRequest
0 голосов
/ 11 октября 2018

Проблема

Я пытаюсь сделать очень простое подтверждение концепции с помощью TabLayout и фрагментов, используя MvvmCross 6.1.2.Для этого я реализовал действие с TabLayout и ViewPager, которые должны иметь две вкладки - каждая из которых содержит отдельный фрагмент только с одним TextView.

Но я получаю исключение, сопровождаемое падением во время выполнения, когда должно отображаться это действие:

Тип MvxTabLayoutPresentationAttribute не настроен в словаре презентатора

Код

Вот так выглядит мой код, который я реализовал, следуя примеру 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)

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)

[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 and FragmentTab2View.axml - это просто LinearLayouts с TextView)

Вопросы

  1. В чем причина возникшего исключения?
  2. Это рекомендуемый способ реализации TabLayout с фрагментами?
  3. Что можно сделать, чтобы решить эту проблему, следуя рекомендациям MvvmCross 6.x?

1 Ответ

0 голосов
/ 11 октября 2018

Это исключение выдается, потому что этот атрибут не зарегистрирован в AttributeTypesToActionsDictionary из Presenter.

В коде вы можете видеть, что в методе RegisterAttributeTypes он зарегистрирован, нопринять во внимание, что это в MvxAppCompatViewPresenter.Кроме того, в документах говорится, что этот атрибут работает только на AppCompat.

. Учитывая, что вы получаете это исключение, я могу предположить, что используется не-AppCompat презентатор, поэтому выMvxAndroidSetup.

. Для решения этой проблемы убедитесь, что вы используете AppCompat классы, в частности наследуйте от MvxAppCompatSetup, если у вас есть пользовательская установка, которая , где MvxAppCompatViewPresenter установлено.Также убедитесь, что вы используете MvxAppCompatApplication, поэтому, если заставляет использовать AppCompat версию Setup.


Обновление относительнопрокомментируйте исключение MvvmCross.Exceptions.MvxException: ViewPager not found

Я думаю, что проблема в том, что вы переходите к дочерним моделям представления в Initialize вместо того, чтобы делать это после создания представления вкладок, так что ViewPager может еще не инициализироватьсяпоэтому при попытке перейти к дочерним элементам он не найден.

Так же, как и в Playground Viewmodel , у вас должна быть команда, которая вызывает метод для навигации по вашей 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);
}

И, как в Playground View , вы должны вызывать команду в вашем 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

...