Search code examples
android-layoutandroid-fragmentsxamarinxamarin.androidmvvmcross

How can I properly load a different Activity layouts based on screen size with Mvx?


I'm developing an Xamarin Android Mvx5-beta application. When running on a small-screen device, I want to show a drawer navigation using the Toolbar and the hamburger-icon. On larger devices, e.g. tablets, I want a different layout conaining three columns. No drawer navigation but a static panel with navigation options and two other panels for content.

I started with the examples XPlatformMenus and Fragments to get a drawer navigation layout combined with the use of activities (with fragments) in different layouts qualifiers, like:

enter image description here

Question:

Using this approach, Android automaticly looks for an activity with the same name (e.g. main_activity.axml) in the appropriate layout-qualifier folders. But on the larger screens I don't need a drawer layout and I do need an extra column. The Mvx-viewmodel does not yet know what layout to render, so it just calls:

ShowViewModel<HomeViewModel>();
ShowViewModel<MenuViewModel>();

These ViewModels, for example MenuViewModel, are registered for fragments that require a navigation_frame, as shown in here:

[MvxFragment(typeof(MainViewModel), Resource.Id.navigation_frame)]
[Register("mydemoapp.droid.views.fragments.MenuFragment")]
public class MenuFragment : MvxFragment<MenuViewModel>, NavigationView.IOnNavigationItemSelectedListener
{
  <..>
}

So, rendering this same Activity in layout-sw600dp requires a navigation_frame. Which I don't want on these larger displays.

What would be the preferred design choise in this situation? I can think of two:

  1. Show/hide elements in the Activity programmatically by querying the screen info
  2. Don't make use of layout qualifiers, but design complete seperate Activities for larger screens and based on screen size let MVX Show ViewModel-A or ViewModel-B.

Any advice would be appreciated, many thanks in advance.


Solution

  • I think it depends how different your layout need to be between large screen and small screen form factors.

    Few UI differences

    In addition to using different layouts, you can define a bool property in your XML values resources that is different between standard and sw-600dp

    values

    <bool name="is_large_screen">false</bool>
    

    values-sw600dp

    <bool name="is_large_screen">true</bool>
    

    You can then read this value in your Android views and prevent methods like ShowViewModel<MenuViewModel>(); firing when on large screens by altering the method calls from the view.

    Many differences/Structural differences

    If they share the same business logic but have very different UI requirements and you want to keep large screen code separate. Then I would suggest sharing the ViewModels but creating two separate Activites and layouts to handle the UI presentation. Using this method requires a bit more setup as you have to override some default MvvmCross behaviors as by default you can not register multiple Activities/Fragments to the same ViewModel. Overriding the MvxViewModelViewTypeFinder view lookup FindTypeOrNull you can intercept the lookup and filter types base on naming conventions. For example all large screen views end with "Tablet". Using the is_large_screen bool you can flag which views to register.