Mostra DialogFragment con animazione che cresce da un punto


93

Sto mostrando un DialogFragmentquando l'utente tocca una riga in un file ListView. Vorrei animare la visualizzazione della finestra di dialogo in modo che cresca dal centro della riga. Un effetto simile può essere visto quando si apre una cartella dal programma di avvio.

Un'idea che ho avuto è una combinazione di TranslateAnimatione ScaleAnimation. C'è un altro modo?


1
Fare riferimento al collegamento per le animazioni su DialogFragment.
ASH

Risposte:


168

Essendo DialogFragmentun wrapper per la Dialogclasse, dovresti impostare un tema sulla tua base Dialogper ottenere l'animazione che desideri:

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

Quindi devi solo definire il tema che includerà l'animazione desiderata. In styles.xml aggiungi il tuo tema personalizzato:

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

Ora aggiungi i file di animazione nella cartella res / anim :

( android:pivotYè la chiave)

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>

Infine, la cosa difficile qui è far crescere la tua animazione dal centro di ogni riga. Suppongo che la riga riempia lo schermo orizzontalmente, quindi, da un lato, il android:pivotXvalore sarà statico. D'altra parte, non è possibile modificare il android:pivotYvalore a livello di codice.

Quello che suggerisco è che tu definisci diverse animazioni ognuna delle quali ha un diverso valore percentuale sull'attributo android:pivotY(e diversi temi che fanno riferimento a tali animazioni). Quindi, quando l'utente tocca la riga, calcola la posizione Y in percentuale della riga sullo schermo. Conoscendo la posizione in percentuale, assegna un tema al tuo dialogo che abbia il android:pivotYvalore appropriato .

Non è una soluzione perfetta ma potrebbe fare il trucco per te. Se non ti piace il risultato, ti suggerisco di dimenticare DialogFragmente animare una semplice Viewcrescita dal centro esatto della riga.

In bocca al lupo!


Buona idea con le animazioni multiple per diverse posizioni sullo schermo. È un trucco, ma sembra essere l'unico modo.
Edward Dale

Questo funzionerà solo con> API 11 @Kiran Babu La risposta è un lavoro intorno
Blundell

Sai se c'è un modo possibile per ottenere una richiamata quando queste animazioni sono state completate? Vorrei fare un'animazione in 2 parti, una in cui scorre la finestra di dialogo e poi dissolvenza nelle viste. Come attaccherei un ascoltatore a windowAnimations?
android_student

Eccellente! È esattamente quello che ho cercato!
Aleksey Timoshchenko

2
L'impostazione del tema può essere semplice come fare setStyle(DialogFragment.STYLE_NORMAL, R.style.MyCustomTheme)su onCreate(bundle)Vedi: developer.android.com/reference/android/app/DialogFragment.html
tropicalfish

117

Controlla questo codice, funziona per me

// Fai scorrere l'animazione verso l'alto

<?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>

// Slide dowm animation

<?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>

// Stile

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

// Frammento di dialogo interno

@Override
public void onActivityCreated(Bundle arg0) {
    super.onActivityCreated(arg0);
    getDialog().getWindow()
    .getAttributes().windowAnimations = R.style.DialogAnimation;
}

8
Spiacenti, questo non risponde affatto alla mia domanda.
Edward Dale

3
Questo potrebbe non essere esattamente ciò che chiede l'OP, ma è un buon punto di ingresso, credo.
mdelolmo

2
Ottimo esempio! L'unico campione che ha funzionato per me. Il trucco è impostare l'animazione / tema nel metodo onActivityCreated (...)
tomurka

3
Questo può essere utile ma non risponde affatto alla domanda.
Olayinka

Sai se esiste un modo per ottenere una richiamata quando queste animazioni sono state completate? Vorrei fare un'animazione in 2 parti, una in cui scorre la finestra di dialogo e poi dissolvenza delle viste. Come attaccherei un ascoltatore a windowAnimations?
android_student

22

DialogFragment ha un metodo pubblico getTheme () che puoi sovrascrivere per questo motivo esatto. Questa soluzione utilizza meno righe di codice:

public class MyCustomDialogFragment extends DialogFragment{
    ...
    @Override
    public int getTheme() {
        return R.style.MyThemeWithCustomAnimation;
    }
}

1
Niente più preoccupazioni ... Soluzione semplice e diretta.
Noundla Sandeep

Questa è la migliore risposta per me!
superuser

Sebbene non sia correlato alla domanda originale, avevo una galleria mostrata in MainAcitvity in cui il clic dell'utente attiverà la presentazione in DialogFragment. Tuttavia, ogni volta che si torna dalla presentazione, c'è uno scatto in MainActivity. Ciò è dovuto al fatto che MainActivity utilizza AppTheme.NoActionBarmentre DialogFragment utilizza l'impostazione predefinita AppTheme. Il metodo sopra ha risolto il mio problema avendo un tema coerente sia nel frammento che nell'attività.
tingyik90

Fratello, sei un genio
Jacky Chong

Questa soluzione ha funzionato per me. Tuttavia una cosa mi ha confuso; l'impostazione windowEnterAnimation o windowExitAnimation direttamente nel tema non farebbe differenza nelle mie animazioni DialogFragments. L'unica cosa che ha funzionato per me è stata l'impostazione di windowAnimationStyle su un file XML separato che definiva lo stile e l'impostazione delle animazioni di entrata e uscita lì
szaske

9

Per ottenere una finestra di dialogo a schermo intero con animazione, scrivi quanto segue ...

Stili:

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

Codice 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());
}

4

Usa la vista decoro all'interno di onStart nel frammento di dialogo

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


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

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

}

1
La visualizzazione sottostante non sembra essere cliccabile in seguito
HaydenKai

3

In DialogFragment, l'animazione personalizzata viene chiamata onCreateDialog. "DialogAnimation" è lo stile di animazione personalizzato nella risposta precedente.

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

1

Hai esaminato la formazione per sviluppatori Android sullo zoom di una vista ? Potrebbe essere un buon punto di partenza.

Probabilmente vorrai creare una classe personalizzata che si estenda DialogFragmentper farlo funzionare.

Inoltre, dai un'occhiata a Jake Whartons NineOldAndroids per la compatibilità con l'API Honeycomb Animation fino al livello API 1.


1

Se vuoi lavorare sulle API devi farlo all'interno del tuo DialogFragemnt-> onStart e non all'interno di onCreateDialog

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

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

        super.onStart();
    }

La migliore soluzione secondo me. Funziona anche per AlertDialogs, basta usarlo in onShowListener. Grazie!
Gabor Novak

0

Aggiungi questo codice sui valori 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"/>

chiama styles.xml

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

Sul codice java: imposta Onclick

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

    }

impostazione sul metodo:

alertDialog.getWindow().getAttributes().windowAnimations = type;
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.