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:
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:
- The ViewModel layer does not care about the pop-up presentation.
- The ViewModel with pop-up presentation can be tested like any other ViewModel.
- 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:
- ViewModel implementation
- Android View implementation
- iOS View 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:
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:
Important things to know when implementing such dialog:
MvxDialogFragmentPresentationAttributeis applied, so MvvmCross knows how to present this particular View. See the documentation for the additional information.
AlertDialogis created and configured in the
OnCreateDialogmethod. We use
AlertDialog.Builderto configure positive and negative buttons, title, description, etc. here. The custom content view should be set later, as we apply bindings.
- It is impossible to bind the dialog buttons and command in the right way, so we execute the needed commands in button click listeners.
- As soon as the
OnActivityCreatedmethod is called, we know that our custom view has been inflated, and bindings have been created. Now we set the
The layout for the
LoginDialogFragment contains two TextInputs and binding descriptions to connect the entered text with properties of the
The complete pop-up presentation of the
LoginViewModel should look like this on the Android platform:
iOS View Implementation
The iOS part is a bit more complicated, and a custom presentation should be applied, but the idea is straightforward:
- Implement a custom
MvxAlertPresentationAttributethat will be handled by the presenter.
- Create a base
UIViewController-derived class that encapsulates
- Extend the default
MvxIosViewPresenterto process the new presentation attribute and display the View.
- Implement the
This custom attribute contains all the needed information to configure the
PreferredStyle is mandatory and should be set before the alert is presented. The default preferred style is
Message properties are optional and can be assigned later if the alert content is dynamic or some localization mechanism is applied.
The next step is to declare the
MvxAlertViewController that encapsulates the alert creation. We will derive our
LoginViewController from this class later.
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:
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.
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:
MvxIosViewPresenter will take the result of
Wrap method and present the created
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
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)
} var textField = default(UITextField); _alertController.AddTextField(view => textField = view); return textField;
Finally, here is a method to add actions:
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.
The new presenter should know how to show and close the view with
MvxAlertPresentationAttribute, so we need to register this attribute in the constructor:
Then implement 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.
Finally, we set all the things up, and the
LoginViewController could be implemented:
As you can see, the implementation of the final view controller is pretty simple. So all you need is to:
- Define the
MvxAlertPresentationattribute with the right preferred style
- Bind or set
- 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:
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: