Statically Typed

because Hindley-Milner rocks

Android: Styles and Themes with Splash Screens


I continue to play around with all the goodies that are found within the Android API but have yet to find one specifically for a splash screen.  However, I have run into several decent postings on the web for making a splash screen for your application.  They also happen to be on the first page of Google now that content farmers have been hosed:

  1. Splash Screen: Using a threaded, timed Activity with a touch event to control the lifetime of the splash screen
  2. Splash Screen: Using a threaded and timed Activity to control the lifetime of the splash screen
  3. Splash Screen: Using a Handler to control the lifetime of the splash screen

There’s even an SO post about using a Dialog as some sort of splash screen.  Interesting, no?

The first two listings are nearly identical in code content (really identical,) although displayed and written differently.  The first merely adds a touch event to kill the screen quickly.  These are simple and introductory guides and I thank them for putting them up.  However, I wondered, what would happen if you used a Theme or a style with the splash screen?  Could you come up with some sort of crazy magical sweetness?

First Steps: Getting Used to Style Resources

I’m not going to do anything fancier than what was done in the past.  In fact, I can’t see a reason why we should be using anything other than a FrameLayout instead of an ImageView in a ListLayout for the time being.  Let’s keep it simple before complicating things.  Baby steps.

<?xml version="1.0" encoding="utf-8"?>
<FrameLayout  xmlns:android="http://schemas.android.com/apk/res/android"
  android:layout_width="match_parent"
  android:layout_height="match_parent"/>

Next, I want to create a style to use in my project for my splash screen.  Android provides a decent guide on using styles, as well as a list of style attributes and pre-made styles and themes.  In fact, it’s my modus operandi to use a style resource so that I don’t have to write the “match_parent” tags up above or repetitiously add nodes to my child Layouts:

<?xml version="1.0" encoding="utf-8"?>
<resources>
	<style name="Standard">
		<item name="android:layout_width">match_parent</item>
		<item name="android:layout_height">match_parent</item>
	</style>
	<style name="Standard.Splash">
		<item name="android:background">#FFCC66</item>
		<item name="android:foreground">@drawable/oval_shape</item>
	</style>
</resources>

The first style I’ve labeled “Standard” to denote how I feel about it’s use.  The second style tag inherits from the first.  The fact that there is inheritance involved is not obvious as I don’t have a “parent” attribute.  For your own styles Android allows you to pass inheritance within the “name” attribute.  Hence, if I were to create more styles entitle “Standard.<name>” they would all inherit from my “Standard” style.

To incorporate it into my layout, I change the file to look a bit more sparten (I sometimes consider spartan a euphemism for elegant):

<?xml version="1.0" encoding="utf-8"?>
<FrameLayout
  xmlns:android="http://schemas.android.com/apk/res/android"
  style="@style/Standard.Splash"/>

Since I’ve decided to list a drawable called “oval_shape” in my “Standard.Splash” style I need to make it.  I’ll create it in the “drawables” folder like so:

<?xml version="1.0" encoding="utf-8"?>
<shape
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:shape="oval">
    <gradient
    	android:angle="45"
    	android:centerX="0.5"
    	android:centerY="0.3"
    	android:startColor="#330033"
    	android:centerColor="#003366"
    	android:endColor="#330033"
    	android:type="sweep"/>
    <size
    	android:height="25dp"
    	android:width="40dp"/>
</shape>

You can read about shapes from the Android section on Drawables.  They’re a handy means to avoid working in Photoshop or The Gimp when the image desired is simplistic.

Combining this splash screen with the Theme “Theme.NoTitleBar” in the manifest yields a rather basic and unremarkable splash screen:

In my mind I see this as the basis for not only the splash screen (add a game title across the upper extent of the oval) but also the main menu (where you’d then add the “start game,” “options,” and “exit” a la old school Nintendo.)

Next Step: Incorporating Themes

Again, we’re going to work in baby steps.  However, Themes are quite powerful and work some pretty hefty UI magic without the need to drop into the rendering engine.  Let’s have a look at the common Android styles and themes over at the kernel git repository (you’ll need to reference the first to understand the second.)  In particular, focus on the Dialog theme since it is so utterly different from normal screens:

<style name="Theme.Dialog">
  <item name="android:windowFrame">@null</item>
  <item name="android:windowTitleStyle">@android:style/DialogWindowTitle</item>
  <item name="android:windowBackground">@android:drawable/panel_background</item>
  <item name="android:windowIsFloating">true</item>
  <item name="android:windowContentOverlay">@null</item>
  <item name="android:windowAnimationStyle">@android:style/Animation.Dialog</item>
  <item name="android:windowSoftInputMode">stateUnspecified|adjustPan</item>
</style>

I wouldn’t use this as a splash screen.  It’s too sterile and unexciting.  However, at the same point, it does something our previous splash screen couldn’t: it does not consume the entire window.   To get the oval shape to appear hovering over the phone’s normal landscape we could use some of the ideas from the Dialog Theme.  Let’s do it without the outline around the panel or the title bar:

<style name="Island">
	<item name="android:windowFullscreen">false</item>
	<item name="android:windowFrame">@null</item>
	<item name="android:windowNoTitle">true</item>
	<item name="android:windowBackground">@drawable/oval_shape</item>
	<item name="android:windowIsFloating">true</item>
	<item name="android:windowSoftInputMode">stateUnspecified|adjustPan</item>
	<item name="android:windowAnimationStyle">@android:style/Animation.Dialog</item>
	<item name="android:windowContentOverlay">@null</item>
</style>

An important distinction that needs to be made here is that I’m creating a Theme, not just a style.  Both Themes and styles impact the way the UI appears to the user but they do so through different routes.  It may be enclosed in a style tag and thus tempting to think about using them in a Layout but it is a bad idea.  Put Themes in the manifest with your Activities.  Don’t include layout attributes with Themes.  There should be no mixing and matching.

Now, to really accentuate that we’re not going to try to consume the entire Android phone landscape set the Layout of the splash screen to look like this:

<?xml version="1.0" encoding="utf-8"?>
<FrameLayout
  xmlns:android="http://schemas.android.com/apk/res/android"
  android:layout_height="200dp"
  android:layout_width="200dp"/>

And magic happens…

Again, I still wouldn’t use this as a splash screen unless I had a much better graphic.  It’s really a perfect way to set off an AsyncTask in the background while your user thinks the application is just starting up.  It gives the feeling of activity without the feeling of the wait.

Putting it all Together

Now it’s time to think about getting really fancy.  Movies and applications sometimes make use of a fade-away.  That is, one screen fades into another.  That’s one way of doing it but another is to have the next scene “eat away” at the former.  I’d like to create a splash screen which either pulses or grows so that I don’t abruptly switch over to the title screen of my application without resorting to a fade-away.

Let’s take the “Island” theme up above and change it so that irregardless of the content of the FrameView, the background is always translucent:

<color name="blank">#00000000</color>
<style name="Island.Blank">
	<item name="android:windowBackground">@color/blank</item>
</style>

Like in the example before, I’m inheriting from “Island” and augmenting it with a “windowBackground” reference to a  Color resource.

On the FrameLayout front I’ll want to add the animated image.  This involves a combination of background Drawable and either a Frame or Tween Animation.  Since Tween Animations are smoother than the frame by frame nature of Frame Animations I’ll choose that for aesthetic reasons.

<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android"
    android:interpolator="@android:anim/cycle_interpolator"
    android:shareInterpolator="false" >
    <scale
    	android:fromXScale="0.1"
        android:toXScale="2.0"
        android:fromYScale="0.1"
        android:toYScale="2.0"
        android:pivotX="50%"
        android:pivotY="50%"
        android:duration="2000"/>
</set>

The one salient point to remember about animation resources is that they do not force a layout to recalculate the size it needs to be.  Any animation which attempts to augment the size of an image will need to have enough padding to compensate for potential clipping of the image.  If you don’t know how much padding that is, choosing an arbitrarily large number will suffice.

<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
  	style="@style/Standard"
  	android:id="@+id/splash_frame"
  	android:padding="200dp"
  	android:background="@drawable/oval_shape">
</FrameLayout>

Finally, I need to update the code in my “SplashScreen” Activity to include a call to start the animation:

FrameLayout view = (FrameLayout)findViewById(R.id.splash_frame);
Animation anim = AnimationUtils.loadAnimation(this, R.anim.oval_tween);
view.startAnimation(anim);
if(anim.hasStarted()){
	Log.d("SplashScreen", "Animation has Started");
}

With perhaps a little debugging so that I know if I forgot to add padding I’d know the animation really was running (hint: that’s how I figured out that the layout isn’t updated with the Drawable.)  So was “200dp”  enough to see a smooth and well functioning animation?

Drat!  It wasn’t enough.  I needed more padding than I gave it and the clipping at the edges proves it.  For a better example (with video!) of several animations in a view see My life with Android.

Errata

The code I’m using is an almost direct copy of the code from the first two blogs.  I’ve added the animation portion detailed above.  I’d like to give credit to whichever one of them came up with it first (I don’t know, someone isn’t thanking someone else):

public class SplashScreen extends Activity {
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.splash_screen);
        FrameLayout view = (FrameLayout)findViewById(R.id.splash_frame);
        Animation anim = AnimationUtils.loadAnimation(this, R.anim.oval_tween);
        view.startAnimation(anim);
        if(anim.hasStarted()){
        	Log.d("SplashScreen", "Has Started");
        }

        Thread splashThread = new Thread() {
            @Override
            public void run() {
               try {
                  sleep(2000);
               } catch (InterruptedException e) {
                  // do nothing
               } finally {
                  finish();
                  Intent intent = new Intent();
                  intent.setClassName("com.owein","com.owein.Main");
                  startActivity(intent);
               }
            }
         };
         splashThread.start();
    }
}

I’d also like to add that it’s a personal misunderstanding as to why Google chose to always have an application title bar present as the default.  It’s ugly, jives against my aesthetics, and serves no real purpose (other than Hello World applications.)  I’m sure others would disagree but it’s my blog and I’ll cry if I want to, cry if I want to…

Advertisements

One comment on “Android: Styles and Themes with Splash Screens

  1. William Kida
    March 30, 2012

    Cool.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

Information

This entry was posted on March 1, 2011 by in Android, Java.
%d bloggers like this: