Android PopupWindow etkinken arka planı bulanıklaştırma veya karartma


85

Kullanarak açılır penceremi gösterdiğimde arka planı bulanıklaştırmak veya karartmak popup.showAtLocationve çağrıldığında arka planı bulanıklaştırmak / karartmak istiyorum popup.dismiss.

Düzen parametrelerini FLAG_BLUR_BEHINDve FLAG_DIM_BEHINDetkinliğime uygulamayı denedim , ancak bu, uygulamam başladığında arka planı bulanıklaştırıyor ve karartıyor gibi görünüyor.

Yalnızca pop-up'larla bulanıklaştırma / karartma nasıl yapabilirim?


1
Uyarı kelimesi: FLAG_BLUR_BEHIND bazı telefonlarda hatalı ve telefonu çok tepkisiz hale getiriyor (görünüşe göre bulanıklık yazılımda yapılıyor). Örneğin Droid'de. Bunun dışında Macarse'nin söylediği - FLAG_BLUR_BEHIND ön plandaki pencereye uygulanmalıdır.
EboMike


1
Bu soruya aynı cevabı arıyorum. Açılır pencerenin arkasındaki görünümü programlı olarak karartabilmemin bir yolu var mı?
Nick

1
@Nick Bu sorunu nasıl çözdünüz ..
Amit

Yanıtlar:


108

Soru Popupwindowsınıfla ilgiliydi , yine de herkes Dialogsınıfı kullanan cevaplar verdi . PopupwindowSınıfı kullanmanız gerekiyorsa, bu pek işe yaramaz çünkü Popupwindowbir getWindow()metodu yok.

Gerçekten işe yarayan bir çözüm buldum Popupwindow. Yalnızca arka plan etkinliği için kullandığınız xml dosyasının kökünün bir FrameLayout. FramelayoutÖğeye bir android:foregroundetiket verebilirsiniz . Bu etiketin yaptığı şey, tüm etkinliğin üstüne katmanlanacak çekilebilir bir kaynak belirtmektir (yani, Framelayout xml dosyasındaki kök öğeyse). Daha sonra setAlpha()ön plan çekilebilirinin opaklığını ( ) kontrol edebilirsiniz .

İstediğiniz herhangi bir çekilebilir kaynağı kullanabilirsiniz, ancak yalnızca bir karartma efekti istiyorsanız, çekilebilir klasörde <shape>kök olarak etiketiyle bir xml dosyası oluşturun .

<?xml version="1.0" encoding="utf-8"?>
<shape
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:shape="rectangle" >
    <solid android:color="#000000" />
</shape>

( Öğe hakkında daha fazla bilgi için bkz. Http://developer.android.com/guide/topics/resources/drawable-resource.html#Shapeshape ). Renk etiketinde, çekilebilir öğeyi saydam yapacak bir alfa değeri belirtmediğime dikkat edin (örn. #ff000000). Bunun nedeni, kodlanmış herhangi bir alfa değerinin kodumuzda aracılığıyla belirlediğimiz yeni alfa değerlerini geçersiz kılmasıdır setAlpha(), bu yüzden bunu istemiyoruz. Bununla birlikte, bu, çekilebilir öğenin başlangıçta opak olacağı (katı, şeffaf olmayan) anlamına gelir. Bu yüzden aktivitenin onCreate()yönteminde onu şeffaf hale getirmemiz gerekiyor .

Framelayout xml öğesi kodu:

<FrameLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/mainmenu"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    android:foreground="@drawable/shape_window_dim" >
...
... your activity's content
...
</FrameLayout>

Aktivitenin onCreate () yöntemi şöyledir:

public void onCreate( Bundle savedInstanceState)
{
  super.onCreate( savedInstanceState);

  setContentView( R.layout.activity_mainmenu);

  //
  // Your own Activity initialization code
  //

  layout_MainMenu = (FrameLayout) findViewById( R.id.mainmenu);
  layout_MainMenu.getForeground().setAlpha( 0);
}

Son olarak, etkinliği karartmak için kod:

layout_MainMenu.getForeground().setAlpha( 220); // dim

layout_MainMenu.getForeground().setAlpha( 0); // restore

Alfa değerleri 0(opak) ile 255(görünmez) arasında değişir. Açılır pencereyi kapattığınızda aktivitenin karartmasını kaldırmalısınız.

Popupwindow'u göstermek ve kapatmak için kod eklemedim, ancak burada nasıl yapılacağına dair bir bağlantı var: http://www.mobilemancer.com/2011/01/08/popup-window-in-android/


bunun eski cihazlarda da çalıştığından emin olmak için, alfa kanalında yapılan her değişiklikten sonra ön planı geçersiz kılmanız gerekir. Bunu cevaba ekledim. Güzel cevap için +1
user2224350

1
Bunun doğru cevap olarak işaretlenmediği bir sebep düşünemiyorum .. En azını söylemek için harika bir cevap.
Jayshil Dave

2
Peki ya görünümde Eylem Çubuğu var,
Karartamazsınız

bu benim için en iyisi çalıştı ... aşağıdaki çift açılır
pencerede

1
Neredeyse mükemmel. Tek dezavantajı, diğer düzenler için "getForeground" yöntemi olmadığı için FrameLayout kullanmanız gerektiğidir.
LiangWang

81

Yana PopupWindowsadece ekleyen Viewiçin WindowManagersize kullanabilirsiniz updateViewLayout (View view, ViewGroup.LayoutParams params)güncellemek için LayoutParamssizin bir PopupWindow's contentViewgösteriyi çağrıldıktan sonra .. ().

Pencere bayrağını ayarlamak, pencerenin FLAG_DIM_BEHINDarkasındaki her şeyi karartacaktır. dimAmountKarartma miktarını kontrol etmek için kullanın (tamamen opak için 1.0, dim olmaması için 0.0).

Bir arka plan ayarlarsanız, sizi bir kapsayıcıya PopupWindowkoyacağını unutmayın contentView, bu da ebeveynini güncellemeniz gerektiği anlamına gelir.

Arka plan ile:

PopupWindow popup = new PopupWindow(contentView, width, height);
popup.setBackgroundDrawable(background);
popup.showAsDropDown(anchor);

View container = (View) popup.getContentView().getParent();
WindowManager wm = (WindowManager) getSystemService(Context.WINDOW_SERVICE);
WindowManager.LayoutParams p = (WindowManager.LayoutParams) container.getLayoutParams();
// add flag
p.flags |= WindowManager.LayoutParams.FLAG_DIM_BEHIND;
p.dimAmount = 0.3f;
wm.updateViewLayout(container, p);

Arka plan olmadan:

PopupWindow popup = new PopupWindow(contentView, width, height);
popup.setBackgroundDrawable(null);
popup.showAsDropDown(anchor);

WindowManager wm = (WindowManager) getSystemService(Context.WINDOW_SERVICE);
WindowManager.LayoutParams p = (WindowManager.LayoutParams) contentView.getLayoutParams();
// add flag
p.flags |= WindowManager.LayoutParams.FLAG_DIM_BEHIND;
p.dimAmount = 0.3f;
wm.updateViewLayout(contentView, p);

Hatmi Güncellemesi:

M'de PopupWindow, contentView öğesini mDecorView adlı bir FrameLayout içine sarar. PopupWindow kaynağına girerseniz, şöyle bir şey bulacaksınız:createDecorView(View contentView) . MDecorView'in temel amacı, M için yeni olan olay gönderimini ve içerik geçişlerini işlemektir. Bu, konteynere erişmek için bir .getParent () daha eklememiz gerektiği anlamına gelir.

Aşağıdakilere benzer bir değişiklik gerektiren arka plan ile:

View container = (View) popup.getContentView().getParent().getParent();

API 18+ için daha iyi bir alternatif

Daha az hackli bir çözüm kullanarak ViewGroupOverlay :

1) İstenen kök düzenine sahip olun

ViewGroup root = (ViewGroup) getWindow().getDecorView().getRootView();

2) Çağrı applyDim(root, 0.5f);veyaclearDim()

public static void applyDim(@NonNull ViewGroup parent, float dimAmount){
    Drawable dim = new ColorDrawable(Color.BLACK);
    dim.setBounds(0, 0, parent.getWidth(), parent.getHeight());
    dim.setAlpha((int) (255 * dimAmount));

    ViewGroupOverlay overlay = parent.getOverlay();
    overlay.add(dim);
}

public static void clearDim(@NonNull ViewGroup parent) {
    ViewGroupOverlay overlay = parent.getOverlay();
    overlay.clear();
}

2
Bu, artık Android 6.0 Marshmallow çalıştıran cihazlarda çalışmıyor gibi görünüyor. LayoutParams'a dönüştürme yapmaz WindowManager.LayoutParams. Bir çözüm var mı?
Robert

Gösterdiğiniz için teşekkürler. Henüz M'de test etmedim. En kısa sürede güncellenecek.
Markus Rubey

@ stackoverflow.com/users/308153/robert Ben de aynı sorunu yaşadım. Arka plan ile yukarıdaki kodu kullandım.
Rizwan Sohaib

P null ise şunu kullanın:if (p != null) { //same } else { popupView.addOnLayoutChangeListener(new View.OnLayoutChangeListener() { public void onLayoutChange(View v, int left, int top, int right, int bottom, int oldLeft, int oldTop, int oldRight, int oldBottom) { v.removeOnLayoutChangeListener(this); WindowManager.LayoutParams p = (WindowManager.LayoutParams) v.getLayoutParams(); p.flags = WindowManager.LayoutParams.FLAG_DIM_BEHIND; p.dimAmount = 0.3f; wm.updateViewLayout(v, p); } }); }
Beytan Kurt 07

1
Bilginize Bunu daha düşük API seviyelerinde (ör. 15 ve 20) kullandığımda, popup.getContentView (). GetParent () View döndürmediğinden çöküyor, bu yüzden döküm çökmeye neden oluyor. Bu vaka için geri dönüş olarak @ BeytanKurt'un yöntemini kullandım.
Matthew Horst

30

Xml dosyanıza genişlik ve yüksekliğe 'match_parent' olarak buna benzer bir şey ekleyin.

<RelativeLayout
        android:id="@+id/bac_dim_layout"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:background="#C0000000"
        android:visibility="gone" >
</RelativeLayout>

Etkinliğinizde

//setting background dim when showing popup
back_dim_layout = (RelativeLayout) findViewById(R.id.share_bac_dim_layout);

Son olarak, açılır pencerenizi gösterdiğinizde görünür hale getirin ve açılır pencereden çıktığınızda görünür olmasını sağlayın.

back_dim_layout.setVisibility(View.VISIBLE);
back_dim_layout.setVisibility(View.GONE);

1
Lütfen gönderilerde "Teşekkürler, Rupesh" gibi imzalar bırakmayın.
Simon Hellinger

3
ancak bu eylemi / araç çubuğunu karartmaz.
Silvia H


1
back_dim_layout.setVisibility (View.GONE) ekleyin; içinde PopupWindow.OnDismissListener
Pulkit

eminim bana yardım etti
Pixxu Waku

12

Diğer bir numara ise, bir yerine 2 açılır pencere kullanmaktır. 1. açılır pencere, loş efekti sağlayan yarı saydam arka plana sahip sahte bir görünüm olacaktır. 2. açılır pencere, istediğiniz açılır penceredir.

Açılır pencereler oluştururken sıralama: İlk olarak kukla açılır pencereyi ve ardından istenen açılır pencereyi gösterin.

İmha ederken sıra: İstenen açılır pencereyi ve ardından kukla açılır pencereyi kapatın.

Bu ikisini bağlamanın en iyi yolu, bir OnDismissListener eklemek onDismiss()ve kukla açılır pencereyi bunlardan karartmak için amaçlanan yöntemi geçersiz kılmaktır.

Sahte açılır pencere kodu:

fadepopup.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical" 
    android:id="@+id/fadePopup"
    android:background="#AA000000">
</LinearLayout>

Arka planı karartmak için solma açılır penceresini göster

private PopupWindow dimBackground() {

    LayoutInflater inflater = (LayoutInflater) EPGGRIDActivity.this
            .getSystemService(Context.LAYOUT_INFLATER_SERVICE);
    final View layout = inflater.inflate(R.layout.fadepopup,
            (ViewGroup) findViewById(R.id.fadePopup));
    PopupWindow fadePopup = new PopupWindow(layout, windowWidth, windowHeight, false);
    fadePopup.showAtLocation(layout, Gravity.NO_GRAVITY, 0, 0);
    return fadePopup;
}

Neredeyse benim için çalışıyor ... bazen, açılır pencerenin loş / kukla açılır pencerenin arkasında olduğu bir yarış durumu var. Henüz bir geçici çözüm bulamadım ... gecikmiş olanın arkasında zaman vermek için
açılır pencerenin gösterimini

2
@kenyee Bu sorun için bir düzeltme buldum. Önce 'solma' açılır penceresini gösteriyorum ve sonra ikinci açılır pencereyi göstermek için myFadePopup.getContentView (). Post (... myPopup.showAtLocation ...);
Piotr

5

Bunun için bir çözüm buldum

Özel bir şeffaf iletişim kutusu oluşturun ve bu iletişim kutusunun içinde açılır pencereyi açın:

dialog = new Dialog(context, android.R.style.Theme_Translucent_NoTitleBar);
emptyDialog = LayoutInflater.from(context).inflate(R.layout.empty, null);

/* blur background*/
WindowManager.LayoutParams lp = dialog.getWindow().getAttributes();  
lp.dimAmount=0.0f;  
dialog.getWindow().setAttributes(lp);  
dialog.getWindow().addFlags(WindowManager.LayoutParams.FLAG_BLUR_BEHIND); 
dialog.setContentView(emptyDialog);
dialog.setCanceledOnTouchOutside(true);
dialog.setOnShowListener(new OnShowListener()
{
    @Override
    public void onShow(DialogInterface dialogIx)
    {
        mQuickAction.show(emptyDialog); //open the PopupWindow here
    }
});
dialog.show();

iletişim kutusu için xml (R.layout.empty):

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
     android:layout_height="match_parent" android:layout_width="match_parent"
     style="@android:style/Theme.Translucent.NoTitleBar" />

şimdi Açılır pencere kapandığında iletişim kutusunu da kapatmak istiyorsunuz. yani

mQuickAction.setOnDismissListener(new OnDismissListener()
{
    @Override
    public void onDismiss()
    {
        if(dialog!=null)
        {
            dialog.dismiss(); // dismiss the empty dialog when the PopupWindow closes
            dialog = null;
        }
    }
});

Not: NewQuickActionBurada PopupWindow oluşturmak için eklenti kullandım . Yerel Popup Windows'ta da yapılabilir


1

Benim için Abdelhak Mouaamou'nun cevabı gibi bir şey çalışıyor, API seviyesi 16 ve 27'de test edildi.

Sonucu kullanmak popupWindow.getContentView().getParent()ve yayınlamak yerine View(ki API seviyesi 16'da çöküyor çünkü orada ViewRootImplörneği olmayan bir nesne döndürüyor View) sadece kullanıyorum.getRootView() zaten bir görünümü döndüren , bu yüzden burada çevrim gerekli değil.

Umarım birine yardımcı olur :)

diğer stackoverflow gönderilerinden birlikte karıştırılan eksiksiz çalışma örneği, yalnızca kopyalayıp yapıştırın, örneğin bir düğmenin onClick dinleyicisine:

// inflate the layout of the popup window
LayoutInflater inflater = (LayoutInflater)getSystemService(LAYOUT_INFLATER_SERVICE);
if(inflater == null) {
    return;
}
//View popupView = inflater.inflate(R.layout.my_popup_layout, null); // this version gives a warning cause it doesn't like null as argument for the viewRoot, c.f. /programming/24832497 and /programming/26404951
View popupView = View.inflate(MyParentActivity.this, R.layout.my_popup_layout, null);

// create the popup window
final PopupWindow popupWindow = new PopupWindow(popupView,
        LinearLayout.LayoutParams.WRAP_CONTENT,
        LinearLayout.LayoutParams.WRAP_CONTENT,
        true // lets taps outside the popup also dismiss it
        );

// do something with the stuff in your popup layout, e.g.:
//((TextView)popupView.findViewById(R.id.textview_popup_helloworld))
//      .setText("hello stackoverflow");

// dismiss the popup window when touched
popupView.setOnTouchListener(new View.OnTouchListener() {
        @Override
        public boolean onTouch(View v, MotionEvent event) {
            popupWindow.dismiss();
            return true;
        }
});

// show the popup window
// which view you pass in doesn't matter, it is only used for the window token
popupWindow.showAtLocation(view, Gravity.CENTER, 0, 0);
//popupWindow.setOutsideTouchable(false); // doesn't seem to change anything for me

View container = popupWindow.getContentView().getRootView();
if(container != null) {
    WindowManager wm = (WindowManager)getSystemService(Context.WINDOW_SERVICE);
    WindowManager.LayoutParams p = (WindowManager.LayoutParams)container.getLayoutParams();
    p.flags = WindowManager.LayoutParams.FLAG_DIM_BEHIND;
    p.dimAmount = 0.3f;
    if(wm != null) {
        wm.updateViewLayout(container, p);
    }
}

1
findViewById(R.id.drawer_layout).setAlpha((float) 0.7);

R.id.drawer_layout parlaklığını azaltmak istediğiniz düzenin kimliğidir.


0

Bunu android:theme="@android:style/Theme.Dialog"yapmak için kullanabilirsiniz . Bir aktivite oluşturun ve AndroidManifest.xmlsizde aktiviteyi şu şekilde tanımlayın:

    <activity android:name=".activities.YourActivity"
              android:label="@string/your_activity_label"
              android:theme="@android:style/Theme.Dialog">

Bu hile yapmıyor gibi görünüyor. Bunu, ayrı bir etkinlik değil, yalnızca sahip olduğum şişirilmiş bir düzen olan bir açılır pencere gösterdiğimde arka planda olan tek etkinliğime uyguladım. FLAG_BLUR_BEHIND'i bir PopupWindow'a nasıl uygularım?
k_day

0

tamam, uhmdown'u takip ediyorum pop pencere açıkken arka plan etkinliğini karartmak için yanıtını . Ama benim için sorun yaratıyor. karartma etkinliğiydi ve açılır pencere içeriyordu (hem etkinlikte hem de açılır pencerede soluk siyah katmanlı anlamına gelir, aynı zamanda onları ayıramaz).

bu yüzden bu şekilde denedim

karartma efekti için bir dimming_black.xml dosyası oluşturun ,

 <?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
    android:shape="rectangle">
    <solid android:color="#33000000" />
</shape>

Ve olarak eklemek backgroundde FrameLayoutaynı zamanda benim diğer denetimleri koymak, kök xml etiketi olarak LinearLayoutböylelayout.xml

<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    android:background="@drawable/ff_drawable_black">

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="vertical"
        android:layout_gravity="bottom"
        android:background="@color/white">

        // other codes...
    </LinearLayout>

</FrameLayout>

Sonunda MainActivityaşağıdaki gibi bazı ekstra parametrelerle birlikte pop-up'ımda gösteriyorum .

           //instantiate popup window
            popupWindow = new PopupWindow(viewPopup, LinearLayout.LayoutParams.MATCH_PARENT, LinearLayout.LayoutParams.MATCH_PARENT, true);

            //display the popup window
            popupWindow.showAtLocation(layout_ff, Gravity.BOTTOM, 0, 0);

Sonuç: görüntü açıklamasını buraya girin

benim için çalışıyor, aynı zamanda BaDo tarafından yorumlandığı gibi sorunu çözdü . Bununla birlikte Actionbarkarartılabilir.

Ps uhmdown'un yanlış olduğunu söylemiyorum . Onun cevabından öğrendim ve problemim için gelişmeye çalıştım. Bunun iyi bir yol olup olmadığı da kafam karıştı.

Kötü İngilizcem için de üzgünüm.


0

Belki bu depo size yardımcı olur: BasePopup

Bu, PopupWindow'un çeşitli sorunlarını çözmek için kullanılan depom.

Kitaplığın kullanılması durumunda, arka planı bulanıklaştırmanız gerekirse, setBlurBackgroundEnable(true).

Daha fazla ayrıntı için wiki'ye bakın. (Zh-cn'deki dil)

BasePopup: wiki


-1

Bu kod çalışır

        pwindo = new PopupWindow(layout, ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT, true);
        pwindo.showAtLocation(layout, Gravity.CENTER, 0, 0);
        pwindo.setOutsideTouchable(false);

        View container = (View) pwindo.getContentView().getParent();
        WindowManager wm = (WindowManager) getSystemService(Context.WINDOW_SERVICE);
        WindowManager.LayoutParams p = (WindowManager.LayoutParams) container.getLayoutParams();
        p.flags = WindowManager.LayoutParams.FLAG_DIM_BEHIND;
        p.dimAmount = 0.3f;
        wm.updateViewLayout(container, p);
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.