Me gustaría poder difuminar o atenuar el fondo cuando muestro mi ventana emergente usando popup.showAtLocation
, y desenfocar / atenuar el fondo cuando popup.dismiss
se llama.
He intentado aplicar parámetros de diseño FLAG_BLUR_BEHIND
y FLAG_DIM_BEHIND
a mi actividad, pero parece que esto simplemente difumina y atenúa el fondo tan pronto como se inicia mi aplicación.
¿Cómo puedo difuminar / atenuar solo con ventanas emergentes?
Respuestas:
La pregunta era sobre la
Popupwindow
clase, pero todos han dado respuestas que usan laDialog
clase. Eso es bastante inútil si necesita usar laPopupwindow
clase, porquePopupwindow
no tiene ungetWindow()
método.Encontré una solución que realmente funciona con
Popupwindow
. Solo requiere que la raíz del archivo xml que usa para la actividad en segundo plano sea unFrameLayout
. Puedes darleFramelayout
unaandroid:foreground
etiqueta al elemento . Lo que hace esta etiqueta es especificar un recurso dibujable que se superpondrá a toda la actividad (es decir, si Framelayout es el elemento raíz en el archivo xml). A continuación, puede controlar la opacidad (setAlpha()
) del dibujable de primer plano.Puede usar cualquier recurso dibujable que desee, pero si solo desea un efecto de atenuación, cree un archivo xml en la carpeta dibujable con la
<shape>
etiqueta como raíz.<?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 obtener más información sobre el
shape
elemento). Tenga en cuenta que no especifiqué un valor alfa en la etiqueta de color que haría transparente el elemento dibujable (por ejemplo#ff000000
). La razón de esto es que cualquier valor alfa codificado parece anular cualquier valor alfa nuevo que establezcamos a travéssetAlpha()
de nuestro código, por lo que no queremos eso. Sin embargo, eso significa que el elemento dibujable inicialmente será opaco (sólido, no transparente). Por tanto, debemos hacerlo transparente en elonCreate()
método de la actividad .Aquí está el código del 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>
Aquí está el método onCreate () de 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, el código para atenuar la actividad:
layout_MainMenu.getForeground().setAlpha( 220); // dim layout_MainMenu.getForeground().setAlpha( 0); // restore
Los valores alfa van de
0
(opaco) a255
(invisible). Debe quitar la atenuación de la actividad cuando cierre la ventana emergente.No he incluido código para mostrar y descartar la ventana emergente, pero aquí hay un enlace a cómo se puede hacer: http://www.mobilemancer.com/2011/01/08/popup-window-in-android/
fuente
Dado que
PopupWindow
sólo se suma unaView
queWindowManager
se puede utilizarupdateViewLayout (View view, ViewGroup.LayoutParams params)
para actualizar elLayoutParams
de susPopupWindow
'scontentView
después de llamar espectáculo .. ().Establecer la bandera de la ventana
FLAG_DIM_BEHIND
atenuará todo lo que se encuentra detrás de la ventana. ÚselodimAmount
para controlar la cantidad de atenuación (1.0 para completamente opaco a 0.0 para no atenuar).Tenga en cuenta que si establece un fondo para su,
PopupWindow
lo colocarácontentView
en un contenedor, lo que significa que debe actualizar su padre.Con antecedentes:
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);
Sin fondo:
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);
Actualización de Marshmallow:
En M, PopupWindow envuelve el contentView dentro de un FrameLayout llamado mDecorView. Si profundiza en la fuente de PopupWindow, encontrará algo como
createDecorView(View contentView)
. El propósito principal de mDecorView es manejar el envío de eventos y las transiciones de contenido, que son nuevas para M. Esto significa que debemos agregar un .getParent () más para acceder al contenedor.Con antecedentes que requerirían un cambio a algo como:
View container = (View) popup.getContentView().getParent().getParent();
Mejor alternativa para API 18+
Una solución menos hacky usando
ViewGroupOverlay
:1) Obtenga el diseño raíz deseado
2) Llame
applyDim(root, 0.5f);
oclearDim()
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(); }
fuente
WindowManager.LayoutParams
. ¿Existe alguna solució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); } }); }
En su archivo xml agregue algo como esto con ancho y alto 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>
En tu actividad oncreate
//setting background dim when showing popup back_dim_layout = (RelativeLayout) findViewById(R.id.share_bac_dim_layout);
Finalmente, haz que sea visible cuando muestres tu ventana emergente y haz que desaparezca cuando salgas de la ventana emergente.
back_dim_layout.setVisibility(View.VISIBLE); back_dim_layout.setVisibility(View.GONE);
fuente
Otro truco consiste en utilizar 2 ventanas emergentes en lugar de una. La primera ventana emergente será simplemente una vista ficticia con fondo translúcido que proporciona el efecto de atenuación. La segunda ventana emergente es su ventana emergente prevista.
Secuencia al crear ventanas emergentes: muestra la ventana emergente ficticia primero y luego la ventana emergente deseada.
Secuencia al destruir: descarte la ventana emergente deseada y luego la ventana emergente ficticia.
La mejor manera de vincular estos dos es agregar un OnDismissListener y anular el
onDismiss()
método de la intención de atenuar la ventana emergente ficticia de su.Código para la ventana emergente ficticia:
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 ventana emergente de atenuación para atenuar el fondo
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; }
fuente
He encontrado una solución para esto
Cree un diálogo transparente personalizado y dentro de ese diálogo abra la ventana emergente:
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 el 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" />
ahora desea cerrar el cuadro de diálogo cuando se cierra la ventana emergente. entonces
mQuickAction.setOnDismissListener(new OnDismissListener() { @Override public void onDismiss() { if(dialog!=null) { dialog.dismiss(); // dismiss the empty dialog when the PopupWindow closes dialog = null; } } });
Nota: he usado
NewQuickAction
complemento para crear PopupWindow aquí. También se puede hacer en ventanas emergentes nativasfuente
Para mí, algo como la respuesta de Abdelhak Mouaamou funciona, probado en los niveles de API 16 y 27.
En lugar de usar
popupWindow.getContentView().getParent()
y enviar el resultado aView
(que se bloquea en el nivel de API 16 porque allí devuelve unViewRootImpl
objeto que no es una instancia deView
), solo uso.getRootView()
que ya devuelve una vista, por lo que no se requiere conversión allí.Espero que ayude a alguien :)
ejemplo de trabajo completo codificado de otras publicaciones de stackoverflow, simplemente cópielo y péguelo, por ejemplo, en el oyente onClick de un botón:
// 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); } }
fuente
findViewById(R.id.drawer_layout).setAlpha((float) 0.7);
R.id.drawer_layout
es la identificación del diseño cuyo brillo desea atenuar.fuente
Puede utilizar
android:theme="@android:style/Theme.Dialog"
para hacer eso. Cree una actividad yAndroidManifest.xml
defina la actividad como:<activity android:name=".activities.YourActivity" android:label="@string/your_activity_label" android:theme="@android:style/Theme.Dialog">
fuente
ok, sigo la respuesta de uhmdown para atenuar la actividad de fondo cuando la ventana emergente está abierta. Pero me crea un problema. estaba atenuando la actividad e incluía una ventana emergente (significa que el negro atenuado en capas tanto en la actividad como en la ventana emergente también, no se puede separar).
así que lo intenté de esta manera
cree un archivo dimming_black.xml para el efecto de atenuación,
<?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>
Y añadir
background
enFrameLayout
como etiqueta XML raíz, también poner mis otros controles enLinearLayout
como estolayout.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>
por fin muestro una ventana emergente en mi
MainActivity
con algunos parámetros adicionales establecidos como se muestra a continuación.//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 mí, también problema resuelto según lo comentado por BaDo . Con esto
Actionbar
también se puede atenuar.Ps, no estoy diciendo que uhmdown's esté mal. Aprendí de su respuesta y trato de evolucionar para mi problema. También confundí si esta es una buena manera o no.
Cualquier sugerencia también es apreciada y lo siento por mi mal inglés.
fuente
Quizás este repositorio te ayude: BasePopup
Este es mi repositorio, que se utiliza para resolver varios problemas de PopupWindow.
En el caso de usar la biblioteca, si necesita desenfocar el fondo, simplemente llame
setBlurBackgroundEnable(true).
Consulte la wiki para obtener más detalles. (Idioma en zh-cn)
BasePopup: wiki
fuente
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);
fuente