Как закрыть диалоговое окно, нажав на кнопку вне диалогового окна?

156

Я реализовал собственный диалог для моего приложения. Я хочу реализовать это, когда пользователь щелкает за пределами диалогового окна, диалоговое окно будет закрыто. Что я должен сделать для этого?

Шреяш Махаджан
источник

Ответы:

356

Вы можете использовать, dialog.setCanceledOnTouchOutside(true);который закроет диалог, если вы нажмете за пределами диалога.

Что-то вроде,

  Dialog dialog = new Dialog(context)
  dialog.setCanceledOnTouchOutside(true);

Или если ваш диалог не в модели, то

1 - Установите флаг FLAG_NOT_TOUCH_MODALдля атрибута окна вашего диалога

Window window = this.getWindow();
window.setFlags(WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL,
WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL);

2 - Добавить еще один флаг в свойствах окон ,, FLAG_WATCH_OUTSIDE_TOUCH- этот диалог предназначен для получения события касания за пределами видимой области.

3 - Переопределить onTouchEvent()диалог и проверить тип действия. если тип действия « MotionEvent.ACTION_OUTSIDEозначает», пользователь взаимодействует за пределами области диалога. Таким образом, в этом случае вы можете изменить свой диалог или решить, что вы хотите выполнить. просмотреть открытку?

public boolean onTouchEvent(MotionEvent event)  
{  

       if(event.getAction() == MotionEvent.ACTION_OUTSIDE){  
        System.out.println("TOuch outside the dialog ******************** ");  
               this.dismiss();  
       }  
       return false;  
}  

Для получения дополнительной информации см. Как закрыть пользовательский диалог на основе точек касания? и Как отменить ваш немодальный диалог, когда его касаются за пределами области диалога

user370305
источник
9
Это прекрасно работает, за исключением того, что действие под ним также реагирует на событие касания. Есть ли способ предотвратить это?
Howettl
Да. window.setFlags (WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL, WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL); вызывает эту проблему. Я разместил решение ниже :)
Unknownweirdo
Можно ли распространять события «на ощупь-снаружи» на нижележащую активность, используя также нестандартный диалог?
х
1
@howettl Я решил вашу проблему в своем решении, которое я разместил ниже, где мне не нужно устанавливать какие-либо флаги для окна.
Роман Назаревич
@MuhammedRefaat. Посмотрите эту ветку groups.google.com/forum/#!topic/android-developers/VhaiIMl6E_w . Они хорошо описали это.
user370305
18

Просто используйте

dialog.setCanceledOnTouchOutside(true);
Эбин Себастьян
источник
Я знаю, что это правильный ответ, но для меня это не работает, и я просто не знаю почему.
IgniteCoders
16

Вы можете использовать эту реализацию onTouchEvent. Это предотвращает реакцию под действием на событие касания (как упомянуто как).

@Override
public boolean onTouchEvent ( MotionEvent event ) {
  // I only care if the event is an UP action
  if ( event.getAction () == MotionEvent.ACTION_UP ) {
    // create a rect for storing the window rect
    Rect r = new Rect ( 0, 0, 0, 0 );
    // retrieve the windows rect
    this.getWindow ().getDecorView ().getHitRect ( r );
    // check if the event position is inside the window rect
    boolean intersects = r.contains ( (int) event.getX (), (int) event.getY () );
    // if the event is not inside then we can close the activity
    if ( !intersects ) {
      // close the activity
      this.finish ();
      // notify that we consumed this event
      return true;
    }
  }
  // let the system handle the event
  return super.onTouchEvent ( event );
}

Источник: http://blog.twimager.com/2010/08/closing-activity-by-touching-outside.html

Лукас Новак
источник
9

Или, если вы настраиваете диалог, используя тему, определенную в вашем стиле xml, поместите эту строку в вашу тему:

<item name="android:windowCloseOnTouchOutside">true</item>
Chris.Zou
источник
Это не работает для меня на Samsung Galaxy Tab 2 WiFi. dialog.setCanceledOnTouchOutside(true);работает чудесно.
Доплуми
7
dialog.setCanceledOnTouchOutside(true); 

закрыть диалог на ощупь снаружи.

И если вы не хотите закрывать на ощупь снаружи, используйте код ниже:

dialog.setCanceledOnTouchOutside(false);
Нэвин
источник
6

Этот метод должен полностью избегать действий ниже серой области, извлекающих события щелчка.

Удалите эту строку, если она у вас есть:

window.setFlags(WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL, WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL);

Поместите это в свою деятельность, созданную

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

затем переопределить событие касания с этим

@Override
public boolean onTouchEvent(MotionEvent ev)
{
    if(MotionEvent.ACTION_DOWN == ev.getAction())
    {
        Rect dialogBounds = new Rect();
        getWindow().getDecorView().getHitRect(dialogBounds);
        if (!dialogBounds.contains((int) ev.getX(), (int) ev.getY())) {
            // You have clicked the grey area
            displayYourDialog();
            return false; // stop activity closing
        }
    }

    // Touch events inside are fine.
    return super.onTouchEvent(ev);
}
Unknownweirdo
источник
4

Вы можете попробовать это: -

AlterDialog alterdialog;
alertDialog.setCanceledOnTouchOutside(true);

или

alertDialog.setCancelable(true);

И если у вас есть, то AlterDialog.Builderвы можете попробовать это: -

alertDialogBuilder.setCancelable(true);
Julfikar
источник
4

Этот код используется для того, чтобы при щелчке по диалоговому окну использовать время скрытия входа в систему, а когда пользователь щелкает по внешней стороне диалогового окна, когда время ввода и вывода софта близко.

dialog = new Dialog(act) {
    @Override
    public boolean onTouchEvent(MotionEvent event) {
        // Tap anywhere to close dialog.
        Rect dialogBounds = new Rect();
        getWindow().getDecorView().getHitRect(dialogBounds);
        if (!dialogBounds.contains((int) event.getX(),
                (int) event.getY())) {
            // You have clicked the grey area
            InputMethodManager inputMethodManager = (InputMethodManager) act
                    .getSystemService(act.INPUT_METHOD_SERVICE);
            inputMethodManager.hideSoftInputFromWindow(dialog
                    .getCurrentFocus().getWindowToken(), 0);
            dialog.dismiss();
            // stop activity closing
        } else {
            InputMethodManager inputMethodManager = (InputMethodManager) act
                    .getSystemService(act.INPUT_METHOD_SERVICE);
            inputMethodManager.hideSoftInputFromWindow(dialog
                    .getCurrentFocus().getWindowToken(), 0);
        }

        return true;
    }
};
Маулик Сантоки
источник
2

Другое решение, этот код был взят из исходного кода Android. Window Вам просто нужно добавить эти два метода в исходный код вашего диалога.

@Override
public boolean onTouchEvent(MotionEvent event) {        
    if (isShowing() && (event.getAction() == MotionEvent.ACTION_DOWN
            && isOutOfBounds(getContext(), event) && getWindow().peekDecorView() != null)) {
        hide();
    }
    return false;
}

private boolean isOutOfBounds(Context context, MotionEvent event) {
    final int x = (int) event.getX();
    final int y = (int) event.getY();
    final int slop = ViewConfiguration.get(context).getScaledWindowTouchSlop();
    final View decorView = getWindow().getDecorView();
    return (x < -slop) || (y < -slop)
            || (x > (decorView.getWidth()+slop))
            || (y > (decorView.getHeight()+slop));
}

Это решение не имеет этой проблемы:

Это прекрасно работает, за исключением того, что действие под ним также реагирует на событие касания. Есть ли способ предотвратить это? - как

Роман Назаревич
источник
Можете ли вы просто сделать ваш диалог модальным, если вы не хотите, чтобы другие окна получали события?
1

Звоните dialog.setCancelable(false);из вашей деятельности / фрагмент.

EKN
источник
1

Следующее сработало для меня:

myDialog.setCanceledOnTouchOutside(true);
Аканши Шривастава
источник
0

Вы можете backgroundзанять все размеры экрана transparentи прослушать onClickсобытие на dismissнем.

oriolpons
источник
10
Очень плохой ответ! Конечно, это можно сделать, но, пожалуйста, сделайте это правильно!
х
-1

Вот код

    dialog.getWindow().getDecorView().setOnTouchListener(new View.OnTouchListener() {
        @Override
        public boolean onTouch(View v, MotionEvent ev) {

            if(MotionEvent.ACTION_DOWN == ev.getAction())
            {
                Rect dialogBounds = new Rect();
                dialog. getWindow().getDecorView().getHitRect(dialogBounds);
                if (!dialogBounds.contains((int) ev.getX(), (int) ev.getY())) {
                    // You have clicked the grey area
                    UiUtils.hideKeyboard2(getActivity());
                    return false; // stop activity closing
                }
            }
            getActivity().dispatchTouchEvent(ev);
            return false;
        }
    });

Попробуй это . Вы можете скрыть клавиатуру, когда вы касаетесь снаружи

Saljith Kj
источник