Tap outside Android dialog to dismiss it?

北战南征 提交于 2019-11-28 03:56:40

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);
}
dialog.setCanceledOnTouchOutside(true) 

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

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>

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

You may use

  dialog.setCancelable(true\false); 

For the lastest vesrions of Android;

It will disable outSideTouching event.

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

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

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.

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.

this.setFinishOnTouchOutside(false);

you can use this

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.

jungwhan cho

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;
        }
    });
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!