Display a loading overlay on Android screen
Maybe too late, but I guess somebody might find it useful.
Activity:
public class MainActivity extends Activity implements View.OnClickListener { String myLog = "myLog"; AlphaAnimation inAnimation; AlphaAnimation outAnimation; FrameLayout progressBarHolder; Button button; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); button = (Button) findViewById(R.id.button); progressBarHolder = (FrameLayout) findViewById(R.id.progressBarHolder); button.setOnClickListener(this); } @Override public void onClick(View v) { switch (v.getId()) { case R.id.button: new MyTask().execute(); break; } } private class MyTask extends AsyncTask <Void, Void, Void> { @Override protected void onPreExecute() { super.onPreExecute(); button.setEnabled(false); inAnimation = new AlphaAnimation(0f, 1f); inAnimation.setDuration(200); progressBarHolder.setAnimation(inAnimation); progressBarHolder.setVisibility(View.VISIBLE); } @Override protected void onPostExecute(Void aVoid) { super.onPostExecute(aVoid); outAnimation = new AlphaAnimation(1f, 0f); outAnimation.setDuration(200); progressBarHolder.setAnimation(outAnimation); progressBarHolder.setVisibility(View.GONE); button.setEnabled(true); } @Override protected Void doInBackground(Void... params) { try { for (int i = 0; i < 5; i++) { Log.d(myLog, "Emulating some task.. Step " + i); TimeUnit.SECONDS.sleep(1); } } catch (InterruptedException e) { e.printStackTrace(); } return null; } }}
Layout xml:
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" tools:context=".MainActivity"> <Button android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="Start doing stuff" android:id="@+id/button" android:layout_below="@+id/textView" android:layout_centerHorizontal="true" /> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:textAppearance="?android:attr/textAppearanceLarge" android:text="Do Some Stuff" android:id="@+id/textView" android:layout_alignParentTop="true" android:layout_centerHorizontal="true" /> <FrameLayout android:id="@+id/progressBarHolder" android:animateLayoutChanges="true" android:visibility="gone" android:alpha="0.4" android:background="#000000" android:layout_width="match_parent" android:layout_height="match_parent"> <ProgressBar style="?android:attr/progressBarStyleLarge" android:layout_width="wrap_content" android:layout_height="wrap_content" android:indeterminate="true" android:layout_gravity="center" /> </FrameLayout></RelativeLayout>
I like the approach in Kostya But's answer.
Building on that, here's a couple of ideas to make the same overlay easily reusable across your app:
Consider putting the overlay FrameLayout in a separate layout file, e.g. res/layout/include_progress_overlay
:
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android" android:id="@+id/progress_overlay" android:layout_width="match_parent" android:layout_height="match_parent" android:alpha="0.4" android:animateLayoutChanges="true" android:background="@android:color/black" android:clickable="true" android:visibility="gone"> <ProgressBar style="?android:attr/progressBarStyleLarge" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="center" android:indeterminate="true"/></FrameLayout>
(One thing I added in the overlay FrameLayout is android:clickable="true"
. So while the overlay is shown, it prevents clicks going through to UI elements underneath it. At least in my typical use cases this is what I want.)
Then include it where needed:
<!-- Progress bar overlay; shown while login is in progress --><include layout="@layout/include_progress_overlay"/>
And in code:
View progressOverlay;[...]progressOverlay = findViewById(R.id.progress_overlay);[...]// Show progress overlay (with animation): AndroidUtils.animateView(progressOverlay, View.VISIBLE, 0.4f, 200);[...]// Hide it (with animation): AndroidUtils.animateView(progressOverlay, View.GONE, 0, 200);
With animation code extracted into a util method:
/** * @param view View to animate * @param toVisibility Visibility at the end of animation * @param toAlpha Alpha at the end of animation * @param duration Animation duration in ms */public static void animateView(final View view, final int toVisibility, float toAlpha, int duration) { boolean show = toVisibility == View.VISIBLE; if (show) { view.setAlpha(0); } view.setVisibility(View.VISIBLE); view.animate() .setDuration(duration) .alpha(show ? toAlpha : 0) .setListener(new AnimatorListenerAdapter() { @Override public void onAnimationEnd(Animator animation) { view.setVisibility(toVisibility); } });}
(Here using view.animate()
, added in API 12, instead of AlphaAnimation
.)
I have ProgressBar in Relative Layout and I hide or show it respectively. And yes activity can be transparent.
<?xml version="1.0" encoding="utf-8"?><RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" > <LinearLayout android:id="@+id/hsvBackgroundContainer" android:layout_width="match_parent" android:layout_height="match_parent" android:layout_alignParentLeft="true" android:layout_alignParentTop="true" </LinearLayout> <ProgressBar android:id="@+id/pbProgess" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_centerHorizontal="true" android:layout_centerVertical="true" /></RelativeLayout>