54

Is there a simple way to disable a user interacting with an activity. To be done when there is an action running (and a spinning progress bar in the title bar)

EDIT: As it seems I was not clear enough I meant to say: while I already have a spinning progress bar, the user is still able to push any button on the activity, I want to disable the user from being able to do that while the task is running. I do not want to however disable each item on the screen one by one.

Thanks, Jason

Jason
  • 4,034
  • 4
  • 40
  • 62
  • Do you want to visibly disable all views, or do you just want them to not respond (=not very intuitive for the user)? Or do you want to show a ProgressDialog on top of your activity? – EboMike Nov 25 '10 at 20:25
  • Ok, I might have been a little unclear, I meant I already have a spinning dialog but I do not want the user to push more buttons while its working, (IE- disable all items in the activity - but I do not want to do this one by one ) – Jason Nov 25 '10 at 21:51

7 Answers7

153

In order to block user touch events, use:

getWindow().setFlags(WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE,
WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE);

To get touch events back, use:

getWindow().clearFlags(WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE);

EDIT: If you want to add a feature of disable and greyed out display, you need to add in your xml layout file a linear layout that fills the parent. Set its background to #B0000000 and its visibilty to Gone. Than programicly set its visibility to Visible.

Uriel Frankel
  • 14,304
  • 8
  • 47
  • 69
  • 1
    If this does what it sounds like it does, then it suffers from the problem that the user will not see the UI as "Disabled" (Grayed out) – Jason May 23 '12 at 17:23
  • 1
    Ok, I have a solution for greying out the screen. Ill post it later – Uriel Frankel May 24 '12 at 07:17
  • Does anyone knows what WindowManager is? Thought I could import it, but eclipse does not propose it to me, so I guess I should get it from another way... – WhiskThimble Jun 03 '13 at 15:00
  • 4
    Don't forget that this will only prevent touch events, so the user will still be able to interact through other input methods, such as a hard keyboard – sorianiv May 17 '16 at 19:40
  • 1
    This is working like charm... very nice solution... thanx – venkat Jan 25 '17 at 13:36
  • this will also disable the toolbar back button.. any way to keep toolbar buttons clickable? – Siddarth G Jan 06 '20 at 10:35
  • 3
    This does NOT work for translucent activities. In that case, a tap will be made on the content, which is present in the background activity. – Mangesh Apr 18 '20 at 11:35
11

If you need to disable event processing for a period of time (for instance, while you run an animation, show a waiting dialog), you can override the activity's dispatch functions.

To disable touch/clicks on any buttons, add these members/functions to your activity:

protected boolean enabled = true;

public void enable(boolean b) {
    enabled = b;
}

@Override
public boolean dispatchTouchEvent(MotionEvent ev) {
    return enabled ? 
        super.dispatchTouchEvent(ev) : 
        true;        
}

Then just call enable(true/false) when you need to disable and enable the activity's normal event handling.

ricosrealm
  • 1,616
  • 1
  • 16
  • 26
  • with a few tweaks to invert the boolean, this can be expressed more succinctly as `return disabled || super.dispatchTouchEvent(ev);` – gMale Dec 15 '15 at 14:50
  • @gMale The return value of the method can indeed be condensed, but there is no need to invert the boolean. The following does the trick: `!enabled || super.dispatchTouchEvent(ev)`. Android Studio will suggest that automatically. – Sid Aug 03 '17 at 17:47
1

Use AsyncTask with ProgressDialog bundled.

  1. AsyncTask

  2. Progress Dialog

another useful example:

http://www.screaming-penguin.com/node/7746

Vladimir Ivanov
  • 42,730
  • 18
  • 77
  • 103
0

I solved this by adding an full screen blank image with a null click handler at the end on the XML layout.

Create a transparent PNG file in the drawables folder.

Add a full screen ImageView at the end of the XML layout referencing the image:

...
 <ImageView
     android:layout_width="match_parent"
     android:layout_height="match_parent"
     app:srcCompat="@drawable/img_mask"
     android:id="@+id/imgMask"
     android:scaleType="fitXY"
 android:visibility="gone"
     android:onClick="doNothingClick"
 />

Add the null click hander for the image to capture user touches:

public void doNothingClick(View v){
    // do nothing with the click
}

Add the code to disable the user touches:

private void StopTouches(int duration){
    findViewById(R.id.imgMask).setVisibility(View.VISIBLE);
    Handler handler = new Handler();
    handler.postDelayed(new Runnable() {
        @Override
        public void run() {
            findViewById(R.id.imgMask).setVisibility(View.GONE);
        }
    }, duration);
}
PKanold
  • 139
  • 7
0

I have solved this using a custom method - which I did not want to do:

public static void setViewGroupEnabled(ViewGroup view, boolean enabled)
    {
        int childern = view.getChildCount();

        for (int i = 0; i< childern ; i++)
        {
            View child = view.getChildAt(i);
            if (child instanceof ViewGroup)
            {
                setViewGroupEnabled((ViewGroup) child, enabled);
            }
            child.setEnabled(enabled);
        }
        view.setEnabled(enabled);
    }

If anyone finds a better way I'd like to hear about it! Thanks.

TWiStErRob
  • 44,762
  • 26
  • 170
  • 254
Jason
  • 4,034
  • 4
  • 40
  • 62
0

The code of Uriel Frankel (accepted response), works good, but in my case works after my request it's done :(. I want to block before it happend. Some one knows what is wrong in my code (I'm beginning in this..)

(this is a fragment)

   login_login_btn.setOnClickListener {

    if (validateInputs()){
        showSpinner()
        thread {
            doLogin()
        }
    } else {
        validationError("Validation Error","Checkout your inputs. Common errors: \npassword (at least 8 characters)")
    }

}

}

Function after OnViewCreated

fun showSpinner(){
    activity?.window?.setFlags(
        WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE,
        WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE)
    spinner.visibility = View.VISIBLE
}

Thank you (Y)

Mahesh Jamdade
  • 17,235
  • 8
  • 110
  • 131
-2

SpinningProgress in the title bar:

//onCreate(): 
activity.requestWindowFeature(FEATURE_INDETERMINATE_PROGRESS);

//and then: 
activity.setProgressBarIndeterminate(boolean indeterminate)

both in Activity class

Another option is using Progress Dialog (you might want to set cancelable to false on it).

Pedro Loureiro
  • 11,436
  • 2
  • 31
  • 37