Let me start first from the fact that I am new to Xamarin (in fact, I am not that old in C# either).
Anyway, after evaluating the
Starter Edition (free), I decided to go with a
Business License for Android only where we have the great
Xamarin.Forms package.
But having a Business license doesn't make you proficient! And the best way to learn is to start coding. Don't you agree?
So I need to start coding for an App! But what application without a splash screen?
Task
Build an app with Splash Screen that contains a logo!
Start
And so I began as we always do:
- Open Visual Studio.
- New Project.
- Templates -> C# -> Mobile Apps -> Blank App (Xamarin Forms Shared).
- Name the project: AppWithSplashScreen.
- Remove iOS and WinPhone Projects from my solutions. Well, first I don't have the license and for achieving that Splash Screen you need a different approach for each of the platform's app.
Ok and now I have a blank solution with Android app ready to go, so I do what all of us do. That is, go to his majesty Google.com and start digging for the keywords Xamarin
Forms Splash Screen Android.
So let us start doing what they suggest.
Official recipe
Ok, let us do it by the book, but instead of their “
Loading…” image in the Resources/Drawable folder, I'll use the following Logo image:
MCN = My Company Name. How imaginative is that! And the file name:
MCNLogo.png.
Ok, we're done with the image, let's do our Splash Screen theme as they suggest:
- Create a new folder under the Android project folder "Resources" with the name "Values".
- In that folder add a new "Styles.xml" file. Add -> New Item, then XML File. Make sure after creating this file to have the property "Build Action" set to the default value: "AndroidResource". In this file we will create a new theme "Theme.Splash" that set the background of our Splash with our logo.
- Edit the file to be as follows:
- <?xml version="1.0" encoding="utf-8" ?>
- <resources>
- <style name="Theme.Splash" parent="android:Theme">
- <item name="android:windowBackground">@drawable/mcnlogo</item>
- <item name="android:windowNoTitle">true</item>
- </style>
- </resources>
- Add a Splash Activity to the Android Project using Add -> New Item, then Activity. Let's name it SplashActivity.
- Change the attributes of the activity to set the theme attribute to "@styles/Theme.Splash", MainLauncher attribute to "True", and NoHistory also to "True". The Theme attribute is responsible for the style of the activity, the MainLauncher is responsible for making this activity the first activity to show and NoHistory is responsible for preventing navigation back to this activity. The activity attributes should look like the following:
- [Activity(Theme = "@style/Theme.Splash", MainLauncher = true, NoHistory = true)]
- Add the following code to the "OnCreate" method in Splash activity immediately after the comments // Create your application here:
- System.Threading.Thread.Sleep(10000);
- StartActivity(typeof(MainActivity));
The first line simulates a long-loading process.
The second line Start our MainActivity where our application will run main tasks after the Splash is shown.
- Just before running the application, we need to ensure that the MainLancher attribute of the MainActivity is set to false:
- [Activity (Label = "AppWithSplashScreen", Icon = "@drawable/icon", MainLauncher = false, ConfigurationChanges = ConfigChanges.ScreenSize | ConfigChanges.Orientation)]
- And let's run the application. (I don't like working with emulators so I will run it on my Samsung S5).
Pretty simple isn't it? Well wait a second.
Observations
Well, I got my splash screen. But here are some observations of the app:
- The app icon on my devices is the standard Android icon, and that is easy to fix. Just add an icon attribute of the SplashActivity to match that as the MainActivity:
- [Activity(Theme = "@style/Theme.Splash", Icon = "@drawable/icon", MainLauncher = true, NoHistory = true)]
- Sometimes also Xamarin will install the package to your mobile with some random name instead of the name of the application: AppWithSplashScreen. That is also not that complex to fix in many ways, but for now I'll just add the label attribute of SplashScreen to the one in MainActivity:
- [Activity(Label = "AppWithSplashScreen", Theme = "@style/Theme.Splash", Icon = "@drawable/icon", MainLauncher = true, NoHistory = true)]
- This observation is not a big deal, but wouldn't it be better to have the splash screen in full screen mode? In order to do that just change the parent theme in Styles.xml to "android:Theme.Holo.Light.NoActionBar.Fullscreen".
- <style name="Theme.Splash" parent="android:Theme.Holo.Light.NoActionBar.Fullscreen">
- 10000 in Sleep line in SplashActivity.cs is good to watch the now but it is too long (10 sec) for a splash screen. So I will reduce it to 5000 and in the final version of my app it will go to 2000 even.
- The most "dangerous" observation is:
My logo is stretched all over the screen for whatever reason and it is ugly.
Revised Task
Build an app with Splash Screen that contains a logo at the center of the window!
Official Recipe again
So after searching with same keywords of the revised task, I came to
this solution at Xamarin forums. Basically it says that instead of having an image (MCNLogo) as background in Styles.xml, we can redirect to the compiler to another XML resource where we set the image and some of its attributes to center it in the screen.
So:
- In Styles.xml replace the value of the "windowBackground" attribute to "@drawable/backgroundstyle" instead of "@drawable/mcnlogo":
- <item name="android:windowBackground">@drawable/backgroundstyle</item>
- In the Resource/Drawable folder add a new XML file and name it "BackgroundStyle.xml" with the following code inside:
- <?xml version="1.0" encoding="utf-8" ?>
- <bitmap xmlns:android="http://schemas.android.com/apk/res/android"
- android:src="@drawable/mcnlogo"
- android:gravity="center"
- android:layout_gravity="center"/>
"gravity" and "layout_gravity" are set to center and centers the image in the Activity.
- Run the application:
Here you are, a centered logo in a full screen activity. If this is what you want, then you can stop reading this article and start writing your application code after the splash screen, but there is more that can be done.
More Observations
It is too dark, isn't it? I wonder if it would be better to have a White background?
Revised Revised Task
Build an app with Splash Screen that contains a logo at the center of the window with a White background!
Shibbs Recipe
Searching Google with these keywords didn't give me an answer, but I found
this question in Stack Overflow that matches mine.
One of the answers (Shibbs' answer) was very interesting. Basically he suggests, why have the logo image as the background image? The SplashActivity is an activity at the end. So it can have it is own AXML layout where we can do whatever we want (almost). But the most interesting thing is the way he queues the MainActivity in the ThreadPool, allowing the splash screen to draw the XAML layout. Without this we will have only the blank splash screen:
- In Styles.xml, remove the entire line where the "windowBackground" attribute and value are. Instead insert the following line specifying that the background is of White color:
- <item name="android:colorBackground">@android:color/white</item>
- In the Resources folder, create a new folder "Layout". Here we will add our layout for the SplashActivity.
- In the Layout folder, add a new Android Layout: Add->New Item...->Android Layout. let's call it "SplashLayout.xaml".
- Edit the source of SpalshLayout to match the following markup:
- <?xml version="1.0" encoding="utf-8"?>
- <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
- android:orientation="vertical"
- android:layout_width="fill_parent"
- android:layout_height="fill_parent"
- android:minWidth="25px"
- android:minHeight="25px"
- android:gravity="center">
- <ImageView
- android:src="@drawable/mcnlogo"
- android:layout_width="wrap_content"
- android:layout_height="fill_parent"
- android:id="@+id/imageView1"
- android:layout_gravity="center" />
- </LinearLayout>
Here we have an ImageView in the center with source (src) of mcnlogo in the drawable folder.
- In SpalshActivity.cs, edit the "OnCreate" method to match the following code:
- protected override void OnCreate(Bundle bundle)
- {
- base.OnCreate(bundle);
-
- SetContentView(Resource.Layout.SplashLayout);
- System.Threading.ThreadPool.QueueUserWorkItem(o => LoadActivity());
- }
In this code, we set the content view of the SplashActivity to our SplashLayout.xaml and then we queue the MainActivity in the ThreadPool object using the LoadActivity method that we will write in the next step.
- Add a new method to the SpalshActivity class called "LoadActivity":
- private void LoadActivity()
- {
- System.Threading.Thread.Sleep(5000);
- RunOnUiThread(() => StartActivity(typeof(MainActivity)));
- }
Note how we shifted the sleep period to this method.
- Run the application:
Here's our splash screen with centered logo and White background. If you reached your goal, you can stop reading this article. But something is bothering me. What about having a different (custom) background color? Let's say light Aqua color, it would be nice with our bluesh logo.
More observations again
- There is a White blank screen showing for a small period before our logo is shown. In debug mode it takes longer than in the real app. Anyway, It is not a big deal as long as the colors match.
- As long as you use the "Theme.Holo.Light.NoActionBar.Fullscreen" theme as your parent theme in Styles.xml, the color will be White. I tried to write "android:color/black", the color remains White. As a matter of fact, even if you remove the entire line of the colorBackground attribute, the color remains White. I even tried to play around with custom color references like here but no matter what , if you stick to the parent theme, the color will remain White.
So, we cannot change the background color in this theme, but we can change the background itself, right?
- Create to 8x8 png image with whatever color you wish for your background. I want Aqua:
Let's call the file: "BackgroundShape.png".
- Add the file to the Resource/Drawable folder.
- In Styles.xml, remove the line for the "colorBackground" attribute and instead add the following line:
- <item name="android:background">@drawable/backgroundstyle</item>
Remember this "BackgoundStyle.xml" file in Resource/Drawable folder? Thank God I didn't delete it.
- In BackgroundStyle.xml, remove the reference to our logo "mcnlogo" and instead put "backgroundshape". This will make the small PNG as our background. Then we should specify the tileMode to "repeat" in order for the image to be painted all over the Activity. And let's also make the dither attribute to "true" to enable dithering the image if it doesn't have the same pixel configuration as the screen.
So our BackgroundStyle.xml file will contain the following markup:
- <?xml version="1.0" encoding="utf-8" ?>
- <bitmap xmlns:android="http://schemas.android.com/apk/res/android"
- android:src="@drawable/backgroundshape"
- android:tileMode="repeat"
- android:dither="true"/>
- Run the application:
Basically we're done. Mission accomplished, that is to have a splash screen on full screen with custom background a centered logo. So, again, if this is your goal, you can stop reading.
But, what about some "Loading..." animation? Something like this:
At the end we have "SplashLayout.xaml" layout where we can do whatever we want, add images, text, animation, just name it.
Adding Animation
One of the ways, to do this "Loading..." progress bar is to add a GIF image (just like here) to our splash screen. For that you need a special renderer. You can find very good articles about implementing GIF animation in Xamarin for both Android and iOS. I tried some of them and they worked perfectly, but not in SplashActivity. And I don't know why. So we will do it here based on the official recipe again.
Animation Official Recipe
We will use drawable animation as said in
this guide:
- We need to break our GIF layers into separate PNG files and add all of them to our drawable folder. Don't worry, they are usually small files.
- In the Resources folder, create a new folder under the name "Anim".
- In the Resources/Anim folder, add a new XML file under the name "LoadingAnimation.xml" with the following contents:
- <?xml version="1.0" encoding="utf-8" ?>
- <animation-list xmlns:android="http://schemas.android.com/apk/res/android" android:oneshot="false">
- <item android:drawable="@drawable/loading_0017" android:duration="112"/>
- <item android:drawable="@drawable/loading_0016" android:duration="112"/>
- <item android:drawable="@drawable/loading_0015" android:duration="112"/>
- <item android:drawable="@drawable/loading_0014" android:duration="112"/>
- <item android:drawable="@drawable/loading_0013" android:duration="112"/>
- <item android:drawable="@drawable/loading_0012" android:duration="112"/>
- <item android:drawable="@drawable/loading_0011" android:duration="112"/>
- <item android:drawable="@drawable/loading_0010" android:duration="112"/>
- <item android:drawable="@drawable/loading_0009" android:duration="112"/>
- <item android:drawable="@drawable/loading_0008" android:duration="112"/>
- <item android:drawable="@drawable/loading_0007" android:duration="112"/>
- <item android:drawable="@drawable/loading_0006" android:duration="112"/>
- <item android:drawable="@drawable/loading_0005" android:duration="112"/>
- <item android:drawable="@drawable/loading_0004" android:duration="112"/>
- <item android:drawable="@drawable/loading_0003" android:duration="112"/>
- <item android:drawable="@drawable/loading_0002" android:duration="112"/>
- <item android:drawable="@drawable/loading_0001" android:duration="112"/>
- <item android:drawable="@drawable/loading_0000" android:duration="112"/>
- </animation-list>
This is the animation XML file, that contains an animation list and items. Each item reference to the drawable PNG and the duration in msec. Please note that the attribute of the animation-list "oneshot" is set to "false" to reach continuous effect.
- In SpalshLayout.xaml, under the ImageView where we load our logo, add the following ImageView markup:
- <ImageView
- android:id="@+id/animated_loading"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_gravity="center"
- android:src="@anim/loadinganimation" />
Note that how the source (src) attribute references our XML file is in the Resource/Anim folder that is responsible for animation.
- Now we need to make the animation start when our splash screen is displayed. For that, in the SplashActivity.cs file, override the "OnWindowFocusChanged" method with the following code:
- public override void OnWindowFocusChanged(bool hasFocus)
- {
- ImageView imageView = FindViewById<ImageView>(Resource.Id.loadinganimation);
-
- Android.Graphics.Drawables.AnimationDrawable animation = (Android.Graphics.Drawables.AnimationDrawable)imageView.Drawable;
-
- animation.Start();
- }
Note that if you add this code to the "OnCreate" method, the animation will not start.
- Run the application and here is the result:
More Elements and let's animate
Let's add some text to our splash:
- In SpalshLayout.xaml, add the following TextView markup just before our logo ImageView:
- <TextView
- android:text="My Company Name"
- android:fontFamily="sans-serif-condensed"
- android:textStyle="bold"
- android:textSize="44sp"
- android:textColor="#005bed"
- android:shadowColor="#00342c"
- android:shadowDx="4"
- android:shadowDy="6"
- android:shadowRadius="2"
- android:layout_width="wrap_content"
- android:layout_height="200dp"
- android:layout_gravity="center"
- android:gravity="bottom"
- android:id="@+id/mCNLabel" />
- In SplashActivity.cs, add a ValueAnimator object to the activity class:
Don't forget to add Android.Animation to uses block:
- In the "OnCreate" method, let's initiate the text veiw and animator object. Just after queuing the "LoadActivity" method, add the following code:
- TextView companyName = FindViewById<TextView>(Resource.Id.mCNLabel);
- companyName.TextSize = 18;
-
- animator = ValueAnimator.OfInt(18, 44);
- animator.Update += (object sender, ValueAnimator.AnimatorUpdateEventArgs e) =>
- {
- int newValue = (int)e.Animation.AnimatedValue;
- companyName.TextSize = newValue;
- };
In the first 2 lines, we assign and initiate companyName to our new TextView.
In the following lines, we initiate the animator object, with integer property from 18 to 44, then we assign the update event to the lambada expression where we change the TextSize property of our TextView with then new AnimatedValue.
- In the "OnWindowFocusChanged" method, we should start the animation. Add at the end of the method the following code:
- 1. animator.RepeatCount = 1;
- 2. animator.SetDuration(10000);
- 3. animator.Start();
Here we specify the repetition count, the duration and then we start the animation.
- Run your application, and the your done.
I hope this article was useful but please keep in mind that I don't pretend this way is the best way to do the task of: "Splash Screen for Android App with Custom Background, Centered Logo and Animation" and that is why I wish you to share your recipes to get the same goals if you have enhancements or better way to do it.