This post is based on Roman Nurik artwork and initial idea. He is a great source on Android application design.

The new GMail app that comes with Android 4.0 is full of interesting UI tricks. If you have ever been on dodgy data connection, you probably have already encountered this one that I call the flash bar:

There is a little text block for it at the bottom of the Confirming & Acknowledging Android design page.

This bar is used to warn of a non-fatal error in an unobstrusive manner and offer a quick way to retry the operation which failed. If the user actually don’t care about it, the bar will disappear after a small amount of time.

For these cases, it efficiently replaces a normal AlertDialog which is much more costly in term of user interaction.

As such, it’s an excellent pattern to handle most network errors in an app since they happen often, are generally non lethal and can be easily relaunched.

As you can see in the screenshot, flash bars are very similar to normal Toast messages. The problem is that toast messages can never gain the focus and thus you can’t use any interactive UI element (like buttons) inside them, that’s why the bar needs to be a custom XML layout snippet.

First of all, download the following zip containing the 9-patch images and the style definition for the flashbar. Put its content in your application Resources directory (merging the styles.xml file with what you already have).

Next, you will need to tune up a bit the XML layout of the Activity that will contain a flash bar. Essentially, it should look like this:

<?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">
	<LinearLayout
		android:orientation="vertical"
		android:layout_width="fill_parent"
		android:layout_height="fill_parent">
		<!-- Rest of your normal XML layout definition -->
	</LinearLayout>
	<LinearLayout
		android:id="@+id/flashbar"
		style="@style/FlashBar">
		<TextView
			android:id="@+id/flashbar_message"
			style="@style/FlashBarMessage"
			android:text="Some error string" />
		<Button
			android:id="@+id/flashbar_button"
			style="@style/FlashBarButton"
			android:text="Retry" />
	</LinearLayout>
</FrameLayout>

The overlay trick is achieved by using multiple children in a container FrameLayout which stack them bottom to top on the screen. If you have an existing layout where you want to add a flash bar, the first child LinearLayout can be the one that was enclosing your layout initially.

Now, the code manipulating that bar follows:

using System;
using System.Threading.Tasks;

using Android.Animation;
using Android.OS;
using Android.Text;
using Android.Views;
using Android.Widget;

public class FlashBarController : AnimatorListenerAdapter
{
	View barView;
	TextView messageView;
	ViewPropertyAnimator barAnimator;
	Handler hideHandler = new Handler();
	
	string message;
	Action hideRunnable;
	Action flashBarCallback;
	
	const int DefaultHideTime = 5000;
	
	public FlashBarController (View flashBarView)
	{
		barView = flashBarView;
		barAnimator = barView.Animate ();
		
		messageView = barView.FindViewById<TextView> (Resource.Id.flashbar_message);
		var flashBarBtn = barView.FindViewById<Button> (Resource.Id.flashbar_button);
		flashBarBtn.Click += delegate {
			HideBar (false);
			if (flashBarCallback != null)
				flashBarCallback ();
		};
		hideRunnable = () => HideBar(false);
		
		HideBar (true);
	}
	
	public void ShowBarUntil (Func<bool> flashBarCallback, bool immediate = false, string withMessage = null, int withMessageId = -1)
	{
		Action callback = () => {
			var t = Task.Factory.StartNew (flashBarCallback);
			t.ContinueWith (_ => {
				if (t.Exception != null || !t.Result)
					hideHandler.Post (() => ShowBarUntil (flashBarCallback, immediate, withMessage, withMessageId));
			});
		};
		ShowBar (callback, immediate, withMessage, withMessageId);
	}
	
	public void ShowBar (Action flashBarCallback, bool immediate = false, string withMessage = null, int withMessageId = -1)
	{
		if (withMessage != null) {
			this.message = withMessage;
			messageView.Text = message;
		}
		if (withMessageId != -1) {
			this.message = barView.Resources.GetString (withMessageId);
			messageView.Text = message;
		}
		
		this.flashBarCallback = flashBarCallback;
		hideHandler.RemoveCallbacks (hideRunnable);
		hideHandler.PostDelayed (hideRunnable, DefaultHideTime);
		
		barView.Visibility = ViewStates.Visible;
		if (immediate) {
			barView.Alpha = 1;
		} else {
			barAnimator.Cancel();
			barAnimator.Alpha (1);
			barAnimator.SetDuration (barView.Resources.GetInteger (Android.Resource.Integer.ConfigShortAnimTime));
			barAnimator.SetListener (null);
		}
	}
	
	public void HideBar (bool immediate = false)
	{
		hideHandler.RemoveCallbacks (hideRunnable);
		if (immediate) {
			barView.Visibility = ViewStates.Gone;
			barView.Alpha = 0;
		} else {
			barAnimator.Cancel();
			barAnimator.Alpha (0);
			barAnimator.SetDuration (barView.Resources.GetInteger (Android.Resource.Integer.ConfigShortAnimTime));
			barAnimator.SetListener (this);
		}
	}
	
	public override void OnAnimationEnd (Animator animation)
	{
		barView.Visibility = ViewStates.Gone;
		message = null;
	}
}

You generally instantiate this class after inflating your Activity layout by passing it the LinearLayout of the flash bar as a View like so:

var view = inflater.Inflate (Resource.Layout.MyMainLayout, container, false);
// ...
var flashBarView = view.FindViewById (Resource.Id.flashbar);
flashBarCtrl = new FlashBarController (flashBarView);

Afterwards, you can use either ShowBar or ShowBarUntil to display the flash bar.

Each of these methods accepts a boolean parameter to disable animation and you can set the text of the bar either by string id or directly by passing a string instance. The callback is the action to be called when the user tap the bar button.

Here are two examples using the above methods:

// ShowBarUntil
// If the callback returns false or throws an exception, the bar will be shown again
flashBarCtrl.ShowBarUntil (() => {
	DoNetworkCall ();
	DoSomeOtherStuff ();
	return true;
}, withMessageId: Resource.String.flashbar_tab_error);

// ShowBar
flashBarCtrl.ShowBar (() => RecursivelyCallTheExecutingMethod (withThe, sameParameters),
                      withMessage: "Problem while contacting server");