How to create a custom pop-up in Xamarin with MvvmCross in the right way

Image for post
Image for post

Developers often create a [Dialog/Alert/Interaction]Service to display pop-ups in Xamarin cross-platform apps. This way is suitable and clean if we need to show an info message or ask the user simple questions with positive and negative answers. But what if we need some complicated UX like a login experience?

Of course, the existing pop-up service could be extended to have inputs and actions:

Demo pop-up service interface extended for more interaction

But think about the complexity of this service’s usage, especially if we need some validation that should be tested somehow.

How can we simplify these pop-ups?

We can use a regular ViewModel with custom platform-dependent presentation that uses UIAlertController on iOS and DialogFragment on Android.

This approach is clean and has some advantages:

  1. The ViewModel layer does not care about the pop-up presentation.
  2. The ViewModel with pop-up presentation can be tested like any other ViewModel.
  3. The ViewModel with pop-up presentation can have much more space to implement custom functionality, as it does not depend on some generic service.

I will implement a simple login flow to demonstrate the pop-ups in Xamarin using the MvvmCross framework: when the Login button is clicked, the native pop-up should be presented so the user can enter a login and password.

Let’s create a custom pop-up with the following steps:

  1. ViewModel implementation
  2. Android View implementation
  3. iOS View implementation

ViewModel Implementation

On the ViewModel layer, we have a simple ViewModel that represents an authorization screen. This LoginViewModel has Username and Password text and Close and Login commands:

The ViewModel for the simple login flow

There is no actual authentication logic added as this post’s goal is to demonstrate the implementation of the pop-up presentation only. But here are some highlights:

  • The Login command returns the text from the Login property as a navigation result and closes the ViewModel
  • The Cancel command simply closes this ViewModel

Next, we move on to the Android implementation.

Android View Implementation

Unlike iOS, we can apply the default tools of MvvmCross to display a dialog on the Android platform.

We need a DialogFragment with a custom view that contains Login and Password text fields:

The Android view for the simple login flow

Important things to know when implementing such dialog:

  1. MvxDialogFragmentPresentationAttribute is applied, so MvvmCross knows how to present this particular View. See the documentation for the additional information.
  2. The AlertDialog is created and configured in the OnCreateDialog method. We use AlertDialog.Builder to configure positive and negative buttons, title, description, etc. here. The custom content view should be set later, as we apply bindings.
  3. It is impossible to bind the dialog buttons and command in the right way, so we execute the needed commands in button click listeners.
  4. As soon as the OnActivityCreated method is called, we know that our custom view has been inflated, and bindings have been created. Now we set the View for the AlertDialog.

The layout for the LoginDialogFragment contains two TextInputs and binding descriptions to connect the entered text with properties of the LoginViewModel:

The Android layout for the LoginDialogFragment

The complete pop-up presentation of the LoginViewModel should look like this on the Android platform:

Image for post
Image for post
Image for post
Image for post
Image for post
Image for post
The complete login flow with custom login pop-up window on Android

iOS View Implementation

The iOS part is a bit more complicated, and a custom presentation should be applied, but the idea is straightforward:

  1. Implement a custom MvxAlertPresentationAttribute that will be handled by the presenter.
  2. Create a base UIViewController-derived class that encapsulates UIAlertController creation.
  3. Extend the default MvxIosViewPresenter to process the new presentation attribute and display the View.
  4. Implement the LoginViewController.

1. MvxAlertPresentationAttribute

This custom attribute contains all the needed information to configure the UIAlertController:

Presentation attribute to handle alerts and display an alert dialogue in Xamarin

The PreferredStyle is mandatory and should be set before the alert is presented. The default preferred style is ActionSheet. Title and Message properties are optional and can be assigned later if the alert content is dynamic or some localization mechanism is applied.

2. MvxAlertViewController

The next step is to declare the MvxAlertViewController that encapsulates the alert creation. We will derive our LoginViewController from this class later.

The MvxAlertViewController inherits the MvxViewController and is responsible for two main features: it creates a UIAlertController and provides a convenient API to configure this alert.

Technically it sets itself up as the content of the UIAlertController and configures the right content size:

UIAlertController creation and configuration to display an alert dialogue in Xamarin

It is important to set the current view controller as a contentViewController because it allows us to use its view as the alert content and, for instance, display some validation later.

The PrefferedContentSize should be set to a small value, or the view controller will take the default content size, and we will have space at the center of the alert:

Image for post
Image for post
The login alert with the default content size

The custom MvxIosViewPresenter will take the result of Wrap method and present the created UIAlertController.

Now we could take care of users of our MvxAlertViewController and implement some convenience methods that allow them to configure alert and add text fields and actions.

First of all, the Title and Message properties of UIAlertController should be exposed and made bindable:

public override string Title 
{
get => _alertController.Title;
set => _alertController.Title = value;
}
public string Message
{
get => _alertController.Message;
set => _alertController.Message = value;
}

Then we need an ability to add text fields:

protected UITextField AddTextField() 
{
if (_alertController.PreferredStyle != UIAlertControllerStyle.Alert)
{
return null;
}
var textField = default(UITextField); _alertController.AddTextField(view => textField = view); return textField;
}

Finally, here is a method to add actions:

A method that adds a UIAlertAction to the UIAlertController

The most interesting part of this method is the call of the CloseModalViewController method: we should explicitly tell MvvmCross to remove our modal view controller from the navigation stack, or the navigation will be broken.

Note: text fields added to the alert controller can also close it when the Return button is pressed, so be sure to handle it.

The whole source code for this view class and the configuration methods and properties is available here.

3. MvxAlertIosViewPresenter

The new presenter should know how to show and close the view with MvxAlertPresentationAttribute, so we need to register this attribute in the constructor:

AttributeTypesToActionsDictionary
.Register<MvxAlertPresentationAttribute(
ShowAlertView,
CloseAlertView
);

Then implement the ShowAlertView and CloseAlertView methods:

Close and Show methods implementation

The ShowAlertView method is the interesting one, we create the ‘real’ view controller using the default mechanism and wrap it into the alert.

Note: we present the alert controller, not the original view controller.

The whole source code for this presenter class is available here.

4. LoginViewController

Finally, we set all the things up, and the LoginViewController could be implemented:

The iOS view for the simple login flow with custom login pop-up window

As you can see, the implementation of the final view controller is pretty simple. So all you need is to:

  • Define the MvxAlertPresentation attribute with the right preferred style
  • Bind or set Title and Message properties
  • Create and bind text fields
  • Create actions

Unfortunately, we cannot bind UIAlertActions properly without implementing custom binders. These are not the topic of this post, but text fields, title, and message could easily be bound.

The complete pop-up presentation of the LoginViewModel should look like this on the iOS platform:

Image for post
Image for post
Image for post
Image for post
Image for post
Image for post
The complete login flow with custom login pop-up window on iOS

In this post, I described how to implement cross-platform, maintainable, and testable pop-ups using Xamarin and MvvmCross.

Of course, this is not a complete login flow even from the UI perspective, and we need to add some validation and error displaying. But that is the topic for the next post, so stay tuned!

Finally, you can download and run a complete solution on GitHub:

Written by

Xamarin | iOS | Android Developer with 7 years of experience. All things actionable tips, real-life examples and coding guides to help you grow professionally.

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store