PopupWindow - Відхиляє, натиснувши назовні


93

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

Я хочу досягти, коли я торкаюся / прокручую / клацаю / тощо на екрані, який не є PopupWindow, я хочу відхилити PopupWindow. Так само, як працює меню. Якщо ви натиснули поза меню, меню буде відхилено.

Я спробував, setOutsideTouchable(true)але це не відхилить вікно. Дякую.

Відповіді:


129

Будь ласка , спробуйте встановити setBackgroundDrawableна PopupWindowтому , що слід закрити вікно , якщо ви торкаєтеся за його межами.


5
Я це пропустив. Чи використовуєте ви setBackgroundDravable у своєму спливаючому вікні? Я знаю, що встановлення тла, який можна перетворити на нуль, вбиває OnTouchListener
Marcin S.

31
Це воно! thnx людина! у цьому випадку навіть подій із дотиком можна обробляти належним чином. popupWindow.setOutsideTouchable (вірно); popupWindow.setTouchable (вірно); popupWindow.setBackgroundDravable (новий BitmapDravable ()); popupWindow.setTouchInterceptor (новий OnTouchListener () {@Override public boolean onTouch (View v, подія MotionEvent) {if (AppContext.isDebugMode ()) Log.d ("POPUP_WINDOW", "v:" + v.getTag () + | подія: "+ event.getAction ()); popupWindow.dismiss (); return true;}});
пивна буря

3
Налаштування фонового режиму, який можна перетягнути на null, не працює для мене. Якщо хтось має проблеми, дивіться мою відповідь.
mpellegr

2
@WareNinja, ваш коментар спрацював! Можливо, вам краще залишити цілий ансвейр на це питання, це було б корисно для інших
Антон Кізема

3
@WareNinja BitmapDrawable()вилучено. Використовуйте ColorDrawable()замість цього.
Srujan Barai

125

Я виявив, що жодна із наданих відповідей не працювала для мене, крім коментаря WareNinja до прийнятої відповіді, і, ймовірно, також буде працювати Марцін С. Ось частина, яка працює для мене:

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

Як варіант:

myPopupWindow.setFocusable(true);

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


6
Дуже дякую. Жодна з інших відповідей не працювала для мене або недостатньо добре пояснювала це. Другий варіант не працює для мене.
JDN

2
Також зауважу, що BitmapDrawable є застарілим. Було б непогано реально вирішити проблему, оскільки вони виглядають як тимчасове вирішення, яке не гарантовано підтримується в нових версіях API.
HAL9000

щоб не використовувати застарілий конструктор BitmapDrawable, зверніться сюди: stackoverflow.com/a/21680637/2048266 . popupWindow.setBackgroundDravable (новий BitmapDravable (getResources (), ""));
номер

Під час використання альтернативного методу setFocusableнам потрібно двічі натиснути кнопку (де кнопка розміщена поза спливаючого вікна), де, як і в 1-му методі, вона працює добре :)
Joy Rex,

BitmapDrawable()знецінено Використовуйте ColorDrawable()замість цього.
Srujan Barai

59

Я зустрічався з тими ж проблемами і виправляв це, як наведено нижче. Це прекрасно працює для мене.

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

BTW, Не використовуйте застарілий конструктор BitmapDrawable, використовуйте цей новий ColorDravable (android.R.color.transparent) для заміни фону за замовчуванням.

Веселіться @. @


3
Не забудьте додати цей код, перш ніж показувати своє popoupWindow
snersesyan

Мені справді потрібно встановити фокусируемость на true, якщо спливаюче вікно не потребує фокусу?
Левор

Я вражений тим, що це працює, але це потрібно в API 21. Це також встановило, що моє спливаюче вікно анімувало неправильно.
EpicPandaForce

24

Я знаю, що пізно, але помічаю, що люди все ще мають проблеми із спливаючим вікном. Я вирішив написати повністю працюючий приклад, коли ви можете відхилити спливаюче вікно, торкнувшись або клацнувши поза ним, або просто торкнувшись самого вікна. Для цього створіть новий клас 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>      

У своїй основній діяльності створіть екземпляр класу PopupWindow:

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

де YOUR_MAIN_LAYOUT - це макет поточної активності, в якому popupWindow з'явиться


1
Спасибі - це працювало для мене. Лише одна невелика примітка - скоріше використовувати інше ім’я, крім PopupWindow, для свого користувацького класу, можливо, назвіть його MyPopupWindow замість Popupwindow, щоб андроїд не плутався між вашим стандартним андроїд-класом та вашим власним класом.
Саймон

@Marcin S. findViewById (R.id.YOUR_MAIN_LAYOUT) ?? Буде це R.layout.My_Layout
Анкеш кумар Jaisansaria

@Simon findViewById (R.id.YOUR_MAIN_LAYOUT) ?? Це буде R.layout.My_Layout?
Анкеш кумар Джайсансарія

15

Дякуємо за відповідь @ 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));

Mttdat.


Я хотів мати можливість закрити спливаюче вікно, клацнувши поза ним, але коли я це зробив, під ним клацали погляди (не частина спливаючого вікна, а частина діяльності). setFocusabl (правда) - це те, що я шукав. Дякую!
hellaandrew

@hellaandrew, радий, що тобі допомагає :)
Nguyen Tan Dat

8

Для ListPopupWindowвстановлення вікна, щоб бути модальним, коли воно відображається.

mListPopupWindow.setModal(true);

Таким чином, клацання поза межами ListPopupWindowзаповіту відхилить його.


Дякую, я просто доглядав за цим. Це не лише встановлює listpopupwwindow, яке може бути відхилене після дотику поза вікном перегляду, але також не передає сенсорну подію іншим видам, які знаходяться поруч з вікном listpopww. Я відчайдушно шукав цього, оскільки в моєму випадку торкаючись зовнішньої listpopwindow передав подію reciklierview, який знаходився під ним поруч із відхиленням listpopupwindow, і пункт recilerview вибирався, чого я не хотів.
shankar_vl

Також вам може знадобитися mListPopupWindow.setInputMethodMode(PopupWindow.INPUT_METHOD_NOT_NEEDED);, щоб уникнути спливаюче вікно не впливати на екранну клавіатуру.
Містер-ІДЕ

6

Зауважте, що для скасування з 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);

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

Він відхилить PopupWindow при натисканні / натисканні на екрані. Переконайтеся, що ви встановили фокусируемую правду перед showAtLocation.


1
Будь ласка, додайте пояснювальний текст, щоб пояснити, як це дає точну відповідь на поставлене запитання. Дякую.
philantrovert

Дякую! Перед тим, як викликати showAtLocation (), потрібно зателефонувати сетерам.
droid256

5

Ви можете використовувати 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


4

Пропозиція @LunaKong працює як шарм.

Але налаштування mPopupWindow.setFocusable (false). видаляє зайвий дотик, необхідний для зникнення спливаючого вікна.

Наприклад: Давайте розглянемо, що на екрані видно спливаюче вікно, і ви збираєтесь натиснути кнопку. Так що в цьому випадку (якщо mpopwindow.setFocusable (true)) при першому натисканні кнопки popupwindow відкине. Але вам доведеться натиснути ще раз, щоб кнопка працювала. якщо ** (mpopwindwo.setFocusable (false) ** одним натисканням кнопки відхиляє спливаюче вікно, а також запускає натискання кнопки. Сподіваюся, це допоможе.


1
Велике спасибі! Я саме шукав те саме
Ганеш


3

Встановіть фон вікна прозорим:

PopupWindow.getBackground().setAlpha(0);

Після цього встановіть ваш фон у макеті. Добре працює.


1
getBackground () може бути нульовим.
Джаред Румлер

1

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

Альтернативний підхід - це використання сенсорного перехоплювача:

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

0

Використовуйте View popupView, щоб вимкнути popupWindow

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

`Якщо ви користуєтесь цим, ви також можете встановитиOnClickListener на будь-яку кнопку всередині popupWindow

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