Як відмовитись від діалогового вікна, натиснувши його поза межами діалогу?


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 - Додайте ще один прапор до властивостей Windows ,, 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;  
}  

Для отримання додаткової інформації дивіться статтю Як відмовитись від користувацького діалогового вікна на основі сенсорних точок? та Як відхилити ваше немодальне діалогове вікно, якщо торкнутися його поза межами діалогового регіону


9
Це чудово працює, за винятком того, що діяльність внизу також реагує на дотик. Чи є якийсь спосіб запобігти цьому?
howettl

Так. window.setFlags (WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL, WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL); викликає цю проблему. Я розмістив рішення нижче :)
Unknownweirdo

Чи можливо розповсюдження подій "на дотик" до нижньої діяльності, використовуючи також нестандартний діалог?
jc

1
@howettl Я вирішив вашу проблему в своєму рішенні, яке я розмістив нижче, де мені не потрібно встановлювати жодні прапори на вікно.
Роман Назаревич

@MuhammedRefaat - перегляньте цю тему groups.google.com/forum/#!topic/android-developers/VhaiIMl6E_w . Вони чудово описали це.
user370305

18

Просто використовуйте

dialog.setCanceledOnTouchOutside(true);

Я знаю, що це повинна відповідь правильна, але не працює для мене, і я просто не знаю, чому.
IgniteCoders

16

Ви можете використовувати цю реалізацію onTouchEvent. Це заважає реагувати під активністю на подій на дотик (як згадувалося Howettl).

@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>

Це не працює для мене на Wi-Fi у Samsung Galaxy Tab 2. 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);
}

4

Ви можете спробувати це: -

AlterDialog alterdialog;
alertDialog.setCanceledOnTouchOutside(true);

або

alertDialog.setCancelable(true);

І якщо у вас є AlterDialog.Builderтоді, ви можете спробувати це:

alertDialogBuilder.setCancelable(true);

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

Ще одне рішення, цей код був узятий із вихідного коду андроїда. 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));
}

У цього рішення немає цієї проблеми:

Це чудово працює, за винятком того, що діяльність внизу також реагує на дотик. Чи є якийсь спосіб запобігти цьому? - howettl


Не можете зробити ваш діалоговий дотик модальним, якщо ви не хочете, щоб інші вікна отримували події?

1

Телефонуйте dialog.setCancelable(false);зі своєї діяльності / фрагменту.



0

Ви можете зробити , backgroundщо займає весь розмір екрану transparentі слухати onClickподії до dismissнього.


10
Дуже погана відповідь! Звичайно, це можна зробити, але будь ласка, зробіть це правильно!
jc

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

Спробуйте це. ви можете приховати клавіатуру, коли торкаєтесь зовні

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.