Wednesday, May 06, 2015

Cross platform splash screen in Xamarin Forms

EDIT: I do not recommend this approach. Instead, use native approach to create splash screen because it shows much faster.

If the splash screen is more than just an image, you can treat the splash screen as a Xamarin Page.
To make this there are some steps:

Step 1. set the App’s MainPage to the splash screen page:
public partial class App : Application { public App() { InitializeComponent(); Setup.Init(); // with XLabs, you would do (Page)ViewFactory.CreatePage<SplashViewModel>(); MainPage = new SplashPage(); }

Step 2.  In SplashPage, after some logic is done, you will need to “navigate” to your first app’s page. This means you just need to set again the App’s MainPage, i.e”:
void ShowMainPage() { MainPage = new SplashPage(); }
The issue is how do you call this.
If you are not doing any logic in the splash screen, you can just do something like this:
public class SplashPage : Page { async protected override void OnAppearing() { base.OnAppearing(); await Task.Delay(TimeSpan.FromSeconds(2)); // again, here you might want to use instead XLab's ViewFactory.Create<FirstPageViewModel>() App.Current.MainPage = new FirstPage(); } }
If you are doing some logic in the view-model and you want to navigate to FirstPage, you don’t want to call this in the view-model.
There are few ways to change the App’s MainPage without calling it from the view-model.

You could use a messaging mechanism to send a custom message from the view-model to the view. Look to the Xamarin Form’s MessagingCenter:

Another way is, you probably are already using some navigation service to navigate between view-models, so what you need to do is have a custom navigation behavior in the way you navigate to the first page. With XLabs for example, you can define your own CustomNavigationService : XLabs.Platform.Services.INavigationService, override NavigateTo( ), then check for the page to which you navigate to, and if it’s FirstPage then create the NavigationPage and push the first page to it:

public class CustomNavigationService : INavigationService { NavigationService navigationSvc; public CustomNavigationService() { navigationSvc = new NavigationService(); } public void GoBack() { navigationSvc.GoBack(); } public void GoForward() { throw new NotImplementedException(); } public void NavigateTo<T>(object parameter = null, bool animated = true) where T : class { NavigateTo(typeof(T), parameter, animated); } public void NavigateTo(string pageKey, object parameter = null, bool animated = true) { throw new NotImplementedException(); } public void NavigateTo(Type pageType, object parameter = null, bool animated = true) { if (pageType == typeof(MainViewModel)) { var page = (Page)ViewFactory.CreatePage(pageType); App.Current.MainPage = new NavigationPage (page); navigationSvc = new NavigationService(App.Current.MainPage.Navigation); } else { navigationSvc.NavigateTo(pageType, parameter, animated); } } public void RegisterPage(string pageKey, Type pageType) { navigationSvc.RegisterPage(pageKey, pageType); } }
Step 3. In Android, you need to configure few things:

         a. Define a startup theme and an app theme in your Resources\values\themes.axml:
<?xml version="1.0" encoding="utf-8" ?> <resources> <color name="splashscreencolor">#232323</color> <style name="StartUpAppTheme" parent="android:Theme.Holo.Light"> <item name="android:windowNoTitle">true</item> <item name="android:windowBackground">@color/splashscreencolor</item> </style> <style name="AppTheme" parent="android:Theme.Holo.Light"> </style> </resources>

b. In the native MainActivity, have the activity start with the Theme.Splash and then have it running with the AppTheme:

[Activity(Theme = "@style/Theme.Splash"", MainLauncher = true, ConfigurationChanges = ConfigChanges.Orientation | ConfigChanges.KeyboardHidden | ConfigChanges.ScreenSize)] public class MainActivity : FormsApplicationActivity { protected override void OnApplyThemeResource(global::Android.Content.Res.Resources.Theme theme, int resid, bool first) { base.OnApplyThemeResource(theme, Resource.Style.AppTheme, first); } ... }

1 comment:

Christos Matskas said...

Hi buddy, you are missing a closing bracket here:

await Task.Delay(TimeSpan.FromSeconds(2) ")" );

Nice post btw