PopupWindow - ปิดเมื่อคลิกภายนอก


95

ฉันมี PopupWindow ในกิจกรรมของฉันสิ่งนี้ก็คือ PopupWindow ของฉันยังคงแสดงแม้ว่าฉันจะโต้ตอบกับกิจกรรมของฉัน (พูดว่าเลื่อนในรายการของฉัน) ฉันสามารถเลื่อนดูรายการของฉันและ PopupWindow ยังคงอยู่ที่นั่น

สิ่งที่ฉันต้องการบรรลุคือเมื่อฉันสัมผัส / เลื่อน / คลิก / ฯลฯ บนหน้าจอซึ่งไม่ใช่ PopupWindow ฉันต้องการปิด PopupWindow เช่นเดียวกับวิธีการทำงานของเมนู หากคุณคลิกนอกเมนูเมนูจะถูกปิด

ฉันได้ลองแล้วsetOutsideTouchable(true)แต่มันจะไม่ปิดหน้าต่าง ขอบคุณ.

คำตอบ:


131

โปรดลองชุดsetBackgroundDrawableในPopupWindowที่ควรปิดหน้าต่างถ้าคุณสัมผัสนอกของมัน


5
ฉันพลาดไปแล้ว คุณใช้ setBackgroundDrawable บน popupWindow ของคุณหรือไม่? ฉันรู้ว่าการตั้งค่าพื้นหลังที่วาดได้เป็น null จะฆ่า OnTouchListener
Marcin S.

31
แค่นั้นแหละ! ขอบคุณคน! ในกรณีนี้แม้แต่เหตุการณ์การสัมผัสก็สามารถจัดการได้อย่างเหมาะสม popupWindow.setOutsideTouchable (จริง); popupWindow.setTouchable (จริง); popupWindow.setBackgroundDrawable (BitmapDrawable ใหม่ ()); popupWindow.setTouchInterceptor (OnTouchListener ใหม่ () {@Override บูลีนสาธารณะ onTouch (View v เหตุการณ์ MotionEvent) {if (AppContext.isDebugMode ()) Log.d ("POPUP_WINDOW", "v:" + v.getTag () + " | เหตุการณ์: "+ event.getAction ()); popupWindow.dismiss (); กลับจริง;}});
beerstorm

3
การตั้งค่าพื้นหลังที่ดึงได้เป็น null ไม่ได้ผลสำหรับฉัน หากใครมีปัญหาอื่นดูคำตอบของฉัน
mpellegr

2
@WareNinja ความคิดเห็นของคุณใช้งานได้! บางทีคุณควรทิ้งคำตอบทั้งหมดไว้ในคำถามนี้มันจะมีประโยชน์สำหรับคนอื่น ๆ
Anton Kizema

3
@WareNinja BitmapDrawable()หมดค่า ใช้ColorDrawable()แทน
Srujan Barai

127

ฉันพบว่าไม่มีคำตอบใดที่ให้มาสำหรับฉันยกเว้นความคิดเห็นของ WareNinja เกี่ยวกับคำตอบที่ยอมรับและของ Marcin S. ก็น่าจะได้ผลเช่นกัน นี่คือส่วนที่เหมาะกับฉัน:

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.setBackgroundDrawable (BitmapDrawable ใหม่ (getResources (), ""));
เสนอชื่อ

ในขณะที่ใช้วิธีsetFocusableอื่นเราต้องคลิกปุ่มสองครั้ง (โดยที่ปุ่มวางอยู่นอกป๊อปอัป) โดยที่วิธีที่ 1 ทำงานได้ดี :)
Joy Rex

BitmapDrawable()ถูกกีดกัน ใช้ColorDrawable()แทน
Srujan Barai

61

ฉันพบปัญหาเดียวกันและได้รับการแก้ไขตามรหัสด้านล่าง มันใช้ได้ดีสำหรับฉัน

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

BTW อย่าใช้ตัวสร้างที่เลิกใช้ BitmapDrawable ใช้ColorDrawable (android.R.color.transparent) ใหม่นี้เพื่อแทนที่พื้นหลังเริ่มต้น

มีความสุข@.@


3
อย่าลืมเพิ่มรหัสนี้ก่อนที่จะแสดง popoupWindow ของคุณ
snersesyan

ฉันจำเป็นต้องตั้งค่าที่สามารถโฟกัสได้เป็นจริงหรือไม่หากป๊อปอัปไม่ต้องการโฟกัส
Levor

ฉันประหลาดใจที่มันใช้งานได้ แต่จำเป็นต้องใช้กับ 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 เพื่อไม่ให้ Android สับสนระหว่างคลาส android มาตรฐานกับคลาสที่คุณกำหนดเอง
Simon

@Marcin S. findViewById (R.id.YOUR_MAIN_LAYOUT) ?? จะเป็น R.layout.My_Layout
Ankesh kumar Jaisansaria

@Simon findViewById (Rid.YOUR_MAIN_LAYOUT) ?? จะเป็น R.layout.My_Layout หรือไม่?
Ankesh kumar Jaisansaria

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 (true) คือสิ่งที่ฉันกำลังมองหา ขอบคุณ!
hellaandrew

@hellaandrew ดีใจที่ช่วยคุณ :)
Nguyen Tan Dat

8

สำหรับการListPopupWindowตั้งค่าหน้าต่างเป็นโมดอลเมื่อแสดง

mListPopupWindow.setModal(true);

ด้วยวิธีนี้การคลิกด้านนอกListPopupWindowจะเป็นการปิด


ขอบคุณฉันแค่มองหาสิ่งนี้ สิ่งนี้ไม่เพียง แต่ตั้งค่าให้ปิด listpopupwindow ได้หลังจากสัมผัสนอกมุมมอง แต่ยังไม่ส่งต่อเหตุการณ์การสัมผัสไปยังมุมมองอื่น ๆ ที่อยู่ข้าง listpopwindow ฉันกำลังมองหาสิ่งนี้อย่างสิ้นหวังเนื่องจากในกรณีของฉันที่สัมผัสภายนอก listpopwindow กำลังส่งเหตุการณ์ไปที่การดูรีไซเคิลซึ่งอยู่ด้านล่างข้างการปิด listpopupwindow และรายการรีไซเคิลได้รับการเลือกซึ่งฉันไม่ต้องการ
shankar_vl

คุณอาจต้องใช้mListPopupWindow.setInputMethodMode(PopupWindow.INPUT_METHOD_NOT_NEEDED);เพื่อป้องกันไม่ให้หน้าต่างป๊อปอัปรบกวนแป้นพิมพ์บนหน้าจอ
Mr-IDE

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 เมื่อคลิก / สัมผัสบนหน้าจอตรวจสอบให้แน่ใจว่าคุณได้ตั้งค่า true ที่สามารถโฟกัสได้ก่อน showAtLocation


1
โปรดเพิ่มข้อความอธิบายเพื่ออธิบายอย่างละเอียดว่าจะให้คำตอบที่ถูกต้องสำหรับคำถามที่ถามได้อย่างไร ขอบคุณ.
philantrovert

ขอบคุณ! คุณต้องโทรหา setters ก่อนที่จะเรียก 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 (จริง)) ในการคลิกปุ่มครั้งแรกหน้าต่างป๊อปอัปจะปิด แต่คุณต้องคลิกอีกครั้งเพื่อให้ปุ่มทำงาน ถ้า ** (mpopwindwo.setFocusable (false) ** การคลิกปุ่มเพียงครั้งเดียวจะเป็นการปิดหน้าต่างป๊อปอัพและเรียกการคลิกปุ่ม หวังว่าจะช่วยได้


1
ขอบคุณมาก! ฉันกำลังมองหาสิ่งเดียวกัน
Ganesh

3

ตั้งค่าพื้นหลังหน้าต่างให้โปร่งใส:

PopupWindow.getBackground().setAlpha(0);

หลังจากตั้งค่าพื้นหลังของคุณในรูปแบบ ใช้งานได้ดี


1
getBackground () อาจเป็นโมฆะ
Jared Rummler

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

1

หากหน้าต่างป๊อปอัปนี้เป็นกิจกรรมอื่นและคุณลดขนาดลงเป็นหน้าจอเดิมและคุณต้องการเปิดหรือปิดใช้งานพื้นที่ภายนอกคุณสามารถเปิดหรือปิดใช้งานพื้นที่ภายนอกได้โดยใช้รหัสนี้:

เปิดใช้งาน:

YourActivity.this.setFinishOnTouchOutside(true);

ปิดการใช้งาน:

YourActivity.this.setFinishOnTouchOutside(false);


0

ใช้ View popupView เพื่อปิด popupWindow

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

`ถ้าคุณใช้สิ่งนี้คุณยังสามารถ setOnClickListener ไปที่ปุ่มใดก็ได้ภายใน popupWindow

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.