PopupWindow - Tutup saat diklik di luar


93

Saya memiliki PopupWindow di aktivitas saya, masalahnya adalah PopupWindow saya masih muncul bahkan ketika saya berinteraksi dengan aktivitas saya (katakanlah menggulir di daftar saya). Saya dapat menggulir daftar saya dan PopupWindow masih ada.

Apa yang ingin saya capai adalah ketika saya menyentuh / menggulir / mengklik / dll pada layar yang bukan PopupWindow, saya ingin menutup PopupWindow. Sama seperti cara kerja menu. Jika Anda mengklik di luar menu, menu tersebut akan ditutup.

Saya sudah mencoba setOutsideTouchable(true)tetapi tidak menutup jendela. Terima kasih.

Jawaban:


129

Silakan coba untuk set setBackgroundDrawablepada PopupWindowyang harus menutup jendela jika Anda menyentuh di luar itu.


5
Saya melewatkannya. Apakah Anda menggunakan setBackgroundDrawable di popupWindow? Saya tahu bahwa menyetel drawable latar belakang ke nol akan membunuh OnTouchListener
Marcin S.

31
itu dia! terima kasih! dalam hal ini, bahkan acara sentuh dapat ditangani dengan baik. popupWindow.setOutsideTouchable (true); popupWindow.setTouchable (true); popupWindow.setBackgroundDrawable (baru BitmapDrawable ()); popupWindow.setTouchInterceptor (OnTouchListener baru () {@Override public boolean onTouch (Lihat v, acara MotionEvent) {if (AppContext.isDebugMode ()) Log.d ("POPUP_WINDOW", "v:" + v.getTag () + " | acara: "+ event.getAction ()); popupWindow.dismiss (); return true;}});
beerstorm

3
Menyetel drawable latar belakang ke nol tidak berfungsi untuk saya. Jika ada orang lain yang memiliki masalah, lihat jawaban saya.
mpellegr

2
@WareNinja, komentar Anda berhasil! Mungkin lebih baik Anda menyerahkan seluruh jawaban atas pertanyaan ini, ini akan berguna bagi orang lain
Anton Kizema

3
@WareCinja BitmapDrawable()dikosongkan. Gunakan ColorDrawable()sebagai gantinya.
Srujan Barai

125

Saya menemukan bahwa tidak ada jawaban yang diberikan yang berhasil untuk saya, kecuali komentar WareNinja pada jawaban yang diterima, dan kemungkinan Marcin S. juga akan bekerja. Inilah bagian yang berhasil untuk saya:

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

Kalau tidak:

myPopupWindow.setFocusable(true);

Tidak yakin apa perbedaannya, tetapi kode sumber ListPopupWindow benar-benar menggunakan yang terakhir ketika modalnya disetel ke true dengan setModal, jadi setidaknya pengembang Android menganggap ini sebagai pendekatan yang layak, dan itu hanya satu baris.


6
Terima kasih banyak. Tidak ada jawaban lain yang berhasil untuk saya atau menjelaskannya dengan cukup baik. Pilihan kedua tidak bekerja untuk saya.
JDN

2
Juga saya perhatikan bahwa BitmapDrawable sudah tidak digunakan lagi. Alangkah baiknya memiliki solusi nyata untuk masalah ini, karena ini sepertinya solusi sementara tidak dijamin akan didukung dalam versi API yang lebih baru.
HAL9000

untuk tidak menggunakan konstruktor BitmapDrawable yang sudah tidak digunakan lagi, lihat di sini: stackoverflow.com/a/21680637/2048266 . popupWindow.setBackgroundDrawable (BitmapDrawable baru (getResources (), ""));
nommer

Saat menggunakan metode alternatif setFocusable, kita perlu mengklik tombol dua kali (di mana tombol ditempatkan di luar pop-up) dimana seperti pada metode pertama ini berfungsi dengan baik :)
Joy Rex

BitmapDrawable()depricated. Gunakan ColorDrawable()sebagai gantinya.
Srujan Barai

60

Saya menemui masalah yang sama, dan memperbaikinya seperti kode di bawah ini. Ini bekerja dengan baik untuk saya.

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

BTW, Jangan gunakan konstruktor BitmapDrawable deprecated, gunakan ColorDrawable baru ini (android.R.color.transparent) untuk mengganti latar belakang default.

Selamat bersenang-senang@.@


3
Pastikan untuk menambahkan kode ini sebelum menampilkan popoupWindow
snersesyan

Apakah saya benar-benar perlu menyetel fokus ke true jika munculan tidak memerlukan fokus?
Levor

Saya kagum bahwa ini berfungsi, tetapi ini diperlukan pada API 21. Ini juga memperbaiki bahwa jendela popup saya dianimasikan secara tidak benar.
EpicPandaForce

24

Saya tahu ini sudah terlambat tetapi saya perhatikan bahwa orang-orang masih memiliki masalah dengan jendela popup. Saya telah memutuskan untuk menulis contoh yang berfungsi penuh di mana Anda dapat menutup jendela popup dengan menyentuh atau mengeklik di luarnya atau hanya menyentuh jendela itu sendiri. Untuk melakukannya buat kelas PopupWindow baru dan salin kode ini:

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

Sekarang buat tata letak untuk jendela popup: 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>      

Dalam aktivitas utama Anda, buat instance kelas PopupWindow:

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

dimana YOUR_MAIN_LAYOUT adalah tata letak aktivitas saat ini di mana popupWindow akan muncul


1
Terima kasih - ini berhasil untuk saya. Hanya satu catatan kecil adalah lebih baik menggunakan nama lain selain PopupWindow untuk kelas kustom Anda, mungkin menyebutnya MyPopupWindow daripada Popupwindow sehingga android tidak bingung antara kelas android standar dan kelas kustom Anda.
Simon

@Marcin S. findViewById (R.id.YOUR_MAIN_LAYOUT) ?? Apakah R.layout.My_Layout
Ankesh kumar Jaisansaria

@Simon findViewById (R.id.YOUR_MAIN_LAYOUT) ?? Akankah R.layout.My_Layout?
Ankesh kumar Jaisansaria

15

Terima kasih atas jawaban @ LunaKong dan konfirmasi @ HourGlass. Saya tidak ingin membuat komentar duplikat, tetapi hanya ingin membuatnya jelas dan ringkas.

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


Saya ingin menutup jendela popup dengan mengklik di luarnya, tetapi ketika saya melakukannya, tampilan di bawahnya (bukan bagian dari jendela popup, tetapi bagian dari aktivitas) sedang diklik. setFocusabl (true) adalah apa yang saya cari. Terima kasih!
hellaandrew

@hellaandrew, senang ini membantu Anda, :)
Nguyen Tan Dat

8

Untuk ListPopupWindowmengatur jendela menjadi modal saat ditampilkan.

mListPopupWindow.setModal(true);

Dengan begitu, mengklik di luar ListPopupWindowakan menutupnya.


Terima kasih, saya baru saja mencari ini. Ini tidak hanya menyetel listpopupwindow dapat ditutup setelah menyentuh di luar tampilan, tetapi juga tidak meneruskan acara sentuh ke tampilan lain yang ada di samping listpopwindow. Saya putus asa mencari ini karena dalam kasus saya menyentuh listpopwindow luar sedang meneruskan acara ke recyclerview yang berada di bawahnya di samping menutup listpopupwindow, dan item recyclerview dipilih yang tidak saya inginkan.
shankar_vl

Anda mungkin juga perlu mListPopupWindow.setInputMethodMode(PopupWindow.INPUT_METHOD_NOT_NEEDED);, untuk mencegah jendela popup mengganggu keyboard di layar.
Mr-IDE

6

Perhatikan bahwa untuk membatalkan dengan popupWindow.setOutsideTouchable(true), Anda perlu membuat lebar dan tinggi wrap_contentseperti kode di bawah ini:

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

Ini akan menutup PopupWindow saat klik / sentuh di layar. Pastikan Anda telah mengatur focusable true sebelum showAtLocation.


1
Harap tambahkan beberapa teks penjelasan untuk menjelaskan bagaimana ini memberikan jawaban yang akurat untuk pertanyaan yang diajukan. Terima kasih.
philantrovert

Terima kasih! Anda perlu memanggil setter sebelum memanggil showAtLocation ().
droid256

5

Anda dapat menggunakan isOutsideTouchable ATAU isFocusable untuk menutup jendela pop-up saat menyentuh di luar

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

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

Catatan

  • Saat ini, setelah pengujian saya melihat setBackgroundDrawable tidak membantu kami menutup jendela popup

  • Jika Anda melihat kode untuk diberhentikan di PopupWindow( PopupWindow->PopupDecorView->dispatchKeyEventdan PopupWindow->PopupDecorView->onTouchEvent). Anda akan melihat bahwa ketika menekan tombol kembali, mereka mengabaikan ACTION_UPdan ketika menyentuh di luar mereka menutup ACTION_UPatauACTION_OUTSIDE


4
mPopWindow.setFocusable(true);

1
Ini satu-satunya hal yang dibutuhkan. Saya tidak mengerti mengapa jawaban yang diterima sangat disukai.
sziraqui

4

Saran @LunaKong bekerja seperti pesona.

Tetapi menyiapkan mPopupWindow.setFocusable (false).menghapus sentuhan yang tidak perlu yang diperlukan untuk menghilangkan jendela popup.

Misalnya: Anggap saja ada jendela pop-up yang terlihat di layar, dan Anda akan mengklik tombol. Jadi dalam kasus ini, (jika mpopwindow.setFocusable (true)) pada klik pertama tombol popupwindow akan ditutup. Tetapi Anda harus mengklik lagi untuk membuat tombol berfungsi. jika ** (mpopwindwo.setFocusable (false) ** satu klik tombol tutup jendela popup serta memicu klik tombol. Semoga membantu.


1
Terimakasih banyak! Saya benar-benar mencari hal yang sama
Ganesh

3

Setel latar belakang jendela transparan:

PopupWindow.getBackground().setAlpha(0);

Setelah itu atur latar belakang Anda dalam tata letak. Bekerja dengan baik.


1
getBackground () bisa jadi null.
Jared Rummler

1

Dalam beberapa kasus, membuat munculan dapat difokuskan tidak diinginkan (misalnya Anda mungkin tidak ingin munculan mencuri fokus dari tampilan lain).

Pendekatan alternatif menggunakan interceptor sentuh:

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

Jika Jendela Popup ini adalah aktivitas lain, dan Anda mengurangi ukurannya ke layar asli dan Anda ingin mengaktifkan atau menonaktifkan area luar. Anda cukup mengaktifkan atau menonaktifkan area luar dengan kode ini:

memungkinkan:

YourActivity.this.setFinishOnTouchOutside(true);

nonaktifkan:

YourActivity.this.setFinishOnTouchOutside(false);


0

Gunakan View popupView untuk menutup popupWindow

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

`Jika Anda menggunakan ini, Anda juga dapat menyetelOnClickListener ke sembarang tombol di dalam jendela popup

Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.