PopupWindow - закрыть при нажатии снаружи

У меня есть PopupWindow в моей деятельности, дело в том, что мое PopupWindow все еще отображается, даже когда я взаимодействую со своей активностью (скажем, прокручиваю свой список). Я могу прокручивать свой список, но PopupWindow все еще там.

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

Я пробовал setOutsideTouchable(true), но окно не закрывается. Спасибо.


person villager    schedule 02.09.2012    source источник


Ответы (15)


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

person Marcin S.    schedule 02.09.2012
comment
но это не диалог, а PopupWindow - person villager; 02.09.2012
comment
Я пропустил это. Используете ли вы setBackgroundDrawable в своем popupWindow? Я знаю, что установка фонового рисунка на ноль убивает OnTouchListener - person Marcin S.; 02.09.2012
comment
Ты получил это. Настройка backgroundDrawable работает. Возможно, вы захотите отредактировать свой ответ, чтобы я мог пометить его как принятый. :) Спасибо приятель. - person villager; 02.09.2012
comment
Это оно! Спасибо, мужик! в этом случае даже события касания могут быть обработаны должным образом. popupWindow.setOutsideTouchable(true); popupWindow.setTouchable (истина); popupWindow.setBackgroundDrawable (новый BitmapDrawable()); popupWindow.setTouchInterceptor(new OnTouchListener() { @Override public boolean onTouch(View v, событие MotionEvent) { if (AppContext.isDebugMode()) Log.d(POPUP_WINDOW, v: +v.getTag() + | событие: +event .getAction()); popupWindow.dismiss(); вернуть true; } }); - person beerstorm; 05.02.2013
comment
Установка фонового рисунка на ноль у меня не работает. Если у кого-то еще есть проблемы, смотрите мой ответ. - person mpellegr; 31.07.2013
comment
Получение Попытка завершить событие ввода, но приемник события ввода уже удален. Любое исправление? - person Georgian Benetatos; 23.09.2014
comment
@WareNinja, твой комментарий сработал! Может быть, вам лучше оставить полный ответ на этот вопрос, это будет полезно для других - person Anton Kizema; 03.03.2015
comment
@WareNinja BitmapDrawable() устарела. Вместо этого используйте ColorDrawable(). - person Srujan Barai; 18.11.2015
comment
@guleryuz, его всплывающее окно закрыто, но также отображается вид сбоку ... Как предотвратить нажатие на внешний вид во время закрытия всплывающего окна.??? - person AndyBoy; 02.08.2016
comment
Все это не работает для меня. Я установил фон, я установил все осязаемые и фокусируемые. Он все еще там - person Dr. aNdRO; 21.06.2017

Я обнаружил, что ни один из предоставленных ответов не сработал для меня, кроме комментария WareNinja к принятому ответу, и, вероятно, также сработает комментарий Марцина С.. Вот часть, которая работает для меня:

myPopupWindow.setBackgroundDrawable(new BitmapDrawable());
myPopupWindow.setOutsideTouchable(true);

В качестве альтернативы:

myPopupWindow.setFocusable(true);

Не уверен, в чем разница, но исходный код ListPopupWindow на самом деле использует последний, когда для его модальности установлено значение true с помощью setModal, поэтому, по крайней мере, разработчики Android считают этот подход жизнеспособным, и это только одна строка.

person mpellegr    schedule 31.07.2013
comment
Большое спасибо. Ни один из других ответов не работал у меня и не объяснял это достаточно хорошо. Хотя второй вариант мне не подходит. - person JDN; 17.08.2013
comment
Также я отмечаю, что BitmapDrawable устарел. Было бы неплохо иметь реальное решение проблемы, поскольку они выглядят как временный обходной путь, поддержка которого в более новых версиях API не гарантируется. - person HAL9000; 09.12.2013
comment
чтобы не использовать устаревший конструктор BitmapDrawable, см. здесь: stackoverflow.com/a/21680637/2048266. popupWindow.setBackgroundDrawable (новый BitmapDrawable (getResources (), )); - person nommer; 19.03.2014
comment
При использовании альтернативного метода setFocusable нам нужно дважды нажать кнопку (где кнопка находится за пределами всплывающего окна), где, как и в 1-м методе, все работает нормально :) - person Joy Rex; 21.07.2015
comment
BitmapDrawable() устарел. Вместо этого используйте ColorDrawable(). - person Srujan Barai; 18.11.2015
comment
Обязательно добавьте этот код, прежде чем показывать всплывающее окно. - person snersesyan; 14.12.2017

Я столкнулся с теми же проблемами и исправил их, как показано ниже. Он отлично работает для меня.

    // Closes the popup window when touch outside.
    mPopupWindow.setOutsideTouchable(true);
    mPopupWindow.setFocusable(true);
    // Removes default background.
    mPopupWindow.setBackgroundDrawable(new ColorDrawable(Color.TRANSPARENT));

Кстати, не используйте устаревший конструктор BitmapDrawable, используйте этот новый ColorDrawable(android.R.color.transparent) для замены фона по умолчанию.

Развлекайся@.@

person Luna Kong    schedule 03.06.2015
comment
Обязательно добавьте этот код, прежде чем показывать всплывающее окно. - person snersesyan; 14.12.2017
comment
Мне действительно нужно установить для фокуса значение true, если всплывающее окно не нуждается в фокусе? - person Levor; 23.03.2018
comment
Я поражен, что это работает, но это требуется для API 21. Это также исправило неправильную анимацию моего всплывающего окна. - person EpicPandaForce; 11.03.2020

Я знаю, что уже поздно, но я заметил, что у людей все еще есть проблема с всплывающим окном. Я решил написать полностью работающий пример, в котором вы можете закрыть всплывающее окно, коснувшись или щелкнув за его пределами, или просто коснувшись самого окна. Для этого создайте новый класс PopupWindow и скопируйте этот код:

PopupWindow.class

public class PopupWindow extends android.widget.PopupWindow
{
Context ctx;
Button btnDismiss;
TextView lblText;
View popupView;

public PopupWindow(Context context)
{
    super(context);

    ctx = context;
    popupView = LayoutInflater.from(context).inflate(R.layout.popup, null);
    setContentView(popupView);

    btnDismiss = (Button)popupView.findViewById(R.id.btn_dismiss);
    lblText = (TextView)popupView.findViewById(R.id.text);

    setHeight(WindowManager.LayoutParams.WRAP_CONTENT);
    setWidth(WindowManager.LayoutParams.WRAP_CONTENT);

    // Closes the popup window when touch outside of it - when looses focus
    setOutsideTouchable(true);
    setFocusable(true);

    // Removes default black background
    setBackgroundDrawable(new BitmapDrawable());

    btnDismiss.setOnClickListener(new Button.OnClickListener(){

        @Override
        public void onClick(View v) {


         dismiss();
        }});

    // Closes the popup window when touch it
/*     this.setTouchInterceptor(new View.OnTouchListener() {

        @Override
        public boolean onTouch(View v, MotionEvent event) {

            if (event.getAction() == MotionEvent.ACTION_MOVE) {
                dismiss();
            }
            return true;
        }
    }); */   
   } // End constructor

   // Attaches the view to its parent anchor-view at position x and y
   public void show(View anchor, int x, int y)
   {
      showAtLocation(anchor, Gravity.CENTER, x, y);
   }
}

Теперь создайте макет всплывающего окна: popup.xml.

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout     
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:layout_margin="1dp"
    android:orientation="vertical"
    android:padding="10dp" >

<TextView 
    android:id="@+id/text" 
    android:layout_width="wrap_content" 
    android:layout_height="wrap_content"  
    android:gravity="center" 
    android:padding="5dp" 
    android:text="PopupWindow Example"
    android:textColor="#000000" 
    android:textSize="17sp" 
    android:textStyle="italic" />

<FrameLayout
    android:layout_width="match_parent" 
    android:layout_height="wrap_content" 
    android:layout_gravity="center_vertical">

    <Button
        android:id="@+id/btn_dismiss" 
        style="?android:attr/buttonStyleSmall" 
        android:layout_width="wrap_content" 
        android:layout_height="wrap_content" 
        android:text="Dismiss" 
        android:visibility="gone" />

    <TextView
        android:id="@+id/lbl_dismiss"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:gravity="center"
        android:text="Touch outside of this box to dismiss"
        android:textColor="#ffffff"
        android:textStyle="bold" />

</FrameLayout>      

In your main activity create an instance of the PopupWindow class:

final PopupWindow popupWindow = new PopupWindow(this);
popupWindow.show(findViewById(R.id.YOUR_MAIN_LAYOUT), 0, -250);

где YOUR_MAIN_LAYOUT — макет текущего действия, в котором всплывает окно popupWindow.

person Marcin S.    schedule 29.09.2012
comment
Спасибо - это сработало для меня. Всего одно небольшое замечание: лучше использовать другое имя, отличное от PopupWindow, для вашего пользовательского класса, возможно, назовите его MyPopupWindow вместо Popupwindow, чтобы Android не путался между вашим стандартным классом Android и вашим пользовательским классом. - person Simon; 08.08.2015
comment
@Marcin S. findViewById(R.id.YOUR_MAIN_LAYOUT) ?? Будет ли это R.layout.My_Layout - person Ankesh kumar Jaisansaria; 04.05.2016
comment
@Simon findViewById(R.id.YOUR_MAIN_LAYOUT) ?? Будет ли это R.layout.My_Layout ? - person Ankesh kumar Jaisansaria; 04.05.2016

Спасибо за ответ @LunaKong и подтверждение @HourGlass. Я не хочу дублировать комментарий, а хочу сделать его ясным и кратким.

// Closes the popup window when touch outside. This method was written informatively in Google's docs.
mPopupWindow.setOutsideTouchable(true);

// Set focus true to prevent a touch event to go to a below view (main layout), which works like a dialog with 'cancel' property => Try it! And you will know what I mean.
mPopupWindow.setFocusable(true);

// Removes default background.
mPopupWindow.setBackgroundDrawable(new ColorDrawable(Color.TRANSPARENT));

Мттдат.

person Nguyen Tan Dat    schedule 14.11.2017
comment
Я хотел иметь возможность закрыть всплывающее окно, щелкнув за его пределами, но когда я это сделал, щелкались представления под ним (не часть всплывающего окна, а часть действия). setFocusabl(true) был тем, что я искал. Спасибо! - person hellaandrew; 16.08.2018
comment
@hellaandrew, рад, что помог тебе, :) - person Nguyen Tan Dat; 16.08.2018

Для ListPopupWindow установите, чтобы окно было модальным при отображении.

mListPopupWindow.setModal(true);

Таким образом, щелчок за пределами ListPopupWindow закроет его.

person toobsco42    schedule 05.08.2014
comment
Спасибо, я как раз искал это. Это не только позволяет закрыть listpopupwindow после касания за пределами представления, но также не передает событие касания другим представлениям, которые находятся рядом с listpopwindow. Я отчаянно искал это, так как в моем случае прикосновение к внешнему listpopwindow передавало событие в recyclerview, которое находилось под ним, помимо отклонения listpopupwindow, и выбирался элемент recyclerview, которого я не хотел. - person shankar_vl; 04.07.2019
comment
Вам также может понадобиться mListPopupWindow.setInputMethodMode(PopupWindow.INPUT_METHOD_NOT_NEEDED);, чтобы всплывающее окно не мешало работе экранной клавиатуры. - person Mr-IDE; 19.08.2019

Обратите внимание, что для отмены с помощью popupWindow.setOutsideTouchable(true) вам нужно сделать ширину и высоту wrap_content, как показано ниже:

PopupWindow popupWindow = new PopupWindow(
            G.layoutInflater.inflate(R.layout.lay_dialog_support, null, false),
            WindowManager.LayoutParams.WRAP_CONTENT,
            WindowManager.LayoutParams.WRAP_CONTENT, true);

popupWindow.setBackgroundDrawable(new ColorDrawable(Color.TRANSPARENT));
popupWindow.setOutsideTouchable(true);
popupWindow.setFocusable(true);
popupWindow.showAtLocation(view, Gravity.RIGHT, 0, 0);
person Hadi Note    schedule 06.08.2017

  popupWindow.setTouchable(true);
  popupWindow.setFocusable(true);
  popupWindow.showAtLocation(popupView, Gravity.CENTER, 0, 0);

Он будет закрывать PopupWindow при нажатии / касании экрана. Убедитесь, что вы установили focusable true перед showAtLocation.

person android    schedule 31.07.2017
comment
Пожалуйста, добавьте пояснительный текст, чтобы уточнить, как это дает точный ответ на заданный вопрос. Спасибо. - person philantrovert; 31.07.2017
comment
Спасибо! Вам нужно вызвать сеттеры перед вызовом showAtLocation(). - person droid256; 15.08.2019

Вы можете использовать isOutsideTouchable ИЛИ isFocusable, чтобы закрыть всплывающее окно при касании снаружи

popupWindow.isOutsideTouchable = true // dismiss popupwindow when touch outside

popupWindow.isFocusable = true // dismiss popupwindow when touch outside AND when press back button

Примечание

  • В настоящее время после проверки я вижу, что setBackgroundDrawable не помогает нам закрыть всплывающее окно

  • Если вы посмотрите на код отклонения в PopupWindow (PopupWindow->PopupDecorView->dispatchKeyEvent и PopupWindow->PopupDecorView->onTouchEvent). Вы увидите, что при нажатии кнопки «Назад» они закрываются на ACTION_UP, а при касании снаружи они закрываются на ACTION_UP или ACTION_OUTSIDE.

person Linh    schedule 18.07.2019

Работа с предложениями @LunaKong похожа на шарм.

Но настройка mPopupWindow.setFocusable(false) удаляет лишнее касание, необходимое для исчезновения всплывающего окна.

Например: предположим, что на экране отображается всплывающее окно, и вы собираетесь нажать кнопку. Таким образом, в этом случае (если mpopwindow.setFocusable(true)) при первом нажатии кнопки всплывающее окно будет закрыто. Но вам нужно нажать еще раз, чтобы кнопка заработала. if**(mpopwindwo.setFocusable(false)** одним нажатием кнопки закрыть всплывающее окно, а также активировать нажатие кнопки. Надеюсь, это поможет.

person HourGlass    schedule 25.09.2015
comment
Большое спасибо! я точно такой же искал - person Ganesh; 30.11.2016

Установите прозрачный фон окна:

PopupWindow.getBackground().setAlpha(0);

После этого установите свой фон в макете. Работает отлично.

person amak    schedule 17.02.2014
comment
getBackground() может быть нулевым. - person Jared Rummler; 24.03.2015

В некоторых случаях нежелательно делать всплывающее окно фокусируемым (например, вы можете не захотеть, чтобы оно перехватывало фокус из другого представления).

Альтернативный подход — использование сенсорного перехватчика:

popupWindow.setOutsideTouchable(true);
popupWindow.setTouchInterceptor(new View.OnTouchListener() {
    @Override
    public boolean onTouch(View v, MotionEvent event) {
        if (event.getAction() == MotionEvent.ACTION_OUTSIDE) {
            popupWindow.dismiss();
        }
        return false;
    }
});
person dev.bmax    schedule 09.08.2017

Если это всплывающее окно является другим действием, и вы уменьшили его размер до исходного экрана и хотите включить или отключить внешнюю область, вы можете просто включить или отключить внешнюю область с помощью этого кода:

включить:

YourActivity.this.setFinishOnTouchOutside(true);

запрещать:

YourActivity.this.setFinishOnTouchOutside(false);

person Yasser Elgreatly    schedule 28.08.2020

Используйте View popupView, чтобы закрыть всплывающее окно.

`popupView.setOnClickListener(new View.OnClickListener() {
                   @Override
                   public void onClick(View view) {
                       popupWindow.dismiss();
                   }
               }); 

` Если вы используете это, вы также можете установить OnClickListener на любую кнопку внутри popupWindow.

person Prabhat Kumar Singh    schedule 20.07.2018

person    schedule
comment
Это единственное, что требуется. Я не понимаю, почему за принятый ответ так сильно проголосовали. - person sziraqui; 07.01.2019