AndroidPopupWindowがアクティブなときに背景をぼかすまたは暗くする


85

を使用してポップアップウィンドウを表示するときに背景をぼかしたり暗くしたりpopup.showAtLocationpopup.dismissが呼び出されたときに背景をぼかしたり暗くしたりできるようにしたいと思います。

レイアウトパラメータFLAG_BLUR_BEHINDFLAG_DIM_BEHINDアクティビティを適用しようとしましたが、アプリを起動するとすぐに背景がぼやけたり暗くなったりするようです。

ポップアップだけでぼかし/調光を行うにはどうすればよいですか?


1
警告の言葉:FLAG_BLUR_BEHINDは一部の電話でバグがあり、電話が非常に応答しなくなります(明らかに、ぼかしはソフトウェアで行われます)。たとえば、ドロイドでは。それ以外に、マッカースが言ったこと-FLAG_BLUR_BEHINDをフォアグラウンドのウィンドウに適用する必要があります。
EboMike 2010


1
私はこの質問に対する同じ答えを探しています。ポップアップウィンドウの背後にあるビューをプログラムで暗くする方法はありますか?
ニック

1
@Nickこの問題をどのように解決したか..–
Amit

回答:


106

質問はPopupwindowクラスについてでしたが、誰もがDialogクラスを使用して答えを出しました。メソッドがないPopupwindowため、クラスを使用する必要がある場合、これPopupwindowはほとんど役に立ちませんgetWindow()

実際に動作するソリューションを見つけましたPopupwindow。バックグラウンドアクティビティに使用するxmlファイルのルートが。である必要があるだけFrameLayoutです。あなたは与えることができますFramelayout要素にandroid:foregroundタグを。このタグが行うことは、アクティビティ全体の上に階層化されるドローアブルリソースを指定することです(つまり、Framelayoutがxmlファイルのルート要素である場合)。その後、不透明度を制御できます(setAlpha()、前景のドローアブルの)をます。

好きなドローアブルリソースを使用できますが、調光効果だけが必要な場合は、<shape>タグをルートとしてドローアブルフォルダーにxmlファイルを作成します。

<?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>

(要素の詳細については、http://developer.android.com/guide/topics/resources/drawable-resource.html#Shapeを参照してくださいshape)。ドローアブルアイテムを透明にするカラータグにアルファ値を指定しなかったことに注意してください(例 #ff000000)。これは、ハードコードされたアルファ値が、を介して設定した新しいアルファ値を上書きしているように見えるためです。setAlpha()が、コードで望ましくないためです。ただし、これは、描画可能なアイテムが最初は不透明(塗りつぶされ、不透明)になることを意味します。したがって、アクティビティのonCreate()メソッドで透過的にする必要があります。

Framelayoutxml要素コードは次のとおりです。

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

アクティビティのonCreate()メソッドは次のとおりです。

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

最後に、アクティビティを暗くするコード:

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

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

アルファ値は 0(不透明)から255(非表示)になります。ポップアップウィンドウを閉じるときは、アクティビティの調光を解除する必要があります。

ポップアップウィンドウを表示および非表示にするためのコードは含まれていませんが、その方法へのリンクは次のとおりです:http//www.mobilemancer.com/2011/01/08/popup-window-in-android/


これが古いデバイスでも機能するようにするには、アルファチャネルに変更を加えるたびにフォアグラウンドを無効にする必要があります。これを答えに追加しました。素敵な答えを1
user2224350

1
これが正しい答えとしてマークされていない理由を私は考えることができません..控えめに言っても素晴らしい答え。
Jayshil Dave

2
アクションバーが表示されている場合はどうでしょうか。暗くすることはできません
BaDo 2014

これは私にとって最適でした...以下のダブルポップアップの回答には競合状態があったため、淡色表示されたポップアップが実際のポップアップを超えることがありました
kenyee 2014

1
ほぼ完璧。唯一の欠点は、他のレイアウトには「getForeground」メソッドがないため、FrameLayoutを使用する必要があることです。
LiangWang 2015年

79

以来PopupWindowちょうど追加ViewWindowManagerご使用することができますupdateViewLayout (View view, ViewGroup.LayoutParams params)更新するLayoutParamsあなたのPopupWindowのをcontentView)(..ショーを呼び出した後。

ウィンドウフラグFLAG_DIM_BEHINDを設定すると、ウィンドウの背後にあるすべてのものが暗くなります。dimAmount薄暗い量を制御するために使用します(完全に不透明な場合は1.0、薄暗い場合は0.0)。

あなたがあなたPopupWindowに背景を設定した場合、それはあなたを置くことを覚えておいてくださいcontentView、コンテナにつまり、親を更新する必要があります。

背景付き:

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

背景なし:

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

マシュマロアップデート:

Mでは、PopupWindowはcontentViewをmDecorViewと呼ばれるFrameLayout内にラップします。PopupWindowソースを掘り下げると、次のようなものが見つかります。createDecorView(View contentView)ます。mDecorViewの主な目的は、Mの新機能であるイベントディスパッチとコンテンツ遷移を処理することです。つまり、コンテナにアクセスするには、.getParent()をもう1つ追加する必要があります。

次のようなものへの変更が必要な背景がある場合:

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

API18 +のより良い代替手段

以下を使用したハッキーでないソリューションViewGroupOverlay

1)目的のルートレイアウトを取得します

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

2)電話applyDim(root, 0.5f);またはclearDim()

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
これは、Android 6.0Marshmallowを実行しているデバイスでは機能しないようです。layoutParamsはにキャストしませんWindowManager.LayoutParams。回避策はありますか?
ロバート

ご指摘いただきありがとうございます。Mではまだテストしていません。できるだけ早く更新します。
Markus Rubey 2015年

@ stackoverflow.com/users/308153/robert私も同じ問題を抱えていました。上記のコードをバックグラウンドで使用しました。
リズワンソハイブ2015

pがnullの場合は、次を使用します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 2016

1
参考までにこれを低いAPIレベル(15や20など)で使用すると、popup.getContentView()。getParent()がViewを返さないためにクラッシュするため、キャストするとクラッシュします。この場合、フォールバックとして@BeytanKurtのメソッドを使用しました。
マシューホルスト

29

xmlファイルに、幅と高さを「match_parent」として次のようなものを追加します。

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

あなたの活動でoncreate

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

最後に、ポップアップウィンドウを表示するときに表示し、ポップアップウィンドウを終了するときに非表示にします。

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

1
「Thanks、Rupesh」のような署名を投稿に残さないでください。
Simon Hellinger 2013

3
しかし、これはアクション/ツールバーを暗くしません。
シルビアH

Plzはツールバーの薄暗いアクションの方法を教えてくれます
SAndroidD 2015年

back_dim_layout.setVisibility(View.GONE);を追加します。PopupWindow.OnDismissListener
Pulkit

確かに私を助けてくれました
PixxuWaku19年

12

もう1つのトリックは、1つではなく2つのポップアップウィンドウを使用することです。最初のポップアップウィンドウは、薄暗い効果を提供する半透明の背景を持つ単なるダミービューになります。2番目のポップアップウィンドウは、目的のポップアップウィンドウです。

ポップアップウィンドウの作成中のシーケンス: ダミーのポップアップウィンドウを最初に表示し、次に目的のポップアップウィンドウを表示します。

破棄中のシーケンス: 目的のポップアップウィンドウを閉じてから、ダミーのポップアップウィンドウを閉じます。

これら2つをリンクする最良の方法は、OnDismissListenerを追加しonDismiss()、ダミーのポップアップウィンドウをそれらから閉じることを目的としたメソッドをオーバーライドすることです。

ダミーポップアップウィンドウのコード:

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>

フェードポップアップを表示して背景を暗くする

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

ほとんど私にとってはうまくいきます...時々、ポップアップウィンドウが薄暗い/ダミーのポップアップウィンドウの後ろにある競合状態があります。まだ回避策を見つけていません...ポップアップウィンドウの表示を遅らせて、遅らせたものよりも遅れさせることは役に立ちません:-P
kenyee 2014

2
@kenyeeこの問題の修正を見つけました。最初に「フェード」ポップアップを表示し、次に2番目のポップアップを表示するために、myFadePopup.getContentView()。post(... myPopup.showAtLocation ...);を使用しています。
ピョートル・

5

私はこれに対する解決策を見つけました

カスタムの透過ダイアログを作成し、そのダイアログ内でポップアップウィンドウを開きます。

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

ダイアログの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" />

ここで、ポップアップウィンドウが閉じたときにダイアログを閉じたいと思います。そう

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

注:NewQuickActionここでは、PopupWindowを作成するためにプラグインを使用しました。ネイティブのポップアップウィンドウでも実行できます


1

私にとっては、Abdelhak Mouaamouの回答のようなものが機能し、APIレベル16および27でテストされています。

popupWindow.getContentView().getParent()結果を使用してキャストする代わりにView(APIレベル16でクラッシュするとViewRootImpl、インスタンスではないオブジェクトが返されます)、ビューを返すものをView使用するだけ.getRootView()なので、キャストは必要ありません。

それが誰かを助けることを願っています:)

他のstackoverflow投稿から一緒にスクランブルされた完全な作業例。たとえば、ボタンのonClickリスナーにコピーして貼り付けます。

// 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 明るさを暗くしたいレイアウトのIDです。


0

あなたはそれをするandroid:theme="@android:style/Theme.Dialog"ために使うことができます。アクティビティを作成し、アクティビティを次のようにAndroidManifest.xml定義します。

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

これはうまくいかないようです。私はこれを私の唯一のアクティビティに適用しました。これは、私が持っている単なる膨らんだレイアウトであり、個別のアクティビティではないポップアップウィンドウを表示するときにバックグラウンドにあります。FLAG_BLUR_BEHINDをPopupWindowに適用するにはどうすればよいですか?
k_day 2010

0

わかりました。ポップウィンドウが開いているときにバックグラウンドアクティビティを暗くするためのuhmdownの回答に従います。しかし、それは私にとって問題を引き起こします。それは調光アクティビティであり、ポップアップウィンドウが含まれています(アクティビティとポップアップの両方に薄暗い黒のレイヤーがあり、それらを分離することはできません)。

だから私はこの方法を試しました、

調光効果のためにdimming_black.xmlファイルを作成します。

 <?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>

そしてとして追加backgroundFrameLayoutも、私の他のコントロールを入れ、ルートXMLタグとしてLinearLayout、このようにlayout.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>

最後にMainActivity、以下のようにいくつかの追加パラメータを設定してポップアップを表示します。

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

結果: ここに画像の説明を入力してください

それは私のために働き、BaDoによってコメントされたように問題も解決しました。これActionbarで暗くすることもできます。

PS私はuhmdownが間違っていると言っているのではありません。私は彼の答えから学び、私の問題のために進化しようとしました。これが良い方法かどうかも混乱しました。

私の悪い英語も申し訳ありませんが、どんな提案もありがたいです。


0

多分このリポジトリはあなたのために役立つでしょう:BasePopup

これは、PopupWindowのさまざまな問題を解決するために使用される私のリポジトリです。

ライブラリを使用する場合、背景をぼかす必要がある場合は、 setBlurBackgroundEnable(true).

詳細については、wikiを参照してください。(zh-cnの言語)

BasePopup:wiki


-1

このコードは機能します

        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);
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.