Android PopupWindow가 활성화 될 때 배경이 흐리거나 어둡습니다.


85

를 사용하여 팝업 창을 표시 할 때 배경을 흐리게하거나 어둡게 할 수 있고를 사용하여 배경을 흐리게하거나 어둡게 할 수 있기를 popup.showAtLocation원합니다 popup.dismiss.

레이아웃 매개 변수 FLAG_BLUR_BEHINDFLAG_DIM_BEHIND내 활동을 적용하려고 시도했지만 앱이 시작 되 자마자 배경이 흐리게 표시되고 어둡게 표시됩니다.

팝업만으로 블러 링 / 디밍을하려면 어떻게해야하나요?


1
경고의 말씀 : FLAG_BLUR_BEHIND는 일부 휴대폰에서 버그가있어 휴대폰이 매우 응답하지 않게 만듭니다 (분명히 블러가 소프트웨어에서 수행됨). 예를 들어, Droid에서. 그 외에 Macarse가 말한 것-FLAG_BLUR_BEHIND는 전경의 창에 적용되어야합니다.
EboMike 2010


1
이 질문에 대한 동일한 답을 찾고 있습니다. 팝업 창 뒤에있는 뷰를 프로그래밍 방식으로 어둡게 할 수있는 방법이 있습니까?
Nick

1
이 문제를 해결하는 방법 @Nick ..
아 미트

답변:


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()메서드 에서 투명하게 만들어야합니다 .

다음은 Framelayout xml 요소 코드입니다.

<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(보이지 않음)으로 이동합니다. Popupwindow를 닫을 때 활동을 어둡게 해제해야합니다.

Popupwindow를 표시하고 닫는 코드는 포함하지 않았지만 수행 방법에 대한 링크는 다음과 같습니다. http://www.mobilemancer.com/2011/01/08/popup-window-in-android/


이것이 이전 장치에서도 작동하는지 확인하려면 알파 채널이 변경 될 때마다 전경을 무효화해야합니다. 나는 이것을 대답에 추가했습니다. +1 좋은 답변
user2224350 dec.

1
정답으로 표시되지 않은 이유를 생각할 수 없습니다.
Jayshil 데이브

2
보기에 대한 것은 실행 바있는 무엇, 당신은 그것을 어두워 질수
BaDo

이 흐리게 팝업 가끔 진짜 팝업 끝난 있도록 이중 팝업 답은 아래의 경쟁 조건을했다 ... 나에게 가장 일
kenyee을

1
거의 완벽합니다. 유일한 단점은 다른 레이아웃에 대한 "getForeground"메소드가 없기 때문에 FrameLayout을 사용해야한다는 것입니다.
LiangWang 2015 년

80

때문에 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);

Marshmallow 업데이트 :

M PopupWindow는 mDecorView라는 FrameLayout 안에 contentView를 래핑합니다. PopupWindow 소스를 createDecorView(View contentView)살펴보면 .mDecorView의 주요 목적은 M에 새로운 이벤트 전달 및 콘텐츠 전환을 처리하는 것입니다. 즉, 컨테이너에 액세스하려면 .getParent ()를 하나 더 추가해야합니다.

다음과 같이 변경해야하는 배경으로 :

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

API 18+를위한 더 나은 대안

다음을 사용하는 덜 해킹 된 솔루션 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.0 Marshmallow를 실행하는 기기에서는 더 이상 작동하지 않는 것 같습니다. layoutParams는 WindowManager.LayoutParams. 해결 방법이 있습니까?
Robert

지적 해 주셔서 감사합니다. 아직 M에서 테스트하지 않았습니다. 최대한 빨리 업데이트합니다.
Markus Rubey

@ stackoverflow.com/users/308153/robert 나도 같은 문제가있었습니다. 위의 코드를 배경으로 사용했습니다.
Rizwan Sohaib 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 커트

1
참고로 낮은 API 수준 (예 : 15 및 20)에서 이것을 사용하면 popup.getContentView (). getParent ()가 View를 반환하지 않으므로 충돌이 발생하므로 충돌이 발생합니다. 이 경우 @BeytanKurt의 방법을 폴백으로 사용했습니다.
Matthew Horst

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>

당신의 활동에서

//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-04-08

3
그러나 이것은 액션 / 툴바를 어둡게하지 않을 것입니다.
Silvia H

Plz은 어두워 도구 모음 행동을 어떻게 말해
SAndroidD

back_dim_layout.setVisibility (View.GONE); 추가 PopupWindow.OnDismissListener에서
Pulkit

반드시 나를 도와
Pixxu 두근에게

12

또 다른 트릭은 하나가 아닌 2 개의 팝업 창을 사용하는 것입니다. 첫 번째 팝업 창은 희미한 효과를 제공하는 반투명 배경의 더미보기입니다. 두 번째 팝업 창은 의도 한 팝업 창입니다.

팝업 창 생성시 순서 : 더미 팝업 창 1 번을 표시 한 다음 원하는 팝업 창을 표시합니다.

파괴 중 시퀀스 : 의도 한 팝업 창을 닫은 다음 더미 팝업 창을 닫습니다.

이 두 가지를 연결하는 가장 좋은 방법은 추가하는 것입니다 한 OnDismissListener을 하고 오버라이드 (override) onDismiss()(가) 자신의에서 더미 팝업 창을 dimiss하도록 구성의 방법을.

더미 팝업 창의 코드 :

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

2
@kenyee이 문제에 대한 수정 사항을 찾았습니다. 먼저 '페이드'팝업을 표시 한 다음 두 번째 팝업을 표시하기 위해 myFadePopup.getContentView (). post (... myPopup.showAtLocation ...);
Piotr

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

이것은 속임수를 쓰지 않는 것 같습니다. 나는 이것을 내 유일한 활동에 적용했는데, 이것은 내가 가지고있는 부풀려진 레이아웃이고 별도의 활동이 아닌 팝업 창을 표시 할 때 백그라운드에 있습니다. PopupWindow에 FLAG_BLUR_BEHIND를 어떻게 적용합니까?
k_day

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>

그리고로 추가 background에서 FrameLayout또한 내 다른 컨트롤에 넣어, 루트 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또한 흐리게 할 수 있습니다.

추신 나는 uhmdown의 말이 아니다 이 잘못되었다고 . 나는 그의 대답에서 배웠고 내 문제를 위해 진화하려고 노력했습니다. 나는 이것이 좋은 방법인지 아닌지 혼란 스러웠다.

어떤 제안이라도 내 영어가 좋지 않아서 죄송합니다.


0

아마도이 저장소가 도움이 될 것입니다 : BasePopup

이것은 PopupWindow의 다양한 문제를 해결하는 데 사용되는 내 저장소입니다.

라이브러리를 사용하는 경우 배경을 흐리게해야한다면 setBlurBackgroundEnable(true).

자세한 내용은 위키를 참조하십시오. (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.