Implementing BottomNavigationView with a custom Behavior (Xamarin)

So, I'll be writing about how to implement a BottomNavigationView using a CoordinatorLayout, complete with its own custom behavior (hides itself when you slide down, and shows itself when you slide up), which is defined in Material Design guidelines but not implemented by default.

Here's the layout file (.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:id="@+id/main_content"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

  <android.support.design.widget.AppBarLayout
      android:id="@+id/appbar"
      android:layout_width="match_parent"
      android:layout_height="wrap_content"
      android:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar">

    <android.support.v7.widget.Toolbar
        android:id="@+id/toolbar"
        android:layout_width="match_parent"
        android:layout_height="?attr/actionBarSize"
        android:background="?attr/colorPrimary"
        app:popupTheme="@style/ThemeOverlay.AppCompat.Light"
        app:layout_scrollFlags="scroll|enterAlways|snap" />

  </android.support.design.widget.AppBarLayout>

  <FrameLayout
      android:id="@+id/main_container"
      android:layout_width="match_parent"
      android:layout_height="match_parent"
      android:layout_above="@+id/bottom_navigation"
      app:layout_behavior="@string/appbar_scrolling_view_behavior"
      android:layout_alignParentTop="true">

    <TextView
        android:text="@string/version_number"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_below="@android:id/text1"
        android:padding="@dimen/small_margin"
        android:ellipsize="end"
        android:maxLines="4"
        style="?android:textAppearanceSmall" />

  </FrameLayout>

  <android.support.design.widget.BottomNavigationView
      android:id="@+id/bottom_navigation"
      android:layout_width="match_parent"
      android:layout_height="wrap_content"
      android:background="@color/primaryDark"
      android:foregroundTint="@color/accent"
      app:itemIconTint="@android:color/white"
      app:itemTextColor="@android:color/white"
      app:layout_anchor="@+id/main_container"
      app:layout_anchorGravity="bottom"
      app:layout_behavior="com.companyname.xamarinnative.BottomNavigationViewBehavior"
      app:menu="@menu/bottom_navigation_main" />

</android.support.design.widget.CoordinatorLayout>

Here's the menu file (save it as /Resources/menu/bottom_navigation_main.xml)

<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto">
  <item
      android:id="@+id/action_favorites"
      android:enabled="true"
      android:icon="@android:drawable/ic_menu_save"
      android:title="Top"
      app:showAsAction="ifRoom" />
  <item
      android:id="@+id/action_schedules"
      android:enabled="true"
      android:icon="@android:drawable/ic_menu_save"
      android:title="Near"
      app:showAsAction="ifRoom" />
  <item
      android:id="@+id/action_music"
      android:enabled="true"
      android:icon="@android:drawable/ic_menu_save"
      android:title="My"
      app:showAsAction="ifRoom" />
</menu>

Here's the HomeActivity.cs

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

using Android.App;
using Android.Content;
using Android.OS;
using Android.Runtime;
using Android.Views;
using Android.Widget;
using Android.Support.Design.Widget;

namespace XamarinNative.Droid.Activities
{
    //[Activity(Label = "HomeActivity")]
    [Activity(Label = "HomeActivity")]
    public class HomeActivity : BaseActivity
    {

        BottomNavigationView bottomNavigationView;

        /// <summary>
        /// Sets the layout file
        /// </summary>
        protected override int LayoutResource => Resource.Layout.activity_home;

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

            // Create your application here

            // Setup the top toolbar
            SupportActionBar.SetDisplayHomeAsUpEnabled(false);
            SupportActionBar.SetHomeButtonEnabled(false);

            // Setup BottomNavigationView clicks 
            bottomNavigationView = FindViewById<BottomNavigationView>(Resource.Id.bottom_navigation);

            bottomNavigationView.NavigationItemSelected += (sender, e) =>
            {
                switch (e.Item.ItemId)
                {
                    case Resource.Id.action_favorites:
                        Toast.MakeText(this, "meow", ToastLength.Short).Show();

                        Android.Support.V4.App.FragmentTransaction fragmentTransaction = this.SupportFragmentManager.BeginTransaction();
                        BrowseFragment browseFragment = new BrowseFragment();
                        fragmentTransaction.Replace(Resource.Id.main_container, browseFragment);
                        fragmentTransaction.Commit();

                        break;

                    case Resource.Id.action_schedules:

                        Android.Support.V4.App.FragmentTransaction fragmentTransaction2 = this.SupportFragmentManager.BeginTransaction();
                        AboutFragment aboutFragment = new AboutFragment();
                        fragmentTransaction2.Replace(Resource.Id.main_container, aboutFragment);
                        fragmentTransaction2.Commit();

                        break;
                }
            };


        }
    }
}

...and here's the BottomNavigationViewBehavior

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

using Android.App;
using Android.Content;
using Android.OS;
using Android.Runtime;
using Android.Views;
using Android.Widget;
using Android.Support.Design.Widget;
using Android.Util;
using Java.Lang;
using Android.Support.V4.View;

namespace XamarinNative.Droid.Extensions
{
    [Register("com.companyname.xamarinnative.BottomNavigationViewBehavior")]
    public class BottomNavigationViewBehavior :
        CoordinatorLayout.Behavior
    {
        private int height;

        public BottomNavigationViewBehavior(Context context, IAttributeSet attrs) : base()
        {

        }

        public override bool OnLayoutChild(CoordinatorLayout parent, Java.Lang.Object child, int layoutDirection)
        {
            BottomNavigationView childView = child.JavaCast<BottomNavigationView>();
            this.height = childView.Height;
            return base.OnLayoutChild(parent, child, layoutDirection);
        }

        public override bool OnStartNestedScroll(CoordinatorLayout coordinatorLayout, Java.Lang.Object child, View directTargetChild, View target, int nestedScrollAxes)
        {
            return nestedScrollAxes == ViewCompat.ScrollAxisVertical;
            //return base.OnStartNestedScroll(coordinatorLayout, child, directTargetChild, target, nestedScrollAxes);
        }

        public override void OnNestedScroll(CoordinatorLayout coordinatorLayout, Java.Lang.Object child, View target, int dxConsumed, int dyConsumed, int dxUnconsumed, int dyUnconsumed)
        {

            BottomNavigationView childView = child.JavaCast<BottomNavigationView>();

            if (dyUnconsumed > 0)
            {
                this.SlideDown(childView);
            }
            else if (dyUnconsumed < 0)
            {
                this.SlideUp(childView);
            } 

            //base.OnNestedScroll(coordinatorLayout, child, target, dxConsumed, dyConsumed, dxUnconsumed, dyUnconsumed);
        }

        private void SlideUp(BottomNavigationView child)
        {
            child.ClearAnimation();
            child.Animate().TranslationY(0).SetDuration(200);
        }

        private void SlideDown(BottomNavigationView child)
        {
            child.ClearAnimation();
            child.Animate().TranslationY(height).SetDuration(200);
        }
    }
}

 

 

 

 

 

 

No installed provisioning profiles match the installed iOS signing identities

No installed provisioning profiles match the installed iOS signing identities

If you get this error message while trying to deploy your application on your iPhone/iPad, then it simply means as it said, you have not deployed any provisioning profile on your Mac.

Basically, what we need to do is to install a provisioning profile inside your Mac using XCode.

The whole process for free provisioning can be found here:

https://developer.xamarin.com/guides/ios/getting_started/installation/device_provisioning/free-provisioning/

..however, I'm going to walk through it here as well because the screenshots over there seems outdated.

First, you'll need an AppleId. If you don't have one already, sign up for one here: appleid.apple.com.

Next, open Xcode. Open Spotlight (Command + Space), Xcode.

Before everything, you'll need to add your AppleID first. So at the bar at the top-left of the monitor, click XCode and click Preferences. Click the Accounts tab. Click the + button at the bottom left and add your AppleID account.

Once you have added your AppleID, click on your AppleID and click on Manage Certificates at the bottom right. Click the + button and choose iOS Development.

Now once it's finished, close the preference window.

Plug in your iPad or iPhone if you haven't into your Mac.

Click Create a new XCode Project, choose Single View Application. 

Now you'll see the project properties page. Change the bundle identifier to match the one you have in Xamarin.iOS.

Under the Signing section, select the profile you added before. Now if you have plugged in your device, XCode will automatically register a provisioning profile for the device for you.

Now you're done. Try deploying from your Visual Studio and start the app.

 

From Zero to Can-lah: Xamarin + MVVMCross 5 Tutorial: Part 5: iOS

Yay! Now we're finally making an iOS project. Let's go!

Add New Project

Well, you know the drill. Right click on your Solution and Add New Project.

Search for Single View App (iOS) and name it HelloWorld.UI.Ios. Click OK.

Install MVVMCross

Go to Package Manager Console. Change the default project to HelloWorld.UI.Ios. Execute

Install-Package MVVMCross

Add Reference to Core Project

Same.. Add reference to HelloWorld.Core Project

Add Setup Class

Now, add a Setup.cs at the root iOS project. It'll need to inherit MvxIosSetup, as per the following code.

using MvvmCross.iOS.Platform;
using MvvmCross.iOS.Views.Presenters;
using MvvmCross.Core.ViewModels;
using HelloWorld.Core;

namespace HelloWorld.UI.Ios
{
    public class Setup : MvxIosSetup
    {
        public Setup(MvxApplicationDelegate appDelegate, IMvxIosViewPresenter presenter)
        : base(appDelegate, presenter)
        {
        }

        protected override IMvxApplication CreateApp()
        {
            return new App();
        }
    }
}

Modify AppDelegate

Now, we need to tell iOS to use our Setup class. We do that by modifying the AppDelegate class.

We need to change the AppDelegate to inherit from MvxApplicationDelegate, like so:

public partial class AppDelegate : MvxApplicationDelegate
And to tell it to use MvvmCross setup and presenter upon finished loading, like so:
var presenter = new MvxIosViewPresenter(this, Window);

var setup = new Setup(this, presenter);
setup.Initialize();

var startup = Mvx.Resolve<IMvxAppStart>();
startup.Start();
Your AppDelegate.cs should look like this:
using Foundation;
using MvvmCross.Core.ViewModels;
using MvvmCross.iOS.Platform;
using MvvmCross.iOS.Views.Presenters;
using MvvmCross.Platform;
using UIKit;

namespace HelloWorld.UI.Ios
{
    // The UIApplicationDelegate for the application. This class is responsible for launching the 
    // User Interface of the application, as well as listening (and optionally responding) to 
    // application events from iOS.
    [Register("AppDelegate")]
    public class AppDelegate : MvxApplicationDelegate
    {
        // class-level declarations

        public override UIWindow Window
        {
            get;
            set;
        }

        public override bool FinishedLaunching(UIApplication application, NSDictionary launchOptions)
        {
            // Override point for customization after application launch.
            // If not required for your application you can safely delete this method

            Window = new UIWindow(UIScreen.MainScreen.Bounds);

            var presenter = new MvxIosViewPresenter(this, Window);

            var setup = new Setup(this, presenter);
            setup.Initialize();

            var startup = Mvx.Resolve<IMvxAppStart>();
            startup.Start();

            Window.MakeKeyAndVisible();

            return true;
        }

        public override void OnResignActivation(UIApplication application)
        {
            // Invoked when the application is about to move from active to inactive state.
            // This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) 
            // or when the user quits the application and it begins the transition to the background state.
            // Games should use this method to pause the game.
        }

        public override void DidEnterBackground(UIApplication application)
        {
            // Use this method to release shared resources, save user data, invalidate timers and store the application state.
            // If your application supports background exection this method is called instead of WillTerminate when the user quits.
        }

        public override void WillEnterForeground(UIApplication application)
        {
            // Called as part of the transiton from background to active state.
            // Here you can undo many of the changes made on entering the background.
        }

        public override void OnActivated(UIApplication application)
        {
            // Restart any tasks that were paused (or not yet started) while the application was inactive. 
            // If the application was previously in the background, optionally refresh the user interface.
        }

        public override void WillTerminate(UIApplication application)
        {
            // Called when the application is about to terminate. Save data, if needed. See also DidEnterBackground.
        }
    }
}

Setup Your Mac

Now, we're going to Add a View. Now if this is your first time with Xamarin.iOS, you'll need to connect your Visual Studio to your Mac as the build server. If you don't connect your PC to your Mac, you can't develop the view.

Here are the steps

Buy/Steal a Mac if you don't have one.

Turn on your Mac.

Click on the Apple icon at the top left, click About This Mac. Make sure the version is 10.12 Sierra (this is the version this tutorial is written based on, you can try any newer builds later but I don't know if it'll work). If it's not, update it to 10.12 Sierra. You can update it by clicking on the Apple icon > App Store > Updates. If you don't do this, the Xamarin Mac Agent will not be able to connect to your Mac because reasons.

Version is good? Now there are 2 things you'll need to install and update.

Install XCode 8.3 or above. You can do that by clicking on the Apple > App Store > Search for XCode. Install it.

Install Visual Studio for Mac. You'll need to download it at https://www.visualstudio.com/ using your Mac. More detailed steps here: https://docs.microsoft.com/en-us/visualstudio/mac/installation

Done all that? Nice. Now you need your Mac's IP. Click on the Wifi icon somewhere on the top right. Right Click > Open Network Preferences. Take note of the IP Address.

Awesome. Now go back to your darling PC. Go to Tools > iOS > Xamarin Mac Agent.

You can follow the instructions on the screen. But I'll walk you through anyways.

On your mac, open Spotlight (press Cmd+Space), search for Remote Login, open the Sharing System Preferences.

Enable the "Remote Login" option.

Select Allow Access for Only These Users. Make sure your user is in the list.

Get your Mac's username and password. Note that what you always see on your Mac is the display name. If you don't remember the username, open spotlight (cmd + space), type terminal, open terminal. Use " ls /users " to get a list of users and guess your username from there.

Now back to your PC. Click 'Next'. You'll reach the Xamarin Mac Agent selection page.

Now this is important. Click the Add Mac... button and fill in your Mac's IP Address. Do NOT click on anything in the list. At the time of writing, there may be a bug where the Mac agent simply refuses to connect to Visual Studio when you create a Storyboard later, or maybe I'm just stupid, but anyways do not select from the list. Fill in your IP Address manually in the Add Mac... dialog. Click enter. And after it has finished refreshing, THEN click on your IP in the list.

Now it's going to ask for your Username and Password. Fill it in. Make sure your Mac screen is on and not in sleep mode.

Everything okay? Alright, give yourself a pat on the back. You've earned it.

Add View

Hey, we're not done yet. Finally, we're going to add a view. We're going to use a Storyboard as our view.

Create a Views folder. And inside the Views folder, Right Click > Add New Item > StoryboardViewController. Name it HomeView.cs.

Now, you're going to have 2 things added to your project, which are HomeView.cs and HomeView.storyboard.

Modify HomeView.cs

Let's modify HomeView.cs first.

Inside HomeView.cs, we'll need to inherit HomeView from MvxViewController, and decorate it with the [MvxFromStoryboard] attribute, to tell MVVMCross to look for the storyboard as the view.

Your HomeView.cs class will look like this

using System;
using System.Drawing;

using Foundation;
using UIKit;
using MvvmCross.iOS.Views;
using HelloWorld.Core.ViewModels;

namespace HelloWorld.UI.Ios.Views
{
    [MvxFromStoryboard]
    public partial class HomeView : MvxViewController<HomeViewModel>
    {
        public HomeView(IntPtr handle) : base(handle)
        {
        }

        public override void DidReceiveMemoryWarning()
        {
            // Releases the view if it doesn't have a superview.
            base.DidReceiveMemoryWarning();

            // Release any cached data, images, etc that aren't in use.
        }

        #region View lifecycle

        public override void ViewDidLoad()
        {
            base.ViewDidLoad();

            // Perform any additional setup after loading the view, typically from a nib.
        }

        public override void ViewWillAppear(bool animated)
        {
            base.ViewWillAppear(animated);
        }

        public override void ViewDidAppear(bool animated)
        {
            base.ViewDidAppear(animated);
        }

        public override void ViewWillDisappear(bool animated)
        {
            base.ViewWillDisappear(animated);
        }

        public override void ViewDidDisappear(bool animated)
        {
            base.ViewDidDisappear(animated);
        }

        #endregion
    }
}

 

Modify HomeView.storyboard

Yay, now we're going to modify our storyboard file. Open the storyboard file and you should see this screen.

If you couldn't load the Storyboard, it might be because your Mac is in sleep mode. Turn it on again and make sure you've logged in again.

Now open the Toolbox and drag a ViewController to the screen. It'll be like this: 

Now we need to tell that we want to use HomeView.cs as the ViewController of this screen. So first click on the View Controller. Then open the Properties window on the right. You'll need to do 2 things:

  • Change the class to HomeView.
  • Change the Storyboard ID to HomeView (MVVMCross needs this for reference)

You've done setting up the Storyboard. Lastly, open Toolbox and select Label, drag it onto the screen. Change its name to Hello World.

Okay.. You're done!

Run It

For now, we'll run it on the emulator. In the top toolbar change the Startup project to HelloWorld.UI.Ios and the Play button to iPhone 7 (or anything that you want, like so). 

Click Play.

Now the iPhone 7 emulator should start on your Mac. Congratulations!

Run It on Your iPhone/iPhad

Now, to run it on your real iPhone, simply plug in your iphone to your Mac (NOT your PC) and change the Play button at the top toolbar to Device.

But noooo. If it's your first time, you're going to get this error:

"No installed provisioning profiles match the installed iOS signing identities".

What happens is that iOS requires you to install provisioning profiles for your app in your Mac before you can deploy it anywhere.

Basically, what we need to do is to install a provisioning profile inside your Mac using XCode.

The whole process for free provisioning can be found here:

https://developer.xamarin.com/guides/ios/getting_started/installation/device_provisioning/free-provisioning/

..however, I'm going to walk through it here as well because the screenshots over there seems outdated.

First, you'll need an AppleId. If you don't have one already, sign up for one here: appleid.apple.com.

Next, double check your iOS bundle identifier. On your HelloWorld.UI.Ios, double-click on Properties > iOS Application and look at the Identifier box.

Next, open Xcode. Open Spotlight (Command + Space), Xcode.

Before everything, we're going to add our AppleID first. So at the bar at the top-left of the monitor, click XCode and click Preferences. Click the Accounts tab. Click the + button at the bottom left and add your AppleID account.

Once you have added your AppleID, click on your AppleID and click on Manage Certificates at the bottom right. Click the + button and choose iOS Development.

Now once it's finished, close the preference window.

Plug in your iPad or iPhone if you haven't.

Click Create a new XCode Project, choose Single View Application. Name the application HelloWorld.UI.Ios. Notice the bundle identifier. It's okay because we can change it later. Save it at any path you like and click 'OK'.

Now you'll see the project properties page. Change the bundle identifier to match the one you have in Xamarin.iOS, which is com.companyname.HelloWorld.UI.Ios.

Under the Signing section, select the profile you added before. Now if you have plugged in your device, XCode will automatically register a provisioning profile for the device for you.

Once you have done everything, open your dear PC again.

Now at the play toolbar, change it to Device. Deploy your HelloWorld.UI.Ios. And then click 'Play'. Congratulations!

The whole example source code can be accessed here: 

https://github.com/purrmiaw/HelloWorld.Core/

 

 

 

 

From Zero to Can-lah: Xamarin + MVVMCross 5 Tutorial: Part 4: Android

Alright, so now we're going to make the Android UI for our humble Hello World app.

Add Android Project

First, right click on your solution, select New Project and select Blank App (Android).

Name it HelloWorld.UI.Android. Click OK.

Awesome!

Now delete that MainActivity.cs and the main.axml located in /Resources/layout/ ;)

Install MVVMCross

Now open Package Manager Console and key in:

install-package mvvmcross

...to install MVVMCross.

Add Reference to Core Project

Right click on your Android project References, Add Reference and select Project > HelloWorld.Core

Add Setup Class

Likewise, we need to setup our Android app to use MVVMCross. So add a file named Setup.cs at the root of the project with the following code:

using Android.Content;
using HelloWorld.Core;
using MvvmCross.Core.ViewModels;
using MvvmCross.Droid.Platform;

namespace HelloWorld.UI.Android
{
    public class Setup : MvxAndroidSetup
    {
        public Setup(Context applicationContext)
        : base(applicationContext)
        {
        }

        protected override IMvxApplication CreateApp()
        {
            return new App();
        }
    }
}

Add View

Add Layout

Now we're going to add a View for our HomeView. Just like UWP, there's the AXML file and the code-behind file.

Now go to /Resources/layout/ . Right click, add new item and add an Android Layout. Name it home_view.axml.

Now inside the home_view.axml, put this xml inside. You can try dissecting it yourself. Don't worry if your don't know what's a LinearLayout yet :).

 

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
              xmlns:local="http://schemas.android.com/apk/res-auto"
    android:orientation="vertical"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

  <TextView
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:text="Hello World!" />
  
</LinearLayout>

Add Code Behind

Now for the code behind. In your Android project root, add a new folder named Views. Inside it add a HomeView class.

The HomeView class will need to inherit from MvxActivity for MVVMCross to recognize it as the code behind.

The HomeView class need to also be decorated with the [Activity] attribute for MVVMCross to recognize it.

The following is the code:

 

using Android.App;
using MvvmCross.Droid.Views;

namespace HelloWorld.UI.Android.Views
{
    [Activity(MainLauncher=true)]
    public class HomeView : MvxActivity
    {
        protected override void OnViewModelSet()
        {
            SetContentView(Resource.Layout.home_view);
        }
    }
}

Complete!

Yay, you did it! Now, to run it, change your StartUp project at the top toolbar to HelloWorld.UI.Android. And then select any emulator, like so:

However, if you're like me, who prefer to run it on a phone immediately, you'll need to enable the Developer Mode on your Android first.

It's hidden though, so we'll need to enable it first.

This may be different depending on the device, but basically you'll need to go to Settings > About Phone > Build Number. Now, tap on the Build Number 7 times. Once you pressed enough times, you will get the message "You are now a developer!".

Now, go back to Settings. You will now see the Developer Options section. Now turn it on (if it's not already on) and turn on USB Debugging.

Alright, now connect your Android phone to your PC. Now your device should be available at the top toolbar, like so:

Nice! Now as usual, we'll need to Deploy first. Right click on your Android project, click Deploy.

And after it's done, click the Play button at the top toolbar.

Nice! Enjoy and bask yourself in the glory of the HelloWorld Android app.

Notes:

Notice the line...

[Activity(MainLauncher=true)]

..The MainLauncher=true argument is the one that tells Xamarin.Android which activity is supposed to be the main launcer of the app.

"But I thought I've defined the HomeViewModel as the first viewmodel of the app in HelloWorld.Core.App?" Yes, you did. However, due to the intricacies of Android, there's no way for Xamarin.Android to access the App class, they can only rely on the Activity attribute or the AndroidManifest file. After an activity is launched that Xamarin.Android can access the App.cs file.

The usual strategy to handle this is to create a SplashScreen view and mark it as the MainLauncher. The SplashScreen will then access App.cs and navigate to the default view model defined in App.cs, which in our case is HomeViewModel. We won't do that in this HelloWorld tutorial just yet :).

 

From Zero to Can-lah: Xamarin + MVVMCross 5 Tutorial: Part 3: Universal Windows Platform

Alright, so we're now going to make the Universal Windows Platform (UWP) implementation of our humble Hello World app.

Create New UWP Project

Right click on your solution (Solution 'HelloWorld.Core') and click Add New Project

Select the Blank App (Universal Windows) project.

Name it 'HelloWorld.UI.Uwp'

You will be greeted with this dialog. Simply leave it at the default settings. This is my default settings:

Install MVVMCross

Open your Package Manager Console. Change the Default project to HelloWorld.UI.Uwp and type

Install-Package MvvmCross

Press enter and MVVMCross will now be installed.

Add Reference to Core Project

We want the UWP project to refer to our core project. So go to References -> Right Click -> Add Reference -> Select Projects -> Tick 'HelloWorld.Core' and click OK.

Add a Setup Class

Now, we need to tell UWP to use MVVMCross and our Core project as the handler. And to do that, we need to add a Setup class.

Simply add the following class to the root of your project

using MvvmCross.Core.ViewModels;
using MvvmCross.Uwp.Platform;
using Windows.UI.Xaml.Controls;

namespace HelloWorld.UI.Uwp
{
    public class Setup : MvxWindowsSetup
    {
        public Setup(Frame rootFrame) : base(rootFrame)
        {
        }

        protected override IMvxApplication CreateApp()
        {
            return new Core.App();
        }
    }
}

Modify the App.xaml.cs to use Setup

Now that we have a Setup class, we need to tell UWP to actually use our Setup class when UWP starts. To do this, we modify the App.xaml.cs file. We need to replace these lines:

// When the navigation stack isn't restored navigate to the first page,
// configuring the new page by passing required information as a navigation
// parameter
rootFrame.Navigate(typeof(MainPage), e.Arguments);

...with this:

var setup = new Setup(rootFrame);
setup.Initialize();

var start = Mvx.Resolve<IMvxAppStart>();
start.Start();

So, your whole App.xaml.cs should look like this

using MvvmCross.Core.ViewModels;
using MvvmCross.Platform;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Runtime.InteropServices.WindowsRuntime;
using Windows.ApplicationModel;
using Windows.ApplicationModel.Activation;
using Windows.Foundation;
using Windows.Foundation.Collections;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;
using Windows.UI.Xaml.Controls.Primitives;
using Windows.UI.Xaml.Data;
using Windows.UI.Xaml.Input;
using Windows.UI.Xaml.Media;
using Windows.UI.Xaml.Navigation;

namespace HelloWorld.UI.Uwp
{
    /// <summary>
    /// Provides application-specific behavior to supplement the default Application class.
    /// </summary>
    sealed partial class App : Application
    {
        /// <summary>
        /// Initializes the singleton application object.  This is the first line of authored code
        /// executed, and as such is the logical equivalent of main() or WinMain().
        /// </summary>
        public App()
        {
            this.InitializeComponent();
            this.Suspending += OnSuspending;
        }

        /// <summary>
        /// Invoked when the application is launched normally by the end user.  Other entry points
        /// will be used such as when the application is launched to open a specific file.
        /// </summary>
        /// <param name="e">Details about the launch request and process.</param>
        protected override void OnLaunched(LaunchActivatedEventArgs e)
        {
            Frame rootFrame = Window.Current.Content as Frame;

            // Do not repeat app initialization when the Window already has content,
            // just ensure that the window is active
            if (rootFrame == null)
            {
                // Create a Frame to act as the navigation context and navigate to the first page
                rootFrame = new Frame();

                rootFrame.NavigationFailed += OnNavigationFailed;

                if (e.PreviousExecutionState == ApplicationExecutionState.Terminated)
                {
                    //TODO: Load state from previously suspended application
                }

                // Place the frame in the current Window
                Window.Current.Content = rootFrame;
            }

            if (e.PrelaunchActivated == false)
            {
                if (rootFrame.Content == null)
                {
                  
                    var setup = new Setup(rootFrame); // Changed line
                    setup.Initialize();  // Changed line

                    var start = Mvx.Resolve<IMvxAppStart>();  // Changed line
                    start.Start();  // Changed line
                }
                // Ensure the current window is active
                Window.Current.Activate();
            }
        }

        /// <summary>
        /// Invoked when Navigation to a certain page fails
        /// </summary>
        /// <param name="sender">The Frame which failed navigation</param>
        /// <param name="e">Details about the navigation failure</param>
        void OnNavigationFailed(object sender, NavigationFailedEventArgs e)
        {
            throw new Exception("Failed to load Page " + e.SourcePageType.FullName);
        }

        /// <summary>
        /// Invoked when application execution is being suspended.  Application state is saved
        /// without knowing whether the application will be terminated or resumed with the contents
        /// of memory still intact.
        /// </summary>
        /// <param name="sender">The source of the suspend request.</param>
        /// <param name="e">Details about the suspend request.</param>
        private void OnSuspending(object sender, SuspendingEventArgs e)
        {
            var deferral = e.SuspendingOperation.GetDeferral();
            //TODO: Save application state and stop any background activity
            deferral.Complete();
        }
    }
}

Add View

Cool, now that we have completed the setup, we can start adding views to our UWP app.

Since we have a HomeViewModel, we will now create a HomeView as the view.

Add a new folder named Views in your UWP project.

Inside the Views folder, add new item and choose XAML > Blank Page and name it HomeView.xaml. 

Now the HomeView.xaml and HomeView.xaml.cs file should be added to your project.

Modify HomeView to use HomeViewModel

We're not done yet! Now we need to tell the page to use MVVMCross and reference HomeViewModel as its ViewModel.

Open the HomeView.xaml.cs file and change the inheritance from Page to MvxWindowsPage as per below:

using MvvmCross.Uwp.Views;

// The Blank Page item template is documented at https://go.microsoft.com/fwlink/?LinkId=234238

namespace HelloWorld.UI.Uwp.Views
{
    /// <summary>
    /// An empty page that can be used on its own or navigated to within a Frame.
    /// </summary>
    public sealed partial class HomeView : MvxWindowsPage
    {
        public HomeView()
        {
            this.InitializeComponent();
        }
    }
}



Alright, now you're going to get an error saying "Partial declarations of HomeView must not specify different base classes". This is because the designer file is not updated to inherit from MvxWindowsPage. Don't worry, we're going to fix it in the next step.

Modify the .xaml File

FINALLY we're going to modify the XAML file and add a text. Open the xaml file in XML view.

You will need to change the Page to use MvxWindowsPage, change the x:Class to use our HomeView and add a namespace that references MvvmCross so that UWP understands where to look for.

...and we're going to add a TextBlock with the text 'Hello World'. Just open the Toolbox, look for TextBlock and drag it onto the screen.

 

...And change the text to Hello World.

Your XML should look like this.

<views:MvxWindowsPage
    xmlns:views="using:MvvmCross.Uwp.Views"
    x:Class="HelloWorld.UI.Uwp.Views.HomeView"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:local="using:HelloWorld.UI.Uwp.Views"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    mc:Ignorable="d">

    <Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
        <TextBlock HorizontalAlignment="Left" Margin="107,190,0,0" TextWrapping="Wrap" Text="Hello World" VerticalAlignment="Top"/>

    </Grid>
</views:MvxWindowsPage>

Now Save.

This will trigger a regeneration of the designer code and the previous error should be gone as well.

If the error is still there, then you'll need to modify the .g.i.cs file yourself. Right click on HomeView, Go to Definition, then find the .g.i.cs file. Modify the file so that it inherits from MvxWindowsPage.

Run the UWP App

With a UWP app (or any mobile app development with Xamarin), rather then immediately running, you need to Deploy and then Run the project.

So go to solution explorer, right click on your UWP project and click Deploy.

And once it has finished deploying, right click on your UWP project again and Set as Startup Project.

Now you can click Run / Local Machine at the top toolbar of Visual Studio.

 ...If all went well, then you should see this UWP.

 Congratulations! You have written your first UWP app with MVVMCross.

Run on Mobile

Now, how do you run your app on mobile?

First, you'll need to enable the Developer mode on your device. Go to Settings > For Developers.

Enable the Developer Mode.

Now plug in your Windows 10 Mobile device to your PC.

Change the Debug button from Local Machine to Device. Depending on your device, you may need to change the build from Any CPU to ARM, like so.

Now, deploy your app to mobile the same way you did before. Right click UWP project and click Deploy. Then Run it. Your Hello World app should now be running on your mobile.

Yeah.. Now we're going to move on to Android.

The Millionaire Mindset When You Create Products... and Not Only Digital Ones!

This is mainly written for me to record stuffs.

But to begin the article, I need to tell you a very short story about a mobile developer. His AMA on reddit is: https://www.reddit.com/r/IAmA/comments/68pck7/im_that_multimillionaire_app_developer_who/ .

To make the story short, he writes mobile apps for a living. His overall strategy is.. pretty simple.

1. Look for trending apps. See what kind of apps people are downloading.

2. Make apps similar to the trending apps.

3. Make it free with upgrades. Either no ads / more features.

4. Rinse and repeat.

He did it for a while until he reached $600/day. Then he made the police scanner app which pretty much made him a millionaire.

If you want the 'secret' to being rich, that's basically it. Just look whatever people are downloading, make them, and boom, rich. In fact, this pretty much holds true ever since the dawn of time. Just replace downloading with any verb of that time. Buying, digging (gold rush), planting (agriculture), eating (food industry), watching (movie industry), etc. The principal is totally the same at any point of time, at any place.

So.. What's the problem with Venture?

Here's the problem. Venture made lots and lots of products that you have never heard, which I won't touch in this article. Pretty much all of them are misses, misses that are allllll avoidable if Venture had the right mindset. But even when Venture do things wrong (IMO), Venture finally made a hit with OfficeCentral, which hit all the right principals of a selling product, which managed to take advantage of the most opportune time (GST introduction in Malaysia), of which was reached purely through trial and error and countless number head-banging on the wall.

See, the good thing is, when you persevere long enough, you'll eventually hit something. So, "never give up" is, always was, and will always be, the all-time 'truth' that everybody should follow.

But the bad thing is, if you don't understand the fundamentals, you're bound to repeat the same mistakes you made all over again with your 'hit', and this is the bug that keeps OfficeCentral from hitting its full potential.

Now, OfficeCentral was, in its baby-form, was a HRMS system only. It was a small but focused product.

Then some client said they want Payroll, so boom Payroll was added. The point was, Venture wants to say: "See, if you buy our Payroll, you get HRMS too!".

Then a contract comes in for an Accounting system, then booom Accounting is added. The intention is the same: "See, if you buy our Accounting, you get Payroll AND HRMS too."

This goes on and on until OfficeCentral reaches this current form.

Now, see what the problem is? Try comparing OfficeCentral's model to the millionaire mobile app developer model.

Now, the millionaire looked for something that people are downloading, then build it to get them to download it.

Whereas, Venture just added stuffs so that they have more points to say to people when they sell.

This difference leads to a totally different software experience.

Since the millionaire build the apps especially to get people who are interested in that kind of apps to download his one instead, lots of the focus goes towards tailoring the app towards new users. That means:

Quick sign in / No logins at all
The app does only what the new users want, nothing more, nothing less.
And it does the only thing it does very, very well.
And this reflects in his apps. Police scanner? Yup, it scans for police. Upgrade for no ads / better scanning capabilities. That's it. It doesn't try to be more than it has to be.

Compare that to OfficeCentral. OfficeCentral adds features so that, rather than to get new users, is to have more talking points to its current (mostly offline) marketing channels.

This results in apps that are not geared to get new customers at all and the resulting experience is pretty bad for any new users or anyone who found OfficeCentral from Play Store. Only current OfficeCentral users can take advantage of it.

Example: OfficeCentral Staff Mobile. Nobody searches the Play Store to apply for leave. Hence this app does not provide any new customers, only pleasing the current customers, hence under the millionaire's mindset, OfficeCentral Staff Mobile makes no sense.

Second Example: OfficeCentral POS. If by divine intervention a new user finds OfficeCentral POS, they'll immediately be greeted by a login page. With nowhere to register. This totally makes sense for OfficeCentral because the app is made not to get new users but to please the existing ones. But this totally makes no sense if we use the millionaire's mindset.

Third example: The whole of OfficeCentral itself. Since each feature is added so that there's more talking point, rather than focusing on new user experience, the focus was on adding as much feature as possible. This resulted in very heavy configuration required for any new users to OfficeCentral, with very little focus on new user experience.

For example, let's say someone buys OfficeCentral for the CRM. But when he registers, rather than immediately going to the CRM part, he was greeted by Home the dashboard, which has like 100 links on the page. He'll need to find the CRM link at the top of the page, and click one of the Account, Leads, Invoicing dropdowns before he sees anything else. So, someone wanting to give OfficeCentral a try, will quickly be confused and ultimately exit OfficeCentral and look for a simpler one, even though OfficeCentral, once mastered, is totally better.

As much as Venture say that we have divided it as logically as possible, even having 7 links on a page is confusing as it is, especially to new guys. This was offset by providing training to new users, but frankly, it is at best just a duct tape on a broken wall.

There are more examples, not only limited to software side, since Venture have this "add it so we have more talking point" mindset: Online payment is confusing. Marketing OfficeCentral becomes "we have this and we also have that". Take everything. Configuration nightmare. Events not working as intended. Support problems.

However, this can ultimately be solved by switching our mindset from "add it so we have more talking point" to the millionaire mindset "we create new product so we get new customer". Once we switch our mindset to the millionaire mindset, every single design we have will naturally follow through.

Now, for example, OfficeCentral POS. With the millionaire mindset in mind, how will you design the app?

Currently, people who finds the app in Play Store opens the app. Cannot login. Then he must open OfficeCentral.com.my. Register in the website. Then open it inside the mobile again. Log in. Then realises you need to add product. Then open website again, add product (pricebook in the system). Then go to POS again. THEN he's good to go.

Here's a simple diagram:

Open App -> Go to OfficeCentral.com.my -> Register -> Login -> Configure Wizard -> Click CRM Pricebook -> Add pricebook -> Return to App -> Start Session

See how horrible it is for any new users to get started? Most will probably drop at the second step.

Now, let's apply the millionaire mindset. Remember, the mindset is "we create new product so we get new customer". How will you approach the design?

By design, I mean just try to think the screens that the user will see. If it's a web app, then a page. Try to list down each screen user will see by chronology from a new user download, open the app, until he can get it up and running.

So, how will you design it?

You want a new user to be able to use it, so you must allow registration. And he needs to be able to use the POS as quickly as possible, without any configuration.

Hence, the design will naturally become like this

Open app -> Register / Login -> POS Cash Register interface.

If it's possible, we should even skip the register phase. Hence:

Open app -> POS Cash Register interface.

That's it! That's your new design. By changing and be aware of your mindset, you will naturally come to this conclusion on your own. Of course, your designs will then be constrained by technical limitations, but this is the correct way to approach when designing any new app, or actually any new product, doesn't matter whether it's digital or not.

Example of very good design: https://squareup.com/pos . It's basically 3 steps:

Open app -> Register / Login -> POS Cash Register interface.

...and they try to make registering as easy as possible by prefilling everything for you, except for the password.

Now with this new millionaire mindset approach, you can start transforming the way you design your business or marketing strategy as well. Remember, this millionaire mindset approach isn't limited to only mobile app design. This approach is universal.

Let's take another example. OfficeCentral CRM. Currently it's the same design as OfficeCentral Staff:

Open App -> Open OfficeCentral.com.my -> Register -> Click CRM -> Find configurations and configure it -> Open App again -> Add Leads, Contacts, Accounts -> Then you can add quotations, invoices etc.

How will you approach this? Remember, "we create new product so we get new customer".

Now, one of the most important tenets of this millionaire mindset is to create something that people are currently downloading or will be downloading. The only way to find this out is by research. And by research, you either simply look at the trend and follow the winners, or actually understand what's going on in a person's mind.

I'm going to share with you another nugget.

When users complain something isn't right, something definitely isn't right. However, when an user recommends how to fix it, the user is wrong.

Simply, users know when something isn't right and they are usually correct. However, the users are not experts at fixing it. The expert is you. So you, yourself need to understand the heart of the user and do something to fulfill the user's expectations.

How does this wind up with OfficeCentral CRM? Now, when people looks up for CRM on mobile, they are not looking for the whole CRM she-bang. They're not looking forward to inputting leads, accounts, or dissecting graphs and whole data on their mobile.

They are only looking to: Immediately issue quotation to a potential client when they're meeting at Starbucks.

Right now they need to return home, fire up MS Word, copy and paste, change names, etc and THEN email to their potential client. This is very leceh and a waste of time for both him and the potential client, hence reducing the opportunity to close the sale.

THAT's the only thing they need. For the whole analytical side, they'd rather open it on a big screen at a computer with Excel on the side so they can analyze their own sales data.

So, with that knowledge + the millionaire mindset, what will you do?

Here's what I will do:

Rather than OfficeCentral CRM, it should be cut down to OfficeCentral Invoicing, because people are looking to invoice their client when they use the app, not to do analysis. Less is more. This hugely simplifies our app design:

Open -> Register/Login -> Invoicing choice (Quote, Invoice) -> Quoting process -> Email

Simple, isn't it? Once the user downloads the app, he can immediately invoice a client. No more, no less.

And no, this does not only apply to mobile app design. Like I said, the millionaire mindset is universal.

Now let's go to the whole OfficeCentral online and offline marketing. Here's pretty much the flow of how things happen:

Offline:
Find a group of entrepreneurs/business -> Marketing people say OfficeCentral have everything -> Some people buy because it has something he wants -> Register free trial and login -> Cannot understand how to do what he wants -> Contact marketing people -> Demo -> Buy

Online:
Generic OfficeCentral.com.my -> Send everything there -> Register free trial -> Don't understand -> Contact marketing people -> Demo -> Buy
In short, it's basically "Yup, we have what you want. If buy ours you get others too!".

What if you apply the millionaire mindset?

Now things are different.

Rather than saying "OfficeCentral have everything you need", it becomes "Hey, you need point of sale? Yup, we have the best goddamn POS on the planet. And it's integrated with everything else as well!".

With this mindset, the whole marketing strategy becomes something else. Rather than OfficeCentral, you have CRM. You have HRMS. You have Payroll. You have Accounting. This translates to a different methodology

General if we sell POS:
Find a group of shops with no POS -> Sell POS to them -> They login and can immediately use it
Online if we sell accounting:
Create a website about Accounting -> Talk about OfficeCentral Accounting -> They login and can immediately use it.
This mindset also will change the approach to new people being registered into OfficeCentral as well. If people are interested in OfficeCentral to use her CRM, when they register they should immediately see CRM.

This also totally changes the billing methodology as well. "We create new product so we get new customer" is also "We create new product so we get money".

For example, Payroll. Under the current billing structure, its limited to per user per month billing. However, that billing system does not make any sense for a Payroll system. Why?

Because a Payroll administrator can might as well be one user only, because the system is supposed to generate payroll as automatically as possible, doesn't matter if it's a company with 1 employee, or 1000 employee. However, the difference between levels of company is that a small company may only generate salary slip for 1 employee, a bigger company may generate for 1000 employees.

Hence, the only one that makes sense under the millionaire mindset is: Charge based on the number of salary slips being generated.

This also applies for Accounting. The administrator might as well be one, but the difference between small and big is, the number of transactions recorded. So the billing should be based on number of transactions, not number of users.

Of course, there are real world constraints that Venture need to follow, but by following the millionaire mindset, we will actually approach problems and tackle new challenges with the correct method and mindset.

Hence, the millionaire mindset, "We create new product so we get new customer" is, IMO, how Venture should base their strategy on for years to come. This will fix a lot of mistakes and provide a good framework for each of Venturians to make decisions on.

 

From Zero to Can-lah: Xamarin + MVVMCross 5 Tutorial: Part 2: Hello World

Alright, so we're going to start with a very simple Hello World application, accessible on Android, iOS and UWP.

Create New Project

Create a new Class Library (Portable) project. If you can't find it, search for it in the Search textbox. Name it HelloWorld.Core .

You will be greeted with this dialog:

Just select all and select OK.

Awesome! Now go and delete Class1.cs. As per MVVMCross' TipCalc tutorial, ain't nobody need it ;)

Install MVVMCross

Now, we are going to install MVVMCross in our class library. Open Package Manager Console and type:

Install-Package MvvmCross

Add App Class

Now we'll need to add an App class. This class will handle interfaces, implementations and viewmodel registrations.

For now, create a new App.cs class at the root project and add this code:

using HelloWorld.Core.ViewModels;
using MvvmCross.Core.ViewModels;
using MvvmCross.Platform;

namespace HelloWorld.Core
{
    public class App : MvxApplication
    {
        public App()
        {
            Mvx.RegisterSingleton<IMvxAppStart>(new MvxAppStart<HomeViewModel>());
        }
    }
}

It's okay if you have an error at the HomeViewModel line, we're going to add that next.

Add HomeViewModel

A ViewModel represents a screen or a page inside our app. So, let's add one viewmodel and name it HomeViewModel. Add a folder named ViewModels and add a HomeViewModel.cs class inside.

using MvvmCross.Core.ViewModels;

namespace HelloWorld.Core.ViewModels
{
    public class HomeViewModel : MvxViewModel
    {

    }
}

...This should be enough.

Now, refer to the App.cs class again. The line ...

Mvx.RegisterSingleton<IMvxAppStart>(new MvxAppStart<HomeViewModel>());

... simply means that we set the class HomeViewModel as the first screen/view model our app will start with.

Your file structure will look like this:

Alright! We're done with the portable class library. Easy ain't it? Let's move on to the UWP implementation.

From Zero to Can-lah: Xamarin + MVVMCross 5 Tutorial: Part 1: Getting Started

Alright, so I'm going to write down a tutorial about how to start using Xamarin and MVVMCross.

One of the gripes I had with MVVMCross was that the documentation on their website is old (well, at least at the time of writing) hence for newer versions, you had to dig through the net until you found and try them until it works. Now, the older videos are very helpful (especially the N+1 videos, thank you!) but as a beginner I found it hard to use because of the changes in namespaces and also some 'deprecated' methods, for example creating tabs in Android. However, once I got my head around MVVMCross, the N+1 videos is an absolute goldmine.

Even worst is that since you're new to the mobile and xamarin world, you absolutely don't know which advice is the correct or the most recent one, or even worse is that you may have found the most recent one, but you just can't get it to work because you didn't know there's a small change in Setup.cs that you needed to do, but there's no way you can know that unless you're already well-versed in MVVMCross in the first place.

This will mostly be for myself so that I can refer back to refresh my memory, and also possibly for my co-workers and friends and others who are interested in starting with Xamarin and MVVMCross but are scared by the prospect of it.

First of all, useful links are:

MVVMCross website: http://mvvmcross.com
Their Github: https://github.com/MvvmCross/MvvmCross
N+1 Tutorial: https://mvvmcross.wordpress.com/
Beginner TipCalc Tutorial: https://www.mvvmcross.com/documentation/tipcalc-tutorial/the-tip-calc-tutorial

This tutorial assumes that:

  1. You never did any mobile development
  2. You know C# (It's fine if you only know VB.NET, it's pretty much the same thing)
  3. Nuget and stuffs
  4. .... Yeah that's it I guess. I'll try to walk y'all through the gotchas as much as possible.
  5. ...And I won't focus much on any non-mobile parts (such as accessing the web service) though there may be examples of them inside.

Some Gotchas

This tutorial simplifies/skips some explanations during the early parts (HelloWorld and TipCalc) so that the readers can focus and getting it to work first. I've added a small notes at the end of the tutorial explaining a bit about the skipped parts and will go more in-depth when we reach the final tutorial (Apps with Tabs).

What you should be able to do after this tutorial:

1. A whole, real-world Xamarin application that is deployable on Android, iOS and Universal Windows Platform (UWP), ready to be published to their respective stores.

What we're going to make

 We're going to create a total of 2 apps.

1. A HelloWorld app, which will be extended to become the TipCalc tutorial, but in more detail / more hand-holding.
2. A full application which can be Scrolled and Tabs as the main navigation method.

What you need to start with Xamarin and this tutorial

0. We're using MVVMCross 5.0
1. Visual Studio 2017 Community Edition - Download here
2. A Mac (updated to 10.12 Sierra). Yup, you heard me right. A Mac. So go out there and buy/borrow/steal/beg from your boss for one. You can also skip the iOS part if you don't have a Mac, no problem. This tutorial was written with the macOS version 10.12 Sierra.
3. An Android phone, an iPhone and a Windows phone (optional, unless you're okay with using simulators).
4. A punching bag. So that you have something to punch when you inevitably left something out and wonder why something doesn't work.

So, I have everything ready. Give it to me!

Hell yeah, let's go! Click here.

 

 

How to make an iOS page with tabbed view

How to make an iOS page with tabbed view - MVVMCross 4.4.

1. Get the MVVMCross iOS Support package via nuget

2. Override the FinishedLaunching() in AppDelegate class and set the presenter as MvxTabsViewPresenter:

public override bool FinishedLaunching(UIApplication application, NSDictionary launchOptions)
{
	// ...
	var presenter = new MvxTabsViewPresenter(this, this.Window);
	var setup = new Setup(this, presenter);
	setup.Initialize();
 
	Mvx.Resolve<IMvxAppStart>().Start();
 
	Window.MakeKeyAndVisible();
 
	return true;
}

3. Set the main page (the one with tabs)

[MvxTabPresentation(MvxTabPresentationMode.Root)]
public class MyRootView : MvxBaseTabBarViewController<MyRootViewModel>
{
	// ...
}

4. Create the page inside the tab

[MvxTabPresentation(MvxTabPresentationMode.Tab, "Tab 1", "home", true)]
public class SomeView : MvxViewController<SomeViewModel>
{
	// some code
}

Reference and more info at http://nmilcoff.com/2016/10/16/tabs-presenter-for-mvvmcross/