Android

Create a transparent progress dialog on Android

A game development hobby project inspired this app developer to figure out a way to create a transparent progress dialog that animates an image. He describes how to do it.

Over the last year I've been working hard in my spare time writing a multiplayer game for mobile devices. It's slow going, and often after putting in eight or more hours at my day gig (where I also write applications), I start thinking I need to get a new hobby that doesn't involve computers, cell phones, or tablets.

Still, I do it not just because I enjoy seeing my games out there in the market, but also because game programming is unique in that it often tends to veer from the standard platform conventions. Game developers frequently find themselves thinking creatively, particularly when it comes to user experience and user interface. 

What's all this got to do with transparent progress dialogs on Android? Well, Android's out-of-the-box progress dialog is anything but exciting (Figure A).

Figure A

AndroidProcessDialog_FigA_082713.png

See what I mean?

For my game I needed the functionality of a blocking progress dialog without the dialog part. After poking around the Android documentation, a number of developer forums, and a lot of trial and error, I succeeded in creating a transparent progress dialog that simply animates an image of my choosing. This tutorial walks you through the steps, so you can do the same. If you prefer, you can download and import the project directly in Eclipse.

1. Create a new Android project in Eclipse targeting Android 2.2 or better.

2. In the /res/layout folder, create a linear layout in activity_main.xml. Add a text label and a button.

activity_main.xml
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent" 
    android:orientation="vertical">

    <TextView
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:gravity="center_horizontal"
        android:padding="8dp"
        android:textSize="20sp"
        android:text="Transparent Progress Indicator" />
    
    <Button 
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Check it out!"
        android:layout_marginTop="40dp"
        android:layout_gravity="center"
        android:id="@+id/the_button" />

</LinearLayout>

3. In the /res/values folder, open styles.xml, which is where you will add the style for our transparent dialog. Be sure to specify the parent attribute, or you will have problems at runtime.

styles.xml
<resources>

    <!--
        Base application theme, dependent on API level. This theme is replaced
        by AppBaseTheme from res/values-vXX/styles.xml on newer devices.
    -->
    <style name="AppBaseTheme" parent="android:Theme.Light">
        <!--
            Theme customizations available in newer API levels can go in
            res/values-vXX/styles.xml, while customizations related to
            backward-compatibility can go here.
        -->
    </style>

    <!-- Application theme. -->
    <style name="AppTheme" parent="AppBaseTheme">
        <!-- All customizations that are NOT specific to a particular API-level can go here. -->
    </style>
    
    <!--  Transparent dialog -->
    <style name="TransparentProgressDialog" parent="@android:Theme.Dialog">
        <item name="android:windowFrame">@null</item>
        <item name="android:windowBackground">@android:color/transparent</item>
        <item name="android:windowIsFloating">true</item>
        <item name="android:windowContentOverlay">@null</item>
        <item name="android:windowTitleStyle">@null</item>
        <item name="android:windowAnimationStyle">@android:style/Animation.Dialog</item>
        <item name="android:windowSoftInputMode">stateUnspecified|adjustPan</item>
        <item name="android:backgroundDimEnabled">true</item>
        <item name="android:background">@android:color/transparent</item>
    </style>

</resources>

4. Create a /drawable folder in the /res directory and add an image to represent our spinner. The animation is a simple rotation, so you'll want to use something that is exactly as wide as it is tall. Here's the image I chose (Figure B).

Figure B

AndroidProcessDialog_FigB_082713.png

5. Now you can implement your MainActivity.java file. First, you override the on create and wire up your button handler. Note that in the on create you are instantiating a dialog and a handler; these reference an inner class that you will get to shortly. The last thing MainActivity.java is responsible for is releasing the handler and the dialog when the activity gets destroyed.

MainActivity.java
package com.authorwjf.transparentprogressdialog;

import android.os.Bundle;
import android.os.Handler;
import android.app.Activity;
import android.app.Dialog;
import android.content.Context;
import android.view.Gravity;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.ViewGroup.LayoutParams;
import android.view.WindowManager;
import android.view.animation.Animation;
import android.view.animation.LinearInterpolator;
import android.view.animation.RotateAnimation;
import android.widget.ImageView;
import android.widget.LinearLayout;

public class MainActivity extends Activity implements OnClickListener {

	private TransparentProgressDialog pd;
	private Handler h;
	private Runnable r;
	
	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_main);
		h = new Handler();
		pd = new TransparentProgressDialog(this, R.drawable.spinner);
		r =new Runnable() {
			@Override
			public void run() {
				if (pd.isShowing()) {
					pd.dismiss();
				}
			}
		};
		findViewById(R.id.the_button).setOnClickListener(this);
	}
	
	@Override
	public void onClick(View v) {
		pd.show();
		h.postDelayed(r,5000);
	}
	
	@Override
	protected void onDestroy() {
		h.removeCallbacks(r);
		if (pd.isShowing() ) {
			pd.dismiss();
		}
		super.onDestroy();
	}

}

6. Add the inner class just below your on destroy method. The constructor builds your transparent dialog, and the show method displays it and starts the animation running.

private class TransparentProgressDialog extends Dialog {
		
	private ImageView iv;
		
	public TransparentProgressDialog(Context context, int resourceIdOfImage) {
		super(context, R.style.TransparentProgressDialog);
        	WindowManager.LayoutParams wlmp = getWindow().getAttributes();
        	wlmp.gravity = Gravity.CENTER_HORIZONTAL;
        	getWindow().setAttributes(wlmp);
		setTitle(null);
		setCancelable(false);
		setOnCancelListener(null);
		LinearLayout layout = new LinearLayout(context);
		layout.setOrientation(LinearLayout.VERTICAL);
		LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT);
		iv = new ImageView(context);
		iv.setImageResource(resourceIdOfImage);
		layout.addView(iv, params);
		addContentView(layout, params);
	}
		
	@Override
	public void show() {
		super.show();
		RotateAnimation anim = new RotateAnimation(0.0f, 360.0f , Animation.RELATIVE_TO_SELF, .5f, Animation.RELATIVE_TO_SELF, .5f);
		anim.setInterpolator(new LinearInterpolator());
		anim.setRepeatCount(Animation.INFINITE);
		anim.setDuration(3000);
		iv.setAnimation(anim);
		iv.startAnimation(anim);
	}
}

Load the resulting application to a device or the emulator to have a look (Figure C).

Figure C

AndroidProcessDialog_FigC_082713.png

It's not every day you want a big red sunburst in the middle of your application UI, but the point is you can put any image of any size there. You can apply any of Android's built-in animations, and adding floating text is as easy as instantiating a text view in the class constructor and pushing it into the layout.

Once you have a chance to play around with it, share your thoughts in the discussion thread.

About

William J Francis began programming computers at age eleven. Specializing in embedded and mobile platforms, he has more than 20 years of professional software engineering under his belt, including a four year stint in the US Army's Military Intellige...

0 comments

Editor's Picks