PopupWindow - Loại bỏ khi nhấp vào bên ngoài


93

Tôi có một PopupWindow về hoạt động của mình, vấn đề là PopupWindow của tôi vẫn hiển thị ngay cả khi tôi đang tương tác với hoạt động của mình (giả sử như cuộn trên danh sách của tôi). Tôi có thể cuộn qua danh sách của mình và PopupWindow vẫn ở đó.

Những gì tôi muốn đạt được là khi tôi chạm / cuộn / nhấp vào / vv trên màn hình không phải là PopupWindow, tôi muốn loại bỏ PopupWindow. Cũng giống như cách một menu hoạt động. Nếu bạn nhấp vào bên ngoài menu, menu sẽ bị loại bỏ.

Tôi đã thử setOutsideTouchable(true)nhưng nó sẽ không loại bỏ cửa sổ. Cảm ơn.

Câu trả lời:


129

Vui lòng cố gắng đặt setBackgroundDrawabletrên PopupWindowđó sẽ đóng cửa sổ nếu bạn chạm vào bên ngoài của nó.


5
Tôi đã bỏ lỡ nó. Bạn có đang sử dụng setBackgroundDrawable trên cửa sổ bật lênWindow của mình không? Tôi biết rằng thiết lập drawable nền để null giết OnTouchListener
Marcin S.

31
đó là nó! người đàn ông thnx! trong trường hợp này, ngay cả các sự kiện chạm cũng có thể được xử lý đúng cách. popupWindow.setOutsideTouchable (true); popupWindow.setTouchable (true); popupWindow.setBackgroundDrawable (BitmapDrawable ()) mới; popupWindow.setTouchInterceptor (new OnTouchListener () {@Override public boolean onTouch (View v, sự kiện MotionEvent) {if (AppContext.isDebugMode ()) Log.d ("POPUP_WINDOW", "v:" + v.getTag () + " | event: "+ event.getAction ()); popupWindow.dismiss (); return true;}});
beerstorm

3
Đặt nền có thể vẽ thành null không phù hợp với tôi. Nếu bất kỳ ai khác có vấn đề, hãy xem câu trả lời của tôi.
mpellegr,

2
@WareNinja, bình luận của bạn đã thành công! Có lẽ tốt hơn bạn nên để lại toàn bộ mạng lưới cho quesiton này, nó sẽ hữu ích cho những người khác
Anton Kizema

3
@WareNinja thật đáng buồn BitmapDrawable(). Sử dụng ColorDrawable()thay thế.
Srujan Barai

125

Tôi thấy rằng không có câu trả lời nào được cung cấp phù hợp với tôi, ngoại trừ nhận xét của WareNinja về câu trả lời được chấp nhận và Marcin S.'s có lẽ cũng sẽ hoạt động. Đây là phần phù hợp với tôi:

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

Ngoài ra:

myPopupWindow.setFocusable(true);

Không chắc sự khác biệt là gì, nhưng mã nguồn ListPopupWindow thực sự sử dụng mã sau khi chế độ của nó được đặt thành true với setModal, vì vậy ít nhất các nhà phát triển Android coi đây là một cách tiếp cận khả thi và nó chỉ có một dòng.


6
Cảm ơn bạn rất nhiều. Không có câu trả lời nào khác phù hợp với tôi hoặc giải thích nó đủ tốt. Tùy chọn thứ hai không hoạt động với tôi.
JDN

2
Ngoài ra, tôi lưu ý rằng BitmapDrawable không được dùng nữa. Sẽ rất tuyệt nếu có một giải pháp thực sự cho vấn đề, vì những giải pháp này trông giống như cách giải quyết tạm thời không được đảm bảo sẽ được hỗ trợ trong các phiên bản API mới hơn.
HAL9000

để không sử dụng hàm tạo không được chấp nhận BitmapDrawable, hãy tham khảo tại đây: stackoverflow.com/a/21680637/2048266 . popupWindow.setBackgroundDrawable (BitmapDrawable mới (getResources (), ""));
tối

Trong khi sử dụng phương pháp thay thế setFocusable, chúng ta cần phải nhấp vào nút hai lần (trong đó nút được đặt bên ngoài cửa sổ pop-up) nơi như trong phương pháp 1st nó hoạt động tốt :)
Joy Rex

BitmapDrawable()bị suy nhược. Sử dụng ColorDrawable()thay thế.
Srujan Barai

59

Tôi đã gặp các vấn đề tương tự và đã khắc phục nó như các mã bên dưới. Việc này ổn với tôi.

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

BTW, Không sử dụng hàm tạo không được chấp nhận BitmapDrawable, hãy sử dụng ColorDrawable mới này (android.R.color.transparent) để thay thế nền mặc định.

Chúc vui vẻ@.@


3
Hãy chắc chắn để thêm mã này trước khi hiển thị popoupWindow của bạn
snersesyan

Tôi có thực sự cần đặt có thể lấy tiêu điểm thành true nếu cửa sổ bật lên không cần tiêu điểm không?
Levor

Tôi rất ngạc nhiên rằng điều này hoạt động, nhưng nó được yêu cầu trên API 21. Điều này cũng đã khắc phục rằng cửa sổ bật lên của tôi hoạt động không chính xác.
EpicPandaForce

24

Tôi biết là đã muộn nhưng tôi nhận thấy rằng mọi người vẫn gặp sự cố với cửa sổ bật lên. Tôi đã quyết định viết một ví dụ hoạt động đầy đủ, nơi bạn có thể loại bỏ cửa sổ bật lên bằng cách chạm hoặc nhấp vào bên ngoài nó hoặc chỉ chạm vào chính cửa sổ. Để làm như vậy, hãy tạo một lớp PopupWindow mới và sao chép mã này:

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

Bây giờ tạo bố cục cho cửa sổ bật lên: 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>      

Trong hoạt động chính của bạn, hãy tạo một phiên bản của lớp PopupWindow:

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

trong đó YOUR_MAIN_LAYOUT là bố cục của hoạt động hiện tại, trong đó popupWindow sẽ bật lên


1
Cảm ơn - điều này đã làm việc cho tôi. Chỉ có một lưu ý nhỏ là bạn nên sử dụng một tên khác không phải là PopupWindow cho lớp tùy chỉnh của mình, có thể gọi nó là MyPopupWindow thay vì Popupwindow để android không bị nhầm lẫn giữa lớp android tiêu chuẩn và lớp tùy chỉnh của bạn.
Simon

@Marcin S. findViewById (R.id.YOUR_MAIN_LAYOUT) ?? Đó sẽ là R.layout.My_Layout
Ankesh kumar Jaisansaria

@Simon findViewById (R.id.YOUR_MAIN_LAYOUT) ?? Nó sẽ là R.layout.My_Layout?
Ankesh kumar Jaisansaria

15

Cảm ơn câu trả lời của @ LunaKong và xác nhận của @ HourGlass. Tôi không muốn nhận xét trùng lặp mà chỉ muốn làm cho nó rõ ràng và ngắn gọn.

// 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.


Tôi muốn có thể đóng cửa sổ bật lên bằng cách nhấp vào bên ngoài nó, nhưng khi tôi làm vậy, các chế độ xem bên dưới nó (không phải một phần của cửa sổ bật lên mà là một phần của hoạt động) đang được nhấp. setFocusabl (true) là những gì tôi đang tìm kiếm. Cảm ơn!
hellaandrew

@hellaandrew, vui mừng nó giúp bạn, :)
Nguyễn Tấn Đạt

8

Đối với một ListPopupWindowthiết lập cửa sổ thành một phương thức khi hiển thị.

mListPopupWindow.setModal(true);

Bằng cách đó, nhấp vào bên ngoài ListPopupWindowsẽ loại bỏ nó.


Cảm ơn, tôi chỉ đang tìm kiếm điều này. Điều này không chỉ đặt listpopupwindow có thể loại bỏ sau khi chạm vào bên ngoài dạng xem, mà còn không chuyển sự kiện chạm sang dạng xem khác bên cạnh listpopwindow. Tôi đang rất cố gắng tìm kiếm điều này vì trong trường hợp của tôi chạm vào listpopwindow bên ngoài đang chuyển sự kiện đến recallerview nằm bên dưới nó bên cạnh việc loại bỏ listpopupwindow và mục Recyclerview đang được chọn mà tôi không muốn.
shankar_vl

Bạn cũng có thể cần mListPopupWindow.setInputMethodMode(PopupWindow.INPUT_METHOD_NOT_NEEDED);, để ngăn cửa sổ bật lên can thiệp vào bàn phím trên màn hình.
Mr-IDE

6

Lưu ý rằng để hủy với popupWindow.setOutsideTouchable(true), bạn cần tạo chiều rộng và chiều cao wrap_contentnhư mã dưới đây:

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

Nó sẽ loại bỏ PopupWindow khi nhấp / chạm vào màn hình. Hãy đảm bảo rằng bạn đã đặt tiêu điểm true trước showAtLocation.


1
Vui lòng thêm một số văn bản giải thích để làm rõ cách này cung cấp câu trả lời chính xác cho câu hỏi được hỏi. Cảm ơn.
thiện

Cảm ơn! Bạn cần gọi bộ cài đặt trước khi gọi showAtLocation ().
droid256,

5

Bạn có thể sử dụng isOutsideTouchable HOẶC isFocusable để loại bỏ cửa sổ bật lên khi chạm vào bên ngoài

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

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

Ghi chú

  • Hiện tại, sau khi kiểm tra, tôi thấy setBackgroundDrawable không giúp chúng tôi loại bỏ cửa sổ bật lên

  • Nếu bạn nhìn vào mã loại bỏ trong PopupWindow( PopupWindow->PopupDecorView->dispatchKeyEventPopupWindow->PopupDecorView->onTouchEvent). Bạn sẽ thấy rằng khi nhấn nút quay lại, họ sẽ loại bỏ ACTION_UPvà khi chạm vào bên ngoài, họ loại bỏ ACTION_UPhoặcACTION_OUTSIDE


4

@LunaKong gợi ý công việc giống như một sự quyến rũ.

Nhưng thiết lập mPopupWindow.setFocusable (sai). loại bỏ các thao tác chạm không cần thiết để làm cho cửa sổ bật lên biến mất.

Ví dụ: Hãy xem xét có một cửa sổ bật lên hiển thị trên màn hình và bạn sắp nhấp vào một nút. Vì vậy, trong trường hợp này, (nếu mpopwindow.setFocusable (true)) trong lần nhấp đầu tiên vào nút, cửa sổ bật lên sẽ loại bỏ. Nhưng bạn phải nhấp lại để nút hoạt động. if ** (mpopwindwo.setFocusable (false) ** một cú nhấp chuột vào nút sẽ loại bỏ cửa sổ bật lên cũng như kích hoạt nhấp vào nút. Hy vọng nó sẽ hữu ích.


1
Cảm ơn nhiều! Tôi chính xác đang tìm kiếm điều tương tự
Ganesh

3
mPopWindow.setFocusable(true);

Đây là điều duy nhất được yêu cầu. Tôi không hiểu tại sao câu trả lời được chấp nhận lại được ủng hộ rất nhiều.
sziraqui

3

Đặt nền cửa sổ trong suốt:

PopupWindow.getBackground().setAlpha(0);

Sau khi thiết lập nền của bạn trong bố cục. Hoạt động tốt.


1
getBackground () có thể là null.
Jared Rummler

1

Trong một số trường hợp, việc làm cho cửa sổ bật lên có thể lấy tiêu điểm là không mong muốn (ví dụ: bạn có thể không muốn nó ăn cắp tiêu điểm từ một chế độ xem khác).

Một cách tiếp cận thay thế là sử dụng thiết bị đánh chặn cảm ứng:

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

Sử dụng View popupView để loại bỏ popupWindow

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

`Nếu bạn sử dụng điều này, bạn cũng có thể đặtOnClickListener thành bất kỳ nút nào bên trong cửa sổ bật lên

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.