Mostrar DialogFragment con animación creciendo desde un punto

93

Muestro un DialogFragmentcuando el usuario toca una fila en un ListView. Me gustaría animar la visualización del diálogo para que crezca desde el centro de la fila. Se puede ver un efecto similar al abrir una carpeta desde el lanzador.

Una idea que tuve es una combinación de TranslateAnimationy ScaleAnimation. ¿Hay otra manera?

Edward Dale
fuente
1
Consulte el enlace para ver animaciones en DialogFragment.
ASH

Respuestas:

168

Al ser DialogFragmentun contenedor para la Dialogclase, debe establecer un tema en su base Dialogpara obtener la animación que desea:

public class CustomDialogFragment extends DialogFragment implements OnEditorActionListener
{
    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
        Bundle savedInstanceState) 
    {
        return super.onCreateView(inflater, container, savedInstanceState);
    }

    @Override
    public Dialog onCreateDialog(Bundle savedInstanceState) 
    {
        // Set a theme on the dialog builder constructor!
        AlertDialog.Builder builder = 
            new AlertDialog.Builder( getActivity(), R.style.MyCustomTheme );

        builder  
        .setTitle( "Your title" )
        .setMessage( "Your message" )
        .setPositiveButton( "OK" , new DialogInterface.OnClickListener() 
            {      
              @Override
              public void onClick(DialogInterface dialog, int which) {
              dismiss();                  
            }
        });
        return builder.create();
    }
}

Luego, solo necesita definir el tema que incluirá la animación deseada. En styles.xml agregue su tema personalizado:

<style name="MyCustomTheme" parent="@android:style/Theme.Panel">
    <item name="android:windowAnimationStyle">@style/MyAnimation.Window</item>
</style>

<style name="MyAnimation.Window" parent="@android:style/Animation.Activity"> 
    <item name="android:windowEnterAnimation">@anim/anim_in</item>
    <item name="android:windowExitAnimation">@anim/anim_out</item>
</style>    

Ahora agregue los archivos de animación en la carpeta res / anim :

(la android:pivotYes la clave)

anim_in.xml

<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android">
    <scale
        android:interpolator="@android:anim/linear_interpolator"
        android:fromXScale="0.0"
        android:toXScale="1.0"
        android:fromYScale="0.0"
        android:toYScale="1.0"
        android:fillAfter="false"
        android:startOffset="200"
        android:duration="200" 
        android:pivotX = "50%"
        android:pivotY = "-90%"
    />
    <translate
        android:fromYDelta="50%"
        android:toYDelta="0"
        android:startOffset="200"
        android:duration="200"
    />
</set>

anim_out.xml

<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android">
    <scale
        android:interpolator="@android:anim/linear_interpolator"
        android:fromXScale="1.0"
        android:toXScale="0.0"
        android:fromYScale="1.0"
        android:toYScale="0.0"
        android:fillAfter="false"
        android:duration="200" 
        android:pivotX = "50%"        
        android:pivotY = "-90%"        
    />
    <translate
        android:fromYDelta="0"
        android:toYDelta="50%"
        android:duration="200"
    />
</set>

Finalmente, lo complicado aquí es hacer que su animación crezca desde el centro de cada fila. Supongo que la fila está llenando la pantalla horizontalmente, por lo que, por un lado, el android:pivotXvalor será estático. Por otro lado, no puede modificar el android:pivotYvalor mediante programación.

Lo que sugiero es que defina varias animaciones, cada una de las cuales tiene un valor de porcentaje diferente en el android:pivotYatributo (y varios temas que hacen referencia a esas animaciones). Luego, cuando el usuario toque la fila, calcule la posición Y en porcentaje de la fila en la pantalla. Conociendo la posición en porcentaje, asigne un tema a su diálogo que tenga elandroid:pivotY valor .

No es una solución perfecta, pero podría ayudarte. Si no le gusta el resultado, le sugiero que se olvide DialogFragmenty anime un Viewcrecimiento simple desde el centro exacto de la fila.

¡Buena suerte!

Xavi Gil
fuente
Buena idea con las múltiples animaciones para diferentes ubicaciones en la pantalla. Es un truco, pero parece ser la única forma.
Edward Dale
Esto solo funcionará con> API 11 @Kiran Babu La respuesta es una solución alternativa
Blundell
¿Sabe si existe una forma posible de obtener una devolución de llamada cuando se completen estas animaciones? Me gustaría hacer una animación de 2 partes, una en la que se deslice el diálogo y luego desvanecer las vistas. ¿Cómo conectaría un oyente a windowAnimations?
android_student
¡Excelente! ¡Es exactamente lo que he buscado!
Aleksey Timoshchenko
2
Configurar el tema puede ser tan simple como hacerlo setStyle(DialogFragment.STYLE_NORMAL, R.style.MyCustomTheme)en onCreate(bundle)Ver: developer.android.com/reference/android/app/DialogFragment.html
tropicalfish
117

Mira este código, me funciona

// Deslice hacia arriba la animación

<?xml version="1.0" encoding="utf-8"?> <set xmlns:android="http://schemas.android.com/apk/res/android" >

    <translate
        android:duration="@android:integer/config_mediumAnimTime"
        android:fromYDelta="100%"
        android:interpolator="@android:anim/accelerate_interpolator"
        android:toXDelta="0" />

</set>

// Deslice la animación hacia abajo

<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android" >

    <translate
        android:duration="@android:integer/config_mediumAnimTime"
        android:fromYDelta="0%p"
        android:interpolator="@android:anim/accelerate_interpolator"
        android:toYDelta="100%p" />

</set>

// Estilo

<style name="DialogAnimation">
    <item name="android:windowEnterAnimation">@anim/slide_up</item>
    <item name="android:windowExitAnimation">@anim/slide_down</item>
</style>

// Fragmento de diálogo interior

@Override
public void onActivityCreated(Bundle arg0) {
    super.onActivityCreated(arg0);
    getDialog().getWindow()
    .getAttributes().windowAnimations = R.style.DialogAnimation;
}
Kiran Babu
fuente
8
Lo siento, esto no responde a mi pregunta en absoluto.
Edward Dale
3
Puede que esto no sea exactamente lo que pide el OP, pero creo que es un buen punto de entrada.
mdelolmo
2
¡Excelente ejemplo! La única muestra que funcionó para mí. El truco es establecer la animación / tema en el método onActivityCreated (...)
tomurka
3
Esto puede ser útil pero no responde la pregunta en absoluto.
Olayinka
¿Sabe si existe una forma posible de obtener una devolución de llamada cuando se completen estas animaciones? Me gustaría hacer una animación de 2 partes, una en la que se deslice el diálogo y luego desvanecer las vistas. ¿Cómo conectaría un oyente a windowAnimations?
android_student
22

DialogFragment tiene un método getTheme () público que puede anular por esta razón exacta. Esta solución usa menos líneas de código:

public class MyCustomDialogFragment extends DialogFragment{
    ...
    @Override
    public int getTheme() {
        return R.style.MyThemeWithCustomAnimation;
    }
}
Siavash
fuente
1
No más preocupaciones ... Solución simple y directa.
Noundla Sandeep
¡Esta es la mejor respuesta para mí!
superusuario
Si bien no está relacionado con la pregunta original, tenía una galería que se muestra en MainAcitvity donde el clic del usuario activará la presentación de diapositivas en DialogFragment. Sin embargo, hay una sacudida en MainActivity cada vez que regresa de la presentación de diapositivas. Esto se debe a que MainActivity usa AppTheme.NoActionBarmientras DialogFragment usa el valor predeterminado AppTheme. El método anterior resolvió mi problema al tener un tema consistente tanto en el fragmento como en la actividad.
tingyik90
Hermano, eres un genio
Jacky Chong
Esta solución funcionó para mí. Sin embargo, una cosa me confundió; configurar windowEnterAnimation o windowSalirAnimation directamente en el tema no haría ninguna diferencia en mis animaciones DialogFragments. Lo único que funcionó para mí fue configurar windowAnimationStyle en un archivo XML separado que definía el estilo y configurar las animaciones de entrada y salida allí
szaske
9

Para obtener un diálogo de pantalla completa con animación, escriba lo siguiente ...

Estilos:

<style name="AppTheme" parent="Theme.AppCompat.Light.DarkActionBar">
    <item name="colorPrimary">@color/colorPrimary</item>
    <item name="colorPrimaryDark">@color/colorPrimaryDark</item>
    <item name="colorAccent">@color/colorAccent</item>
    <item name="actionModeBackground">?attr/colorPrimary</item>
    <item name="windowActionModeOverlay">true</item>
</style>

<style name="AppTheme.NoActionBar">
    <item name="windowActionBar">false</item>
    <item name="windowNoTitle">true</item>
</style>

<style name="AppTheme.NoActionBar.FullScreenDialog">
    <item name="android:windowAnimationStyle">@style/Animation.WindowSlideUpDown</item>
</style>

<style name="Animation.WindowSlideUpDown" parent="@android:style/Animation.Activity">
    <item name="android:windowEnterAnimation">@anim/slide_up</item>
    <item name="android:windowExitAnimation">@anim/slide_down</item>
</style>

res / anim / slide_up.xml

<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android"
     android:shareInterpolator="@android:interpolator/accelerate_quad">

    <translate
        android:duration="@android:integer/config_shortAnimTime"
        android:fromYDelta="100%"
        android:toYDelta="0%"/>
</set>

res / anim / slide_down.xml

<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android"
     android:shareInterpolator="@android:interpolator/accelerate_quad">

    <translate
        android:duration="@android:integer/config_shortAnimTime"
        android:fromYDelta="0%"
        android:toYDelta="100%"/>
</set>

Código Java:

public class MyDialog extends DialogFragment {

    @Override
    public int getTheme() {
        return R.style.AppTheme_NoActionBar_FullScreenDialog;
    }
}

private void showDialog() {
    FragmentTransaction fragmentTransaction = getSupportFragmentManager().beginTransaction();
    Fragment previous = getSupportFragmentManager().findFragmentByTag(MyDialog.class.getName());
    if (previous != null) {
        fragmentTransaction.remove(previous);
    }
    fragmentTransaction.addToBackStack(null);

    MyDialog dialog = new MyDialog();
    dialog.show(fragmentTransaction, MyDialog.class.getName());
}
maXp
fuente
4

Use la vista de decoración dentro de onStart en su fragmento de diálogo

@Override
public void onStart() {
    super.onStart();


    final View decorView = getDialog()
            .getWindow()
            .getDecorView();

    decorView.animate().translationY(-100)
            .setStartDelay(300)
            .setDuration(300)
            .start();

}
Horacio
fuente
1
No parece que se pueda hacer clic en la vista subyacente después
HaydenKai
3

En DialogFragment, la animación personalizada se llama onCreateDialog. 'DialogAnimation' es un estilo de animación personalizado en la respuesta anterior.

public Dialog onCreateDialog(Bundle savedInstanceState) 
{
    final Dialog dialog = super.onCreateDialog(savedInstanceState);
    dialog.getWindow().getAttributes().windowAnimations = R.style.DialogAnimation;
    return dialog;
}
Brownsoo Han
fuente
1

¿Ha consultado la capacitación para desarrolladores de Android sobre cómo hacer zoom en una vista ? Podría ser un buen punto de partida.

Probablemente desee crear una clase personalizada que se extienda DialogFragmentpara que esto funcione.

Además, eche un vistazo a Jake Whartons NineOldAndroids para la compatibilidad de API de animación de nido de abeja hasta el nivel 1 de API.

greve
fuente
1

Si desea trabajar sobre API, debe hacerlo dentro de su DialogFragemnt-> onStart y no dentro de onCreateDialog

@Override
    public void onStart() 
    {
        if (getDialog() == null) 
        {
            return;
        }

        getDialog().getWindow().setWindowAnimations(
                  R.style.DlgAnimation);

        super.onStart();
    }
Colateral
fuente
La mejor solución en mi opinión. También funciona para AlertDialogs, solo utilícelo en onShowListener. ¡Gracias!
Gabor Novak
0

Agregue este código en valores anim

 <scale
    android:duration="@android:integer/config_longAnimTime"
    android:fromXScale="0.2"
    android:fromYScale="0.2"
    android:toXScale="1.0"
    android:toYScale="1.0"
    android:pivotX="50%"
    android:pivotY="50%"/>
<alpha
    android:fromAlpha="0.1"
    android:toAlpha="1.0"
    android:duration="@android:integer/config_longAnimTime"
    android:interpolator="@android:anim/accelerate_decelerate_interpolator"/>

llamar a styles.xml

<style name="DialogScale">
    <item name="android:windowEnterAnimation">@anim/scale_in</item>
    <item name="android:windowExitAnimation">@anim/scale_out</item>
</style>

En el código java: establecer Onclick

public void onClick(View v) {
        fab_onclick(R.style.DialogScale, "Scale" ,(Activity) context,getWindow().getDecorView().getRootView());
      //  Dialogs.fab_onclick(R.style.DialogScale, "Scale");

    }

configuración en método:

alertDialog.getWindow().getAttributes().windowAnimations = type;
Mue
fuente