如何在MvvmCross中构建自己的选项卡?

时间:2014-02-06 10:20:28

标签: android-fragments xamarin.android mvvmcross

我正在尝试在MonoDroid和MvvmCross中构建自己的标签。

构建我自己的标签的原因是我可以进一步控制它们。我想在每个屏幕上显示它们,即使它们不在选项卡中,我想控制某些选项卡上的点击。

在页面上加载两个片段很好,但是当我单击导航到下一个内容片段的选项卡片段或内容片段上的按钮时,我收到错误消息“发生了未处理的异常”。这不是那么有用。

 02-06 10:15:13.947 W/dalvikvm( 2040): JNI WARNING: JNI method called with exception pending
 02-06 10:15:13.947 W/dalvikvm( 2040):              in Lcirrious/mvvmcross/droid/fragging/MvxEventSourceFragmentActivity;.n_startActivityForResult:(Landroid/content/Intent;I)V (NewString)
 In mgmain JNI_OnLoad
 02-06 10:15:13.947 W/dalvikvm( 2040): Pending exception is:
 02-06 10:15:13.947 I/dalvikvm( 2040): android.content.ActivityNotFoundException: Unable to find explicit activity class {frags.droid/frags.droid.views.frags.ChildTwoView}; have you declared this activity in your AndroidManifest.xml?
 02-06 10:15:13.947 I/dalvikvm( 2040):   (raw stack trace not found)
 02-06 10:15:13.947 I/dalvikvm( 2040): "main" prio=5 tid=1 NATIVE
 02-06 10:15:13.947 I/dalvikvm( 2040):   | group="main" sCount=0 dsCount=0 obj=0x41aaf710 self=0x41a96210
 02-06 10:15:13.957 I/dalvikvm( 2040):   | sysTid=2040 nice=0 sched=0/0 cgrp=apps handle=1074675708
 02-06 10:15:13.957 I/dalvikvm( 2040):   | state=R schedstat=( 0 0 0 ) utm=164 stm=41 core=0
 02-06 10:15:13.967 I/dalvikvm( 2040):   #00  pc 000012fe  /system/lib/libcorkscrew.so (unwind_backtrace_thread+29)
 02-06 10:15:13.967 I/dalvikvm( 2040):   #01  pc 0006324e  /system/lib/libdvm.so (dvmDumpNativeStack(DebugOutputTarget const*, int)+33)
 02-06 10:15:13.967 I/dalvikvm( 2040):   #02  pc 000572b8  /system/lib/libdvm.so (dvmDumpThreadEx(DebugOutputTarget const*, Thread*, bool)+395)
 02-06 10:15:13.967 I/dalvikvm( 2040):   #03  pc 00057326  /system/lib/libdvm.so (dvmDumpThread(Thread*, bool)+25)
 02-06 10:15:13.967 I/dalvikvm( 2040):   #04  pc 0003b530  /system/lib/libdvm.so
 02-06 10:15:13.967 I/dalvikvm( 2040):   #05  pc 0003eef2  /system/lib/libdvm.so
 02-06 10:15:13.967 I/dalvikvm( 2040):   at cirrious.mvvmcross.droid.fragging.MvxEventSourceFragmentActivity.n_startActivityForResult(Native Method)
 02-06 10:15:13.967 I/dalvikvm( 2040):   at cirrious.mvvmcross.droid.fragging.MvxEventSourceFragmentActivity.startActivityForResult(MvxEventSourceFragmentActivity.java:110)
 02-06 10:15:13.967 I/dalvikvm( 2040):   at android.app.Activity.startActivity(Activity.java:3661)
 02-06 10:15:13.967 I/dalvikvm( 2040):   at android.app.Activity.startActivity(Activity.java:3629)
 02-06 10:15:13.967 I/dalvikvm( 2040):   at mono.android.view.View_OnClickListenerImplementor.n_onClick(Native Method)
 02-06 10:15:13.967 I/dalvikvm( 2040):   at mono.android.view.View_OnClickListenerImplementor.onClick(View_OnClickListenerImplementor.java:29)
 02-06 10:15:13.967 I/dalvikvm( 2040):   at android.view.View.performClick(View.java:4475)
 02-06 10:15:13.967 I/dalvikvm( 2040):   at android.view.View$PerformClick.run(View.java:18786)
 02-06 10:15:13.967 I/dalvikvm( 2040):   at android.os.Handler.handleCallback(Handler.java:730)
 02-06 10:15:13.967 I/dalvikvm( 2040):   at android.os.Handler.dispatchMessage(Handler.java:92)
 02-06 10:15:13.967 I/dalvikvm( 2040):   at android.os.Looper.loop(Looper.java:137)
 02-06 10:15:13.967 I/dalvikvm( 2040):   at android.app.ActivityThread.main(ActivityThread.java:5419)
 02-06 10:15:13.967 I/dalvikvm( 2040):   at java.lang.reflect.Method.invokeNative(Native Method)
 02-06 10:15:13.967 I/dalvikvm( 2040):   at java.lang.reflect.Method.invoke(Method.java:525)
 02-06 10:15:13.967 I/dalvikvm( 2040):   at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1187)
 02-06 10:15:13.967 I/dalvikvm( 2040):   at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1003)
 02-06 10:15:13.967 I/dalvikvm( 2040):   at dalvik.system.NativeStart.main(Native Method)

我的所有自定义代码都在下面。

我有自己的CustomPresenter

public class CustomPresenter : MvxAndroidViewPresenter, ICustomPresenter
{
    // map between view-model and fragment host which creates and shows the view based on the view-model type
    private Dictionary<Type, IFragmentHost> dictionary = new Dictionary<Type, IFragmentHost>();

    public override void Show(MvxViewModelRequest request)
    {
        IFragmentHost host;
        if (this.dictionary.TryGetValue(request.ViewModelType, out host))
        {
            if (host.Show(request))
            {
                return;
            }
        }
        base.Show(request);
    }

    public void Register(Type viewModelType, IFragmentHost host)
    {
        this.dictionary[viewModelType] = host;
    }
}

我使用MvxFragmentActivity作为我的主机视图,其中包含顶部的内容部分和底部的选项卡,这也实现了IFragmentHost。所有页面都将是片段,包括标签。

public class FirstView : MvxFragmentActivity, IFragmentHost
{

    ChildTwoView _childTwo;

    public bool Show(Cirrious.MvvmCross.ViewModels.MvxViewModelRequest request)
    {
        // create view model
        var loaderService = Mvx.Resolve<IMvxViewModelLoader>();
        var viewModel = loaderService.LoadViewModel(request, null /* saved state */);

        _childTwo = (ChildTwoView)SupportFragmentManager.FindFragmentById(Resource.Layout.childtwoview);

        var customPresenter = Mvx.Resolve<ICustomPresenter>();
        //customPresenter.Register(Type)

        // decide which fragment to create based on the view-model type

        var fm = this.SupportFragmentManager;
        var ft = fm.BeginTransaction();


        if (viewModel.GetType().Name == "ChildTwoViewModel")
        {
            var fragmentView = new ChildTwoView();
            ft.Replace(Resource.Id.childViewHost, fragmentView);
        }

        //var fragmentView = viewModel.GetType().Name;
        // load fragment into view


        ft.AddToBackStack(null);
        ft.Commit();
        return true;
    }

    protected override void OnCreate(Bundle bundle)
    {
        base.OnCreate(bundle);
        SetContentView(Resource.Layout.FirstView);

        var childView = new ChildView()
        {
            ViewModel = new ChildViewModel()
        };

        var tabView = new TabView()
        {
            ViewModel = new TabViewModel()
        };
        var fm = this.SupportFragmentManager;
        var ft = fm.BeginTransaction();
        //ft.Add(childView, "child");

        ft.Replace(Resource.Id.childViewHost, childView, "child");


        ft.Replace(Resource.Id.tabViewHost, tabView, "tab");
        ft.Commit();
    }

}

我在Setup.cs中设置了这些

protected override IMvxAndroidViewPresenter CreateViewPresenter()
{
    var customPresenter = new CustomPresenter();
    Mvx.RegisterSingleton<ICustomPresenter>(customPresenter);
    return customPresenter;
}

非常感谢所有帮助。

修改

我决定不采用这种方法,并使用标准的Android TabHost来保持应用之间的一致性。

1 个答案:

答案 0 :(得分:2)

错误说明了一切。您很可能忘记在Activity添加ChildTwoView属性,例如:

[Activity]
public class ChildTwoView : Activity { ... }

等等,您的ChildTwoView不是Activity,之后您无法在演示者中使用内置的Show方法。它不支持Fragments