usernotnull
usernotnull

Reputation: 3628

Intercepting touches outside dialog BEFORE dismissal

I have a DialogFragment which has an animation on start, and I'm trying to do an animation on close.

I first started by adding a "back" key listener, but my dialog has the setCanceledOnTouchOutside(true). So I would also like to add the transition on touching outside the dialog fragment as well.

All methods I tried (AFAIK) are called AFTER the dialog is automatically dismissed on pressing outside. Is there a way to intercept before the dialog goes out of view?

EDIT: this question is still not answered as the proposed solution doesn't work

Upvotes: 1

Views: 323

Answers (2)

Oliver Jonas
Oliver Jonas

Reputation: 1258

Here's a method that intercepts both touches outside of the dialog and the Back key. I used it for validation but you can replace the isValid() by a function to start the animation and then dismiss the dialog.

    fun isValid() = // TODO
    
    // Validate when pressing Back
    dialog.setOnKeyListener { _, keyCode, keyEvent -> // getAction to make sure this doesn't double fire
        if (keyCode == KeyEvent.KEYCODE_BACK && keyEvent.action == KeyEvent.ACTION_UP) {
            !isValid()
        } else false
    }

    // Validate when touching outside to dismiss the dialog
    dialog.window?.let {
        it.callback = object : WindowCallbackWrapper(it.callback) {

            override fun dispatchTouchEvent(event: MotionEvent): Boolean {
                if (isOutOfBounds(event)) {
                    if (!isValid()) {
                        return true
                    }
                }
                return super.dispatchTouchEvent(event)
            }

            private fun isOutOfBounds(event: MotionEvent): Boolean {
                return if (event.action == MotionEvent.ACTION_OUTSIDE) {
                    true
                } else {
                    if (event.action == MotionEvent.ACTION_DOWN) {
                        val x = event.x.toInt()
                        val y = event.y.toInt()
                        val slop = ViewConfiguration.get(context).scaledWindowTouchSlop
                        val decorView: View = it.decorView
                        (x < -slop || y < -slop || x > decorView.width + slop || y > decorView.height + slop)
                    } else {
                        false
                    }
                }
            }
        }
    }

Upvotes: 0

Anshuman Borah
Anshuman Borah

Reputation: 538

When dialog.setCanceledOnTouchOutside(true); then you just override onCancel() like this:

dialog.setOnCancelListener(
new DialogInterface.OnCancelListener() {
            @Override
            public void onCancel(DialogInterface dialog) {
                //When you touch outside of dialog bounds, 
                //the dialog gets canceled and this method executes.
            }
        }
);

Upvotes: 2

Related Questions