Desenfoque o fondo oscuro cuando Android PopupWindow está activo
Me gustaría poder desenfocar o atenuar el fondo cuando muestro mi ventana emergente usando popup.showAtLocation
, y unblur / dim el fondo cuando se llama popup.dismiss
.
He intentado aplicar los parámetros de diseño FLAG_BLUR_BEHIND
y FLAG_DIM_BEHIND
a mi actividad, pero esto parece borrar y atenuar el fondo tan pronto se inicie mi aplicación.
- Android: ¿Cómo arrastrar (mover) PopupWindow?
- Centrarse en EditText en una ventana emergente hace que la actividad se detenga
- Cómo crear un estilo de aplicación de Twitter Acciones rápidas en Android
- Facebook-esque Popup ¿Cómo?
- SetOnItemClickListener de ListView de Android de PopupWindow no se llama
¿Cómo puedo hacer borrosidad / atenuación sólo con pop-ups?
- Android - PopupWindow sobre una vista específica
- ¿No aparece PopupView?
- Popupwindow: ShowAsDropDown como superior derecha en lugar de inferior izquierda?
- OnAnimationEnd no se llama, onAnimationStart funciona bien
- Custom PopupWindow con el método despreciado BitmapDrawable
- EditText en una ventana emergente
- ¿Cómo mostrar el teclado en PopupWindow?
- Cómo mostrar un ListFragment existente en un DialogFragment
La pregunta era acerca de la clase Popupwindow
, sin embargo, todos han dado respuestas que utilizan la clase Dialog
. Eso es bastante inútil si necesita usar la clase Popupwindow
, porque Popupwindow
no tiene un método getWindow()
.
He encontrado una solución que realmente funciona con Popupwindow
. Sólo requiere que la raíz del archivo xml que utilice para la actividad de fondo sea FrameLayout
. Puedes darle al elemento Framelayout
un android:foreground
etiqueta de android:foreground
. Lo que hace esta etiqueta es especificar un recurso dibujable que se superpondrá en la parte superior de 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 primer plano dibujable.
Puede utilizar cualquier recurso extraíble que desee, pero si sólo desea un efecto de atenuación, cree un archivo xml en la carpeta dibujable con la etiqueta <shape>
como root.
<?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 elemento de shape
). Tenga en cuenta que no especificé un valor alfa en la etiqueta de color que haría transparente el elemento #ff000000
(por ejemplo, #ff000000
). La razón de esto es que cualquier valor alfanumérico codificado parece anular cualquier nuevo valor alfa que establezcamos a través de setAlpha()
en nuestro código, por lo que no queremos eso. Sin embargo, esto significa que el elemento estirable será inicialmente opaco (sólido, no transparente). Así que tenemos que hacerlo transparente en el método onCreate()
la actividad.
Aquí está el código del elemento xml de 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 la actividad:
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) a 255
(invisible). Usted debe desmarque la actividad cuando usted rechaza el Popupwindow.
No he incluido código para mostrar y despedir el Popupwindow, pero aquí hay un enlace a cómo se puede hacer: http://www.mobilemancer.com/2011/01/08/popup-window-in-android/
Debido a que PopupWindow
sólo agrega una View
a WindowManager
, puede usar updateViewLayout (View view, ViewGroup.LayoutParams params)
para actualizar los LayoutParams
del LayoutParams
de su contentView
después de llamar a show .. ().
Si se establece el indicador de ventana FLAG_DIM_BEHIND
obtendrá todo detrás de la ventana. Utilice dimAmount
para controlar la cantidad de atenuación (1,0 para completamente opaco a 0,0 para no oscurecer).
Tenga en cuenta que si establece un fondo para su PopupWindow
pondrá su contentView
en un contenedor, lo que significa que necesita 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(); p.flags = WindowManager.LayoutParams.FLAG_DIM_BEHIND; p.dimAmount = 0.3f; wm.updateViewLayout(container, p);
Sin antecedentes:
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(); 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 busca en la fuente de PopupWindow, encontrará algo como createDecorView(View contentView)
. El objetivo principal de mDecorView es gestionar el envío de sucesos y las transiciones de contenido, que son nuevas para M. Esto significa que necesitamos agregar una más .getParent () Para acceder al contenedor.
Con el fondo que requeriría un cambio a algo como:
View container = (View) popup.getContentView().getParent().getParent();
Mejor alternativa para API 18+
Una solución menos hacky con ViewGroupOverlay
:
1) Conseguir un asimiento de la disposición de la raíz deseada
ViewGroup root = (ViewGroup) getWindow().getDecorView().getRootView();
2) Llame a applyDim(root, 0.5f);
O 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(); }
En su archivo xml agregue algo como esto con el ancho y la 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>
En su actividad encrear
//setting background dim when showing popup back_dim_layout = (RelativeLayout) findViewById(R.id.share_bac_dim_layout);
Finalmente hacer visible cuando se muestra su ventana emergente y hacer su visible ido cuando sale popupwindow.
back_dim_layout.setVisibility(View.VISIBLE); back_dim_layout.setVisibility(View.GONE);
Otro truco es usar 2 ventanas emergentes en lugar de una. La primera ventana emergente será simplemente una vista falsa con el fondo translúcido que proporciona el efecto dévil. La segunda ventana emergente es la ventana emergente deseada.
Secuencia durante la creación de ventanas emergentes: Muestre la ventana emergente 1 y luego la ventana emergente deseada.
Secuencia durante la destrucción: Deseche la ventana emergente deseada y luego la ventana emergente de muñeca.
La mejor manera de vincular estos dos es agregar un OnDismissListener y anular el método onDismiss()
de la intención de dimiss la ventana emergente dummy 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 desvanecimiento emergente 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; }
He encontrado una solución para esto
Crear un cuadro de diálogo transparente personalizado y dentro de ese cuadro de diálogo abrir 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 descartar el diálogo cuando se desactiva la ventana emergente. asi que
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 utilizado el complemento NewQuickAction
para crear PopupWindow aquí. También se puede hacer en las ventanas emergentes nativas
Puedes usar android:theme="@android:style/Theme.Dialog"
para hacer eso. Crea una actividad y en tu AndroidManifest.xml
define la actividad como:
<activity android:name=".activities.YourActivity" android:label="@string/your_activity_label" android:theme="@android:style/Theme.Dialog">
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);
- El logcat de Android está inundado con "W / API de Google Maps para Android: GLHudOverlay obsoleto; Draw (): no-op "
- El tamaño de fuente diferente de las cadenas en el mismo TextView