Have you ever wanted to have an Activity or Loading indicator dialog screen overlay, that is transparent, and fully customized by you? in your Xamarin.Forms project?
Then you stopped at the right place.
Today I’m gonna share how to build a fully customizable Activity Indicator /Loading Screen from Xamarin.Forms with a bit of native magic. To be honest, more of a continuation of my previous blog post! 😉 lol
Perks:
- Fully customizable View on the go from Xamarin.Forms
- Overlays on top of your ContentPage / Navigation Stack
- Service based, full MVVM & testing friendly
- Fully transparent and controllable dimmer
- Cancellation & back button disabled
Here’s a sneak peek…
TADAAA! That’s what yol gonna build! 😀
The Concept…
So basically if you think about it, when you want to display an Loading/Activity indicator overlay screen, it is something that would indicate,
“Oh there’s some important processing going on that Page and we need you to wait until it finishes…” 😛
“In the meantime we’re going to block the interactivity of that Page with this overlay, but you can still see the progress of it with the transparency…”
So in the language of Xamarin.Forms, on top of your ContentPage, we need something that would block the interactivity of background content but allows us to see what’s going in the background, in other words, it should be a transparent or dimmed View. 😀
A ghost from the past…
So I’m going to revert your attention to the previous blog post I wrote, Build your own Transparent Page from scratch for Xamarin.Forms, which was all about creating a Transparent page for Xamarin.Forms using a bit of native code. And I’ll be using the same concept and the code here as well, but I’m not going to drill down to the technical details of that specific implementation here, so if you’re looking for it, go ahead and give it a read first and come back.
The Recipe time…
So if you’re coming back from my previous blog post you could probably consider this post as a continuation of it. Today we’re going to create a Transparent Page in Xamarin.Forms using a bit of native magic, that will overlay on top of any Xamarin.Forms ContentPage or the Navigation Stack, and has the capability to customize the Transparent content view on demand. 😀
So to do this, we’re going to implement a native Transparent page in our Platform projects (iOS and Android), then we’re going to create a Service implementation that can display and dismiss our Transparent pages on demand while being able to pass in the desired Content View as we wish to display as parameters. The actual concrete implementation of that service will bed laid down in platform specific projects, along side the native Transparent page rendering implementation. So that we can do the rendering or displaying or dismissing our Loading/Activity indicator overlay on demand as we wish.
So to map the Service interface and its concrete implementations we are going to use Xamarin.Forms Dependency service, but then if you have your own IoC container you could use it as well. 😉
Sounds pretty straight forward eh! 😀 time for coding! 😉
Xamarin.Forms bits…
Alright then let’s hit it with the Service interface implementation. Let’s call it ILodingPageService.
public interface ILodingPageService { void InitLoadingPage (ContentPage loadingIndicatorPage = null); void ShowLoadingPage(); void HideLoadingPage(); }
So we will have three interface methods, one to initiate and prepare the Transparent page we’re going to display as our Loading/Activity indicator overlay. Then two more to Show it or Hide it on the app.
Speaking of InitLoadingPage() method, the reason we need is to facilitate the feature of displaying different Loading pages or designs on demand at the run time. So let’s say in Page 1 we want to display one Loading page, then in Page 2 we want to display a different kind of Loading Page, that right there is possible here with this method. You just pass in whatever the Loading Page design you want to show, and you’re done! 😉 How cool is that!
Since this a Xamarin.Forms Transparent Page, let’s first create our usual ContentPage, with usual stuff. Let’s call it the LoadingIndicatorPage1
<?xml version="1.0" encoding="utf-8" ?> <ContentPage x:Class="XFLoadingPageService.LoadingIndicatorPage1" xmlns="http://xamarin.com/schemas/2014/forms" xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml" BackgroundColor="#80000000"> <ContentPage.Content> <StackLayout Padding="30" BackgroundColor="Black" HorizontalOptions="Center" VerticalOptions="Center"> <ActivityIndicator IsRunning="True" Color="White" /> <Label FontAttributes="Bold" Text="Loading..." TextColor="White" /> </StackLayout> </ContentPage.Content> </ContentPage>
So you can see we have a very simple ContentPage design, with an ActivityIndicator and a Label to show that, “Oh look it’s a loading screen… boo!” lol 😀
Android bits….
Here come the actual magic, let me begin with Android! So let’s start off with our ILoadingPageService’s concrete implementation for Android and register it with the Xamarin Dependency Service.
[assembly: Xamarin.Forms.Dependency(typeof(LodingPageServiceDroid))] namespace XFLoadingPageService.Droid { public class LodingPageServiceDroid : ILodingPageService { private Android.Views.View _nativeView; private Dialog _dialog; private bool _isInitialized; public void InitLoadingPage(ContentPage loadingIndicatorPage) { // check if the page parameter is available if (loadingIndicatorPage != null) { // build the loading page with native base loadingIndicatorPage.Parent = Xamarin.Forms.Application.Current.MainPage; loadingIndicatorPage.Layout(new Rectangle(0, 0, Xamarin.Forms.Application.Current.MainPage.Width, Xamarin.Forms.Application.Current.MainPage.Height)); var renderer = loadingIndicatorPage.GetOrCreateRenderer(); _nativeView = renderer.View; _dialog = new Dialog(CrossCurrentActivity.Current.Activity); _dialog.RequestWindowFeature((int)WindowFeatures.NoTitle); _dialog.SetCancelable(false); _dialog.SetContentView(_nativeView); Window window = _dialog.Window; window.SetLayout(ViewGroup.LayoutParams.MatchParent, ViewGroup.LayoutParams.MatchParent); window.ClearFlags(WindowManagerFlags.DimBehind); window.SetBackgroundDrawable(new ColorDrawable(Android.Graphics.Color.Transparent)); _isInitialized = true; } } public void ShowLoadingPage() { // check if the user has set the page or not if (!_isInitialized) InitLoadingPage(new LoadingIndicatorPage1()); // set the default page // showing the native loading page _dialog.Show(); } public void HideLoadingPage() { // Hide the page _dialog.Hide(); } } }
Most of the above Xamarin Android specific code is already explained in detailed line by line in my previous post. So in short, here we have the concrete implementation of our service for Android, inside the InitLoadingPage() we’re passing in the Xamarin.Forms Page which we want to render as a transparent page which will act as our Activity Indicator. Then we’re rendering that page and embed into a Android Dialog view with a transparent background, and back button cancelled properties enabled. We’re keeping a reference of the _dialog instance so that we can show or hide the Page upon respective ShowLoadingPage() and HideLoadingPage() executions.
So every time a user wants to display a different Loading page, they will call the InitLoadingPage() which will build the new page instance and keep it in the service memory.
At the same time you may have seen inside ShowLoadingPage() if you haven’t instantiated the transparent page, then we’re using a default page, LoadingIndicatorPage1 as a template ad instantiating it on the go, just to avoid exceptions. This choice of default page is totally up to you.
Also don’t forget at the top of the namespace we’re registering this concrete implementation with Xamarin Dependency service. 😉
iOS bits….
Then let’s move on with our ILoadingPageService’s concrete implementation for iOS and register it with the Xamarin Dependency Service.
[assembly: Xamarin.Forms.Dependency(typeof(LodingPageServiceiOS))] namespace XFLoadingPageService.iOS { public class LodingPageServiceiOS : ILodingPageService { private UIView _nativeView; private bool _isInitialized; public void InitLoadingPage(ContentPage loadingIndicatorPage) { // check if the page parameter is available if (loadingIndicatorPage != null) { // build the loading page with native base loadingIndicatorPage.Parent = Xamarin.Forms.Application.Current.MainPage; loadingIndicatorPage.Layout(new Rectangle(0, 0, Xamarin.Forms.Application.Current.MainPage.Width, Xamarin.Forms.Application.Current.MainPage.Height)); var renderer = loadingIndicatorPage.GetOrCreateRenderer(); _nativeView = renderer.NativeView; _isInitialized = true; } } public void ShowLoadingPage() { // check if the user has set the page or not if (!_isInitialized) InitLoadingPage(new LoadingIndicatorPage1()); // set the default page // showing the native loading page UIApplication.SharedApplication.KeyWindow.AddSubview(_nativeView); } public void HideLoadingPage() { // Hide the page _nativeView.RemoveFromSuperview(); } } }
So the implementation here is also similar to Android code above, except for the native bit. So we’re instantiating the Xamarin.Forms Page instance inside, InitLoadingPage() method we’re initiating the transparent page instance and holding inside the service.
Then showing it or hiding it based on the ShowLoadingPage() or HideLoadingPage() calls.
Pretty straightforward eh! 😀
So what next…
Now one of the best features of this implementation is that your could use any number of Loading Indicator Pages as you wish with various kinds of designs. 😀 So just for the kicks of it here’s another page that we’ll use. let’s call it LoadingIndicatorPage2
<?xml version="1.0" encoding="utf-8" ?> <ContentPage x:Class="XFLoadingPageService.LoadingIndicatorPage2" xmlns="http://xamarin.com/schemas/2014/forms" xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml" BackgroundColor="#80000000"> <ContentPage.Content> <StackLayout Padding="30" BackgroundColor="#D93463" HorizontalOptions="Center" VerticalOptions="Center"> <ActivityIndicator IsRunning="True" Color="White" /> <Label FontAttributes="Bold" Text="Yo! Hold on..." TextColor="White" /> </StackLayout> </ContentPage.Content> </ContentPage>
If that’s not enough you can add more and more as you go 😀 but just make sure to call the InitLoadingPage() method! 😉
Let’s fire it up…
So to fire this up we need to call this service from your Xamarin.Forms code using the DependencyService.
// show the loading page... DependencyService.Get<ILodingPageService>() .InitLoadingPage(new LoadingIndicatorPage1()); DependencyService.Get<ILodingPageService>().ShowLoadingPage();
There we’re first initiating our page and then show it on the app. Once you initiate the page you don’t have to call it ever again as you saw in the implementation, it is retained in the memory of the service.
// close the loading page...
DependencyService.Get<ILodingPageService>().HideLoadingPage();
Once you’re done, you can close our awesome Activity / Loading Indicator Page with the above code.
And here we go on iOS and Android in action…. 😀
That’s our first Loading screen in action…
And click on the second button, there’s our second Loading screen in action, on the go…
Look at that, even during navigation between pages our Loading page stays intact on top of the Xamarin.Forms Pages stack. 😉
The reason why it acts so independently is because we are directly accessing the native elements in the service implementation, therefore even during navigation of Xamarin.Forms Stack or whatever the UI activity our Loading page will not be affected, it will keep on, of its own.
How awesome is that eh! 😀
Github it if yo lazy!
So all of this is hosted on my git repo: https://github.com/XFLoadingPageService
Now your own imagination is the limit for what’s possible or not fellas!
That’s it for today.
Cheers! 😀