39

I was wondering if it's possible to somehow tap outside a popup dialog (or an Activity with a dialog theme), and dismiss it by just tapping outside of it?

I made a quick picture to illustrate it:

enter image description here

Normally, you have to press the back key to dismiss the dialogs, but on Honeycomb it could be great to have the option of just tapping outside the dialog, due to all the screen estate.

Adil Soomro
  • 37,609
  • 9
  • 103
  • 153
Michell Bak
  • 13,182
  • 11
  • 64
  • 121

12 Answers12

92
dialog.setCanceledOnTouchOutside(true) 

Sets whether this dialog is canceled when touched outside the window's bounds.

Francesco Vadicamo
  • 5,522
  • 35
  • 29
  • 2
    This is the best solution...So simple. Why isn't this the answer? – Ryan R Dec 06 '11 at 07:14
  • 1
    I needed it to work on an Activity with the dialog theme, and this won't work in that case, but I've upvoted it for general dialogs. – Michell Bak Jan 06 '12 at 14:30
  • 3
    `this.setFinishOnTouchOutside(false);` works for a Dialog Activity – Nick Mar 11 '14 at 18:11
  • 2
    No such method in `AlertDialog.Builder`, me not happy. – Pang Apr 10 '14 at 10:17
  • Here I posted the complete solution: http://stackoverflow.com/questions/23126701/prevent-dialog-activity-from-interacting-with-background-activity-when-clickin/23128194#23128194 – Jacek Kwiecień Apr 17 '14 at 08:43
  • 1
    @Pang for `AlertDialog.Builder` try `alertBox.setCancelable(false);` – suja Apr 25 '14 at 08:59
  • @Pang @Xylian `SetCanceledOnTouchOutside` is a function that can be called on the AlertDialog returned by `AlertDialog.Builder(activity).Create()` its not not on the builder itself. – ForceMagic May 28 '14 at 17:35
  • @Pang you can set the AlertDialog.Builder in Dialog reference like : Dialog dia = new AlertDialog.Builder(this) and use dia to use SetCanceledOnTouchOutside method – Oubaida AlQuraan Apr 04 '15 at 12:16
47

My app is a single activity with Theme.Holo.Dialog. In my case the other answer did not work. It only made the other background apps or the launch screen to receive touch events.

I found that using dispatchTouchEvent works in my case. I think it is also a simpler solution. Here's some sample code on how to use it to detect taps outside the activity with a Dialog theme:

@Override
public boolean dispatchTouchEvent(MotionEvent ev) {
    Rect dialogBounds = new Rect();
    getWindow().getDecorView().getHitRect(dialogBounds);

    if (!dialogBounds.contains((int) ev.getX(), (int) ev.getY())) {
        // Tapped outside so we finish the activity
        this.finish();
    }
    return super.dispatchTouchEvent(ev);
}
Jan S.
  • 10,328
  • 3
  • 31
  • 36
  • 12
    This works better if you change the if condition to `if (!dialogBounds.contains((int) event.getX(), (int) event.getY()) && event.getAction() == MotionEvent.ACTION_DOWN)` That way it doesn't close if the user accidentally moves their finger outside the `Activity`. – Glitch Nov 04 '11 at 12:17
  • 1
    Using API level 8, Using an activity with theme `android:Theme.Dialog` and with this code: `dialogBounds.top` and `dialogBounds.left` have the value 0; and `dialogBounds.bottom` and `dialogBounds.right` have the values of the screen size, suggesting that the diolog window is actually assumed as full screen. So I can't put this code to work. Any other ideas why this is happening? – Jorge Dec 28 '12 at 10:06
14

There is a TouchInterceptor method which will called when you touch on out side of popup window

For example

mWindow.setTouchInterceptor(new OnTouchListener() {
            @Override
            public boolean onTouch(View v, MotionEvent event) {
                if (event.getAction() == MotionEvent.ACTION_OUTSIDE) {
                    mWindow.dismiss();

                    return true;
                }

                return false;
            }
        });

mWindow is the popup window

And if you want same functionality for Activity you have to follow below steps.

1) Add flag before setContentView() method called in onCreate();

 getWindow().setFlags(LayoutParams.FLAG_NOT_TOUCH_MODAL, LayoutParams.FLAG_NOT_TOUCH_MODAL);

    // ...but notify us that it happened.
    getWindow().setFlags(LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH, LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH);

2) Override onTouchEvent() event in Activity

and write below code

 @Override
        public boolean onTouchEvent(MotionEvent event) {
            if (event.getAction() == MotionEvent.ACTION_OUTSIDE) {
                Toast.makeText(getApplicationContext(), "Finish", 3000).show();
                finish();               
                return true;
            }
            return false;
        }

The complete copy is here

Activity

package net.londatiga.android;

import android.app.Activity;
import android.os.Bundle;

import android.view.MotionEvent;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.View.OnTouchListener;
import android.view.WindowManager.LayoutParams;

import android.widget.Button;
import android.widget.Toast;

public class NewQuickAction3DActivity extends Activity implements OnTouchListener {

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
         // Make us non-modal, so that others can receive touch events.
        getWindow().setFlags(LayoutParams.FLAG_NOT_TOUCH_MODAL, LayoutParams.FLAG_NOT_TOUCH_MODAL);

        // ...but notify us that it happened.
        getWindow().setFlags(LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH, LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH);

        setContentView(R.layout.main);

    }


    @Override
    public boolean onTouchEvent(MotionEvent event) {
        if (event.getAction() == MotionEvent.ACTION_OUTSIDE) {
            Toast.makeText(getApplicationContext(), "Hi", 3000).show();

            return true;
        }

        return false;
    }
}

This is manifest.xml

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
      package="net.londatiga.android"
      android:versionCode="1"
      android:versionName="1.0">
    <uses-sdk android:minSdkVersion="7" />

    <application android:icon="@drawable/icon" android:label="@string/app_name">
        <activity android:name=".NewQuickAction3DActivity"
                  android:label="@string/app_name" android:theme="@android:style/Theme.Holo.Dialog">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />
                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>

    </application>
</manifest>
Dharmendra
  • 33,296
  • 22
  • 86
  • 129
  • 2
    This is for `PopupWindow` only, right? I'm using a standard Activity with the Theme.Holo.Dialog theme in Honeycomb. – Michell Bak Aug 27 '11 at 12:07
  • Yeah, I tried it before you wrote it, but it didn't work either :( Missing a semicolon on finish() btw :) – Michell Bak Aug 27 '11 at 12:27
  • Using Theme.Holo.Dialog? Remember, this is Honeycomb. – Michell Bak Aug 27 '11 at 12:34
  • If you want to test in small screen just set theme of activity as dialog and click outside it will give you message. – Dharmendra Aug 27 '11 at 12:34
  • I'm using a Honeycomb tablet, and I'm starting an activity with Theme.Holo.Dialog from another activity, and pressing outside the activity dialog bounds doesn't work. – Michell Bak Aug 27 '11 at 12:35
  • Yes I had test in Honeycomb tablet emulator using Theme.Holo.Dialog and it is working fine for me – Dharmendra Aug 27 '11 at 12:44
  • Did you set the theme in the manifest.xml file? That's where I set it. – Michell Bak Aug 27 '11 at 12:45
  • 1
    Yeah, that works - but I don't want the background activity to receive touch events. I have some buttons in the background activity that shouldn't be triggered. I guess I could just disable it upon starting the popup intent, but if there's an easier way, I'd definitely prefer that. – Michell Bak Aug 27 '11 at 13:08
  • Can you come in chat room "Android Discussion" ? – Dharmendra Aug 27 '11 at 13:13
  • @Dharmendra let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/2916/discussion-between-michell-bak-and-dharmendra) – Michell Bak Aug 27 '11 at 13:25
  • This pretty much work, the problem is when I touch outside I also interact with the UI elements of the activity below which is bad. – Jacek Kwiecień Apr 17 '14 at 07:01
6

You may use

  dialog.setCancelable(true\false); 

For the lastest vesrions of Android;

It will disable outSideTouching event.

Amt87
  • 5,493
  • 4
  • 32
  • 52
5

You could use Activity#setFinishOnTouchOutside too, if your dialog is an Activity. That's gotta be the shortest way for Activitys ;)

(It's API 11+ though. But API <= 10 is generally screen size normal.)

nmr
  • 16,625
  • 10
  • 53
  • 67
4
    dialog = new Dialog(MainActivity.this);
    dialog.requestWindowFeature(Window.FEATURE_NO_TITLE);
    dialog.setContentView(R.layout.dialog_layout);
    dialog.getWindow().setBackgroundDrawableResource(
            android.R.color.transparent);
    dialog.setCancelable(false);

    dialog.setCanceledOnTouchOutside(true);

Check if you have this line of code or not....

    dialog.setCanceledOnTouchOutside(true);
Manoj Behera
  • 2,736
  • 22
  • 13
4

Simply I write dialog.setCanceledOnTouchOutside(false); and it work for me, window will not dismiss on outside tap .

Sachindra N. Pandey
  • 1,177
  • 17
  • 15
2

this.setFinishOnTouchOutside(false);

you can use this

Gopi Cg
  • 384
  • 3
  • 7
  • For dismiss use the `true` value: `this.setFinishOnTouchOutside(true);` This method is needed for the _dialog activity_ but not for pure _dialog_. – gotwo Jan 29 '20 at 20:38
1

Old question but yet another solution:

  1. Make your foreground activity full-screen. Usenested layouts: The full-screen layout should have transparent background (e.g. @null or @android:color/transparent). The inner layout should have a visible background.

  2. Add an OnClickListener to the invisible outer layout that finish()es your activity.

laalto
  • 150,114
  • 66
  • 286
  • 303
1

Use style of dialog rather than other styles.

For example, Use

public YourCustomDialog(Context context) {
    super(context, android.R.style.Theme_Holo_dialog_NoActionBar);
}

When you use other styles like Theme_Translucent_NoTitleBar , the dialog will not be dismissed.

Mark
  • 493
  • 5
  • 10
0

Any views within the dialog can set to consume the touch event so that below won't be called.

onCreate(){
    getWindow().getDecorView().getRootView().setOnTouchListener(new OnTouchListener(){
        @Override
        public boolean onTouch(View v, MotionEvent event) {
            dialog.dismiss();
            return false;
        }
    });
Pang
  • 9,564
  • 146
  • 81
  • 122
0
LayoutParams lp=dialogp.getWindow().getAttributes(); 
lp.flags=LayoutParams.FLAG_LAYOUT_NO_LIMITS;

I added this and it works flawlessly on 3.0 up, but should work on all.

a54studio
  • 965
  • 11
  • 11