2010-07-11 10 views
67

Me gustaría poder desenfocar o atenuar el fondo cuando se muestra mi ventana emergente usando popup.showAtLocation, y desdibujar/atenuar el fondo cuando se llama popup.dismiss.Desenfocar o atenuar el fondo cuando Android PopupWindow activo

He tratado de aplicar los parámetros de diseño FLAG_BLUR_BEHIND y FLAG_DIM_BEHIND a mi actividad, pero parece que esto borra y atenúa el fondo tan pronto como se inicia mi aplicación.

¿Cómo puedo hacer borrosas/atenuadas solo con ventanas emergentes?

+1

Una palabra de advertencia: FLAG_BLUR_BEHIND está libre de errores en algunos teléfonos y hace que el teléfono muy insensibles (al parecer la falta de definición se hace en software). En el Droid, por ejemplo. Aparte de eso, lo que dijo Macarse: FLAG_BLUR_BEHIND debe aplicarse a la ventana en primer plano. – EboMike

+0

posible duplicado de [¿La mejor forma de mostrar un texto de edición sobre la pantalla?] (Http://stackoverflow.com/questions/460418/best-way-to-show-a-edit-text-over -screen) – Pops

+1

Yo soy buscando la misma respuesta a esta pregunta. ¿Hay alguna manera de atenuar programáticamente la vista que se encuentra detrás de la ventana emergente? – Nick

Respuesta

0

Puede usar android:theme="@android:style/Theme.Dialog" para hacer eso. Crear una actividad y en su AndroidManifest.xml definir la actividad como:

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

Esto no parece hacer el truco. Apliqué esto a mi única actividad, que está en segundo plano cuando muestro una ventana emergente que es solo un diseño inflado que tengo, y no una actividad separada. ¿Cómo aplico FLAG_BLUR_BEHIND a una ventana emergente? –

4

he encontrado una solución para este

Crear un diálogo personalizado transparente y dentro de ese diálogo de 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 cuadro 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" /> 

ahora desea cerrar el cuadro de diálogo cuando se cierra la ventana emergente. por lo

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 plugin para crear PopupWindow aquí. También se puede hacer en ventanas emergentes nativas

94

La pregunta era sobre la clase Popupwindow, sin embargo, todos han dado respuestas que usan 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. Solo requiere que la raíz del archivo xml que utiliza para la actividad de fondo sea FrameLayout. Puede darle al elemento Framelayout una etiqueta android:foreground. 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 primer plano dibujable.

Puede utilizar cualquier recurso dibujable que desee, pero si solo desea un efecto de atenuación, cree un archivo xml en la carpeta dibujable con la etiqueta <shape> 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> 

(Ver http://developer.android.com/guide/topics/resources/drawable-resource.html#Shape para obtener más información sobre el elemento shape). Tenga en cuenta que no especifique un valor alfa en la etiqueta de color que haría que el elemento dibujable sea transparente (por ejemplo, #ff000000). La razón de esto es que cualquier valor alfa codificado parece anular cualquier valor alfa nuevo que establezcamos a través del setAlpha() en nuestro código, por lo que no queremos eso. Sin embargo, eso significa que el elemento dibujable será inicialmente opaco (sólido, no transparente). Entonces debemos hacerlo transparente en el método onCreate() de la actividad.

Aquí está el código de elementos 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á) 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); 
} 

Por último, el código para atenuar la actividad:

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

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

El los valores alfa van de 0 (opaco) a 255 (invisible). Debe atenuar la actividad cuando cierra la Ventana emergente.

no he incluido el código para mostrar y revocar al popupWindow, pero aquí hay un enlace a la forma en que se puede hacer: http://www.mobilemancer.com/2011/01/08/popup-window-in-android/

+0

para garantizar que esto funcione en dispositivos antiguos, también debe invalidar el primer plano después de cada cambio realizado en su canal alfa. Agregué esto a la respuesta. +1 por la buena respuesta – user2224350

+1

No puedo pensar en una razón por la que esto no esté marcado como la respuesta correcta ... respuesta increíble para decir lo menos. –

+2

¿Qué tal a la vista tiene la barra de acciones? No puede atenuarlo – BaDo

10

Otro truco es usar 2 ventanas emergentes en lugar de uno. La primera ventana emergente será simplemente una vista ficticia con fondo translúcido que proporciona el efecto tenue. La segunda ventana emergente es su ventana emergente prevista.

Secuencia al crear ventanas emergentes: Muestre la ventana emergente ficticia primero y luego la ventana emergente prevista.

Secuencia al destruir: Descartar la ventana emergente prevista 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 dummy:

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> 

FUNDIDO 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; 
} 
+0

Casi funciona para mí ... a veces, hay una condición de carrera donde la ventana emergente está detrás de la ventana emergente de dim/dummy.Aún no encontré una solución alternativa ... incluso demorar la aparición de la ventana emergente para darle tiempo al demorado no ayuda :-P – kenyee

+1

@kenyee He encontrado una solución para este problema. Primero muestro la ventana emergente 'fade' y luego, para mostrar la segunda ventana emergente, utilizo myFadePopup.getContentView(). Post (... myPopup.showAtLocation ...); – Piotr

24

en el archivo XML añadir algo como esto con un ancho y height 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 alcrear

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

Finalmente hacen visibles cuando muestre su popupWindow y crea su visible ido al salir popupWindow.

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

No deje firmas como "Gracias, Rupesh" en las publicaciones. –

+2

pero esto no atenuará la barra de herramientas/acciones. –

+0

Por favor, dígame cómo acción barra de herramientas dim – SAndroidD

52

Desde PopupWindow sólo se suma a una ViewWindowManager puede utilizar para actualizar el updateViewLayout (View view, ViewGroup.LayoutParams params)LayoutParams de sus PopupWindow 's contentView después de llamar espectáculo ..().

Establecer el indicador de ventana FLAG_DIM_BEHIND atenuará todo detrás de la ventana. Use dimAmount para controlar la cantidad de dim (1.0 para completamente opaco a 0.0 para no dim).

Tenga en cuenta que si establece un fondo en su PopupWindow, pondrá su contentView en un contenedor, lo que significa que debe actualizarlo.

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

Marshmallow Actualización:

En M PopupWindow envuelve el contentView dentro de un FrameLayout llama mDecorView. Si profundiza en el origen de PopupWindow, encontrará algo como createDecorView(View contentView). El objetivo principal de mDecorView es gestionar el envío de eventos y las transiciones de contenido, que son nuevos para M. Esto significa que necesitamos agregar uno más .getParent() para acceder al contenedor .

Con fondo que requeriría un cambio a algo como:

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

mejor alternativa para la API 18+

Una solución menos hacky usando ViewGroupOverlay:

1) Obtenga la distribución de 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(); 
} 
+1

Esto ya no parece funcionar en dispositivos con Android 6.0 Marshmallow. Los parámetros de diseño no se convierten en 'WindowManager.LayoutParams'. ¿Hay alguna solución? – Robert

+0

Gracias por señalarlo. No lo he probado en M todavía. Se actualizará lo antes posible. –

+0

gracias hombre. esta solución encajó perfectamente en mi código. –

-1

Este código de trabajo

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