Tap outside Android dialog to dismiss it?

32,883

Solution 1

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);
}

Solution 2

dialog.setCanceledOnTouchOutside(true) 

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

Solution 3

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>

Solution 4

You may use

  dialog.setCancelable(true\false); 

For the lastest vesrions of Android;

It will disable outSideTouching event.

Solution 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.)

Share:
32,883
Michell Bak
Author by

Michell Bak

I like Android. Android is good for me. And you.

Updated on January 10, 2020

Comments

  • Michell Bak
    Michell Bak over 4 years

    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.

  • Michell Bak
    Michell Bak over 12 years
    This is for PopupWindow only, right? I'm using a standard Activity with the Theme.Holo.Dialog theme in Honeycomb.
  • Michell Bak
    Michell Bak over 12 years
    Yeah, I tried it before you wrote it, but it didn't work either :( Missing a semicolon on finish() btw :)
  • Michell Bak
    Michell Bak over 12 years
    Using Theme.Holo.Dialog? Remember, this is Honeycomb.
  • Dharmendra
    Dharmendra over 12 years
    If you want to test in small screen just set theme of activity as dialog and click outside it will give you message.
  • Michell Bak
    Michell Bak over 12 years
    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.
  • Dharmendra
    Dharmendra over 12 years
    Yes I had test in Honeycomb tablet emulator using Theme.Holo.Dialog and it is working fine for me
  • Michell Bak
    Michell Bak over 12 years
    Did you set the theme in the manifest.xml file? That's where I set it.
  • Michell Bak
    Michell Bak over 12 years
    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.
  • Dharmendra
    Dharmendra over 12 years
    Can you come in chat room "Android Discussion" ?
  • Michell Bak
    Michell Bak over 12 years
  • Glitch
    Glitch over 12 years
    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.
  • Ryan R
    Ryan R over 12 years
    This is the best solution...So simple. Why isn't this the answer?
  • Michell Bak
    Michell Bak over 12 years
    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.
  • Jorge
    Jorge over 11 years
    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?
  • Amt87
    Amt87 over 10 years
    It is tested for all versions except KITKAT :)
  • Nick
    Nick about 10 years
    this.setFinishOnTouchOutside(false); works for a Dialog Activity
  • Pang
    Pang about 10 years
    No such method in AlertDialog.Builder, me not happy.
  • Jacek Kwiecień
    Jacek Kwiecień about 10 years
    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ń
    Jacek Kwiecień about 10 years
    Here I posted the complete solution: stackoverflow.com/questions/23126701/…
  • suja
    suja about 10 years
    @Pang for AlertDialog.Builder try alertBox.setCancelable(false);
  • ForceMagic
    ForceMagic almost 10 years
    @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.
  • Oubaida AlQuraan
    Oubaida AlQuraan about 9 years
    @Pang you can set the AlertDialog.Builder in Dialog reference like : Dialog dia = new AlertDialog.Builder(this) and use dia to use SetCanceledOnTouchOutside method
  • JaredBanyard
    JaredBanyard about 8 years
    This is the winning answer, the question is addressing Activities themed as Dialogs, not Dialogs.
  • gotwo
    gotwo over 4 years
    For dismiss use the true value: this.setFinishOnTouchOutside(true); This method is needed for the dialog activity but not for pure dialog.