Mostrar DialogFragment com animação crescendo a partir de um ponto

93

Estou mostrando um DialogFragmentquando o usuário toca em uma linha em a ListView. Gostaria de animar a exibição do diálogo para que cresça a partir do centro da linha. Um efeito semelhante pode ser visto ao abrir uma pasta no inicializador.

Uma ideia que tive é uma combinação de TranslateAnimatione ScaleAnimation. Existe outra maneira?

Edward Dale
fonte
1
Consulte o link para animações em DialogFragment.
ASH

Respostas:

168

Sendo DialogFragmentum wrapper para a Dialogclasse, você deve definir um tema para sua base Dialogpara obter a animação desejada:

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

Depois, basta definir o tema que incluirá a animação desejada. Em styles.xml, adicione seu 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>    

Agora adicione os arquivos de animação na pasta res / anim :

( android:pivotYé a chave)

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, o complicado aqui é fazer a animação crescer a partir do centro de cada linha. Suponho que a linha está preenchendo a tela horizontalmente, então, por um lado, o android:pivotXvalor será estático. Por outro lado, você não pode modificar o android:pivotYvalor programaticamente.

O que eu sugiro é que você defina várias animações, cada uma com um valor percentual diferente no android:pivotYatributo (e vários temas fazendo referência a essas animações). Então, quando o usuário tocar na linha, calcule a posição Y em porcentagem da linha na tela. Sabendo a posição em porcentagem, atribua um tema ao seu diálogo que tenha o android:pivotYvalor apropriado .

Não é uma solução perfeita, mas pode fazer o truque para você. Se você não gostar do resultado, sugiro que esqueça DialogFragmentoe anime um Viewcrescimento simples do centro exato da linha.

Boa sorte!

Xavi Gil
fonte
Boa ideia com as várias animações para diferentes locais na tela. É um hack, mas parece ser o único caminho.
Edward Dale
Isso só funcionará com> API 11 @Kiran Babu A resposta é uma solução alternativa
Blundell
Você sabe se existe uma maneira possível de obter um retorno de chamada quando essas animações forem concluídas? Eu gostaria de fazer uma animação de 2 partes, uma em que a caixa de diálogo deslize para dentro e, em seguida, esmaeça as visualizações. Como eu conectaria um ouvinte para windowAnimations?
android_student
Excelente! É exatamente o que tenho procurado!
Aleksey Timoshchenko
2
Definir o tema pode ser tão simples quanto fazer setStyle(DialogFragment.STYLE_NORMAL, R.style.MyCustomTheme)em onCreate(bundle)Consulte: developer.android.com/reference/android/app/DialogFragment.html
tropicalfish
117

Veja este código, funciona para mim

// Animação deslizante

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

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

@Override
public void onActivityCreated(Bundle arg0) {
    super.onActivityCreated(arg0);
    getDialog().getWindow()
    .getAttributes().windowAnimations = R.style.DialogAnimation;
}
Kiran Babu
fonte
8
Desculpe, isso não responde minha pergunta de forma alguma.
Edward Dale,
3
Isso pode não ser exatamente o que o OP está pedindo, mas é um bom ponto de entrada, eu acho.
mdelolmo
2
Excelente exemplo! A única amostra que funcionou para mim. O truque é definir animação / tema no método onActivityCreated (...)
tomurka 01 de
3
Isso pode ser útil, mas não responde à pergunta de forma alguma.
Olayinka de
Você sabe se existe uma maneira possível de obter um retorno de chamada quando essas animações forem concluídas? Eu gostaria de fazer uma animação em 2 partes, uma em que a caixa de diálogo deslize para dentro e, em seguida, esmaeça as visualizações. Como eu conectaria um ouvinte para a janelaAnimações?
android_student
22

DialogFragment tem um método getTheme () público que você pode substituir por este motivo exato. Esta solução usa menos linhas de código:

public class MyCustomDialogFragment extends DialogFragment{
    ...
    @Override
    public int getTheme() {
        return R.style.MyThemeWithCustomAnimation;
    }
}
Siavash
fonte
1
Não se preocupe mais ... Solução simples e direta.
Noundla Sandeep
Esta é a melhor resposta para mim!
superusuário
Embora não esteja relacionado à pergunta original, mostrei uma galeria em MainAcitvity onde o clique do usuário irá ativar a apresentação de slides em DialogFragment. No entanto, há um solavanco na MainActivity sempre que retornar da apresentação de slides. Isso se deve ao uso de MainActivity, AppTheme.NoActionBarenquanto DialogFragment está usando o padrão AppTheme. O método acima resolveu meu problema por ter um tema consistente tanto no fragmento quanto na atividade.
tingyik90
Mano, você é um gênio
Jacky Chong
Essa solução funcionou para mim. No entanto, uma coisa me confundiu; definir windowEnterAnimation ou windowExitAnimation diretamente no tema não faria diferença nas minhas animações DialogFragments. A única coisa que funcionou para mim foi definir windowAnimationStyle para um arquivo XML separado que definiu o estilo e definir as animações de entrada e saída lá
szaske
9

Para obter uma caixa de diálogo em tela inteira com animação, escreva o seguinte ...

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

Use a visualização de decoração dentro de onStart em seu 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();

}
Horatio
fonte
1
A visualização subjacente não parece ser clicável posteriormente
HaydenKai
3

Em DialogFragment, a animação personalizada é chamada onCreateDialog. 'DialogAnimation' é o estilo de animação personalizado na resposta anterior.

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

Você já olhou para Android Developers Training on Zooming a View ? Pode ser um bom ponto de partida.

Você provavelmente deseja criar uma extensão de classe personalizada DialogFragmentpara fazer isso funcionar.

Além disso, dê uma olhada na compatibilidade da API Jake Whartons NineOldAndroids for Honeycomb Animation desde o nível 1 da API.

greve
fonte
1

Se você quiser trabalhar em APIs, você deve fazer dentro de seu DialogFragemnt-> onStart e não dentro de onCreateDialog

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

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

        super.onStart();
    }
Colateral
fonte
Melhor solução na minha opinião. Ele funciona para AlertDialogs também, basta usá-lo no onShowListener. Obrigado!
Gabor Novak
0

Adicione este código aos 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"/>

chamar styles.xml

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

No código java: set Onclick

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

    }

configuração no método:

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