Eu gostaria de poder desfocar ou escurecer o fundo quando eu mostrar minha janela pop-up usando popup.showAtLocation
, e desfocar / escurecer o fundo quando popup.dismiss
for chamado.
Tentei aplicar parâmetros de layout FLAG_BLUR_BEHIND
e FLAG_DIM_BEHIND
à minha atividade, mas isso parece apenas embaçar e escurecer o fundo assim que meu aplicativo é iniciado.
Como posso desfocar / escurecer apenas com pop-ups?
Respostas:
A pergunta era sobre a
Popupwindow
aula, mas todos deram respostas que usam aDialog
aula. Isso é praticamente inútil se você precisar usar aPopupwindow
classe, porquePopupwindow
não tem umgetWindow()
método.Eu encontrei uma solução que realmente funciona
Popupwindow
. Requer apenas que a raiz do arquivo xml que você usa para a atividade em segundo plano seja aFrameLayout
. Você pode dar aoFramelayout
elemento umaandroid:foreground
tag. O que essa tag faz é especificar um recurso drawable que será colocado em camadas sobre toda a atividade (ou seja, se o Framelayout for o elemento raiz no arquivo xml). Você pode então controlar a opacidade (setAlpha()
) do drawable do primeiro plano.Você pode usar qualquer recurso drawable que desejar, mas se quiser apenas um efeito de escurecimento, crie um arquivo xml na pasta drawable com a
<shape>
tag como raiz.<?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>
(Consulte http://developer.android.com/guide/topics/resources/drawable-resource.html#Shape para obter mais informações sobre o
shape
elemento). Observe que não especifiquei um valor alfa na tag de cor que tornaria o item drawable transparente (por exemplo#ff000000
). A razão para isso é que qualquer valor alfa codificado parece substituir quaisquer novos valores alfa que definimos por meio dosetAlpha()
em nosso código, então não queremos isso. No entanto, isso significa que o item drawable inicialmente será opaco (sólido, não transparente). Portanto, precisamos torná-lo transparente noonCreate()
método da atividade .Este é o código do elemento xml Framelayout:
<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>
Este é o método onCreate () da Activity:
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); }
Finalmente, o código para escurecer a atividade:
layout_MainMenu.getForeground().setAlpha( 220); // dim layout_MainMenu.getForeground().setAlpha( 0); // restore
Os valores alfa vão de
0
(opaco) a255
(invisível). Você deve apagar a atividade ao fechar a janela Popup.Não incluí o código para mostrar e dispensar o Popupwindow, mas aqui está um link de como isso pode ser feito: http://www.mobilemancer.com/2011/01/08/popup-window-in-android/
fonte
Desde
PopupWindow
apenas adiciona umView
paraWindowManager
que você pode usarupdateViewLayout (View view, ViewGroup.LayoutParams params)
para atualizar oLayoutParams
dos seusPopupWindow
'scontentView
depois de chamar espectáculo .. ().Definir o sinalizador da janela
FLAG_DIM_BEHIND
escurecerá tudo atrás da janela. UsedimAmount
para controlar a quantidade de não ofuscante (1,0 para opaco completamente a 0,0 para sem brilho).Lembre-se de que se você definir um plano de fundo para seu,
PopupWindow
ele o colocarácontentView
em um contêiner, o que significa que você precisa atualizá-lo.Com fundo:
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);
Sem fundo:
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);
Atualização do Marshmallow:
Em M PopupWindow envolve o contentView dentro de um FrameLayout chamado mDecorView. Se você pesquisar a fonte PopupWindow, encontrará algo como
createDecorView(View contentView)
. O objetivo principal do mDecorView é lidar com o envio de eventos e as transições de conteúdo, que são novas para M. Isso significa que precisamos adicionar mais um .getParent () para acessar o contêiner.Com antecedentes que exigiriam uma mudança para algo como:
View container = (View) popup.getContentView().getParent().getParent();
Melhor alternativa para API 18+
Uma solução menos hacky usando
ViewGroupOverlay
:1) Obtenha o layout de raiz desejado
2) Ligue
applyDim(root, 0.5f);
ouclearDim()
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(); }
fonte
WindowManager.LayoutParams
. Existe uma solução alternativa?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); } }); }
Em seu arquivo xml, adicione algo assim com largura e altura como '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>
Em sua atividade ao criar
//setting background dim when showing popup back_dim_layout = (RelativeLayout) findViewById(R.id.share_bac_dim_layout);
Finalmente, torne visível quando você mostrar sua janela pop-up e deixe-o visível quando você sair da janela pop-up.
back_dim_layout.setVisibility(View.VISIBLE); back_dim_layout.setVisibility(View.GONE);
fonte
Outro truque é usar 2 janelas pop-up em vez de uma. A primeira janela pop-up será simplesmente uma visão fictícia com fundo translúcido que fornece o efeito de escurecimento. A segunda janela pop-up é a janela pop-up pretendida.
Sequência durante a criação de janelas pop-up: Mostre a janela pop-up fictícia primeiro e depois a janela pop-up pretendida.
Sequência durante a destruição: Ignore a janela pop-up pretendida e, em seguida, a janela pop-up fictícia.
A melhor maneira de vincular esses dois é adicionar um OnDismissListener e substituir o
onDismiss()
método do pretendido para apagar a janela popup fictícia deles.Código para a janela pop-up fictícia:
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>
Mostrar pop-up de esmaecimento para escurecer o fundo
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; }
fonte
Eu encontrei uma solução para isso
Crie uma caixa de diálogo transparente personalizada e, dentro dessa caixa de diálogo, abra a janela pop-up:
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 para a caixa de diálogo (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" />
agora você deseja descartar a caixa de diálogo quando a janela Popup for fechada. então
mQuickAction.setOnDismissListener(new OnDismissListener() { @Override public void onDismiss() { if(dialog!=null) { dialog.dismiss(); // dismiss the empty dialog when the PopupWindow closes dialog = null; } } });
Nota: usei o
NewQuickAction
plugin para criar PopupWindow aqui. Também pode ser feito em janelas pop-up nativasfonte
Para mim, algo como a resposta de Abdelhak Mouaamou funciona, testado na API de nível 16 e 27.
Em vez de usar
popupWindow.getContentView().getParent()
e lançar o resultado paraView
(que trava na API de nível 16 porque lá ele retorna umViewRootImpl
objeto que não é uma instância deView
), eu apenas uso o.getRootView()
que já retorna uma visualização, portanto, não é necessário lançar aqui.Espero que ajude alguém :)
exemplo de trabalho completo misturado a partir de outras postagens stackoverflow, basta copiar e colar, por exemplo, no ouvinte onClick de um botão:
// 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); } }
fonte
findViewById(R.id.drawer_layout).setAlpha((float) 0.7);
R.id.drawer_layout
é o id do layout cujo brilho você deseja diminuir.fonte
Você pode usar
android:theme="@android:style/Theme.Dialog"
para fazer isso. Crie uma atividade e em vocêAndroidManifest.xml
defina a atividade como:<activity android:name=".activities.YourActivity" android:label="@string/your_activity_label" android:theme="@android:style/Theme.Dialog">
fonte
ok, então eu sigo a resposta do uhmdown para escurecer a atividade em segundo plano quando a janela pop está aberta. Mas isso cria problemas para mim. estava escurecendo a atividade e incluía janela pop-up (significa preto escuro em camadas na atividade e no pop-up também, não pode ser separado).
então eu tentei desta forma,
crie um arquivo dimming_black.xml para efeito de escurecimento,
<?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>
E adicionar como
background
emFrameLayout
como tag xml raiz, também colocar meus outros controlesLinearLayout
como estelayout.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>
finalmente mostro o pop-up no meu
MainActivity
com alguns parâmetros extras definidos como abaixo.//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);
Resultado:
funciona para mim, também resolveu problema como comentado pelo BaDo . Com isso
Actionbar
também pode ser esmaecido.PS, eu não estou dizendo que o uhmdown está errado. Aprendi a responder e tento evoluir para o meu problema. Também fiquei confuso se essa é uma boa maneira ou não.
Qualquer sugestão também é apreciada, desculpe pelo meu inglês ruim.
fonte
Talvez este repo ajude para você: BasePopup
Este é o meu repositório, que é usado para resolver vários problemas do PopupWindow.
No caso de usar a biblioteca, se você precisar desfocar o fundo, basta chamar
setBlurBackgroundEnable(true).
Veja o wiki para mais detalhes. (Idioma em zh-cn)
BasePopup: wiki
fonte
Este código funciona
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);
fonte