CustomFragment in MVVMCross
Asked Answered
S

1

0

I have used the following template in my Android application which has navigation drawer has a list of options such as Settings.

https://github.com/MvvmCross/MvvmCross-Samples/tree/master/XPlatformMenus

Source code could be downloaded from the following url https://github.com/MvvmCross/MvvmCross-Samples

I wonder how could I able to make Settings page as a Dialog or CustomFragment which will look like similar to following image.

enter image description here

Seethrough answered 19/5, 2016 at 20:57 Comment(1)
The way we do this in our app is using a Custom presenter. The presenter holds a reference to the current Activity and we added methods DisplayDialog and DismissDialog which add the Fragment to the current Activity. This blog post on custom presenters is a good place to start: gregshackles.com/presenters-in-mvvmcross-a-primerAsel
Y
1

One approach that you could make use of is to create a custom implementation of Dialog. Following the XPlatformMenus sample you linked to, you could implement something as follows:

Generic Custom Dialog

This class inherits android Dialog control, and can be used with any XML/AXML layout you want. You could tightly couple it to a particular ViewModel/Layout or you can make it handle a generic ViewModel type. Here is an example of the generic type:

public class CustomDialog : Dialog, IMvxBindingContextOwner
{
    public CustomDialog(Context context, int layout, IMvxViewModel viewModel)
        : this(context, Resource.Style.CustomDialog)
    {
        this.BindingContext = new MvxAndroidBindingContext(context, (context as IMvxLayoutInflaterHolder));
        ViewModel = viewModel;
        Init(layout);
    }

    public CustomDialog(Context context, int themeResId)
        : base(context, themeResId)
    {
    }

    protected CustomDialog(IntPtr javaReference, JniHandleOwnership transfer)
        : base(javaReference, transfer)
    {
    }

    protected CustomDialog(Context context, bool cancelable, IDialogInterfaceOnCancelListener cancelListener)
        : base(context, cancelable, cancelListener)
    {
    }

    protected CustomDialog(Context context, bool cancelable, EventHandler cancelHandler)
        : base(context, cancelable, cancelHandler)
    {
    }

    private void Init(int layout)
    {
        SetContentView(layout);
    }

    public override void SetContentView(int layoutResID)
    {
        var view = this.BindingInflate(layoutResID, null);
        base.SetContentView(view);
    }

    public IMvxBindingContext BindingContext { get; set; }

    public object DataContext
    {
        get { return this.BindingContext.DataContext; }
        set { this.BindingContext.DataContext = value; }
    }

    public IMvxViewModel ViewModel
    {
        get { return this.DataContext as IMvxViewModel; }
        set { this.DataContext = value; }
    }
}

XML layout for modal:

<?xml version="1.0" encoding="utf-8" ?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:local="http://schemas.android.com/apk/res-auto"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:background="@color/colorPrimary">

    <Button
        android:id="@+id/btn_option"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="Show"
        local:MvxBind="Click ShowSettingsCommand"/>

    <Button
        android:id="@+id/btn_close"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_below="@id/btn_option"
        android:text="CLOSE"
        local:MvxBind="Click ShowCloseCommand"/>
</RelativeLayout>

CustomDialog style:

<resources>
  <style name="CustomDialog">
    <item name="android:windowIsFloating">true</item>
    <item name="android:windowNoTitle">true</item>
  </style>
</resources>

Custom Presenter

Create a custom presenter to handle the navigation to show/hide the dialog:

public class CustomPresenter : MvxFragmentsPresenter
{
    protected IMvxViewModelLoader MvxViewModelLoader => Mvx.Resolve<IMvxViewModelLoader>();

    CustomDialog _modal;

    public CustomPresenter(IEnumerable<Assembly> AndroidViewAssemblies) : base(AndroidViewAssemblies)
    {
    }

    protected override void ShowActivity(MvxViewModelRequest request, MvxViewModelRequest fragmentRequest = null)
    {
        if (!Intercept(request))
            base.ShowActivity(request, fragmentRequest);
    }

    protected override void ShowFragment(MvxViewModelRequest request)
    {
        if (!Intercept(request))
            base.ShowFragment(request);
    }

    private bool Intercept(MvxViewModelRequest request)
    {
        if (request.ViewModelType == typeof(ThirdViewModel))
        {
            var activity = Mvx.Resolve<IMvxAndroidCurrentTopActivity>().Activity;
            var viewModel = MvxViewModelLoader.LoadViewModel(request, null) as ThirdViewModel;
            _modal = new CustomDialog(activity, Resource.Layout.modal_popup, viewModel);
            _modal.Show();
            return true;
        }

        if (_modal != null)
        {
            _modal.Dismiss();
            _modal = null;
        }
        return false;
    }
}

Register your custom presenter in the setup class:

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

ViewModel

public class ThirdViewModel : BaseViewModel
{
    private MvxCommand _showSettingsCommand;
    public MvxCommand ShowSettingsCommand =>
        _showSettingsCommand ?? (_showSettingsCommand = new MvxCommand(() => ShowViewModel<HomeViewModel>()));

    private MvxCommand _showCloseCommand;
    public MvxCommand ShowCloseCommand =>
        _showCloseCommand ?? (_showCloseCommand = new MvxCommand(() => ShowViewModel<SettingsViewModel>()));
}
Yehudi answered 25/5, 2016 at 18:39 Comment(2)
I have just got a chance to implement the logic that you provided, but unfortunately I could not able to get it. Here is the github: github.com/texas16/DialogSeethrough
@hotspring, It seems the issues are in line 36 and line 39 of CustomPresenter.cs, which needs to use the ViewModel type i.e. ThirdViewModel not ThirdFragment . Additionally, in your Setup.cs you need to return a CustomPresenter instance. You can do this on line 43 replacing MvxFragmentsPresenter with your custom presenter type CustomPresenter.Yehudi

© 2022 - 2024 — McMap. All rights reserved.