Pokaż DialogFragment z animacją rosnącą od punktu

94

Wyświetlam, DialogFragmentgdy użytkownik dotyka wiersza w a ListView. Chciałbym ożywić wyświetlanie okna dialogowego, aby rosło od środka wiersza. Podobny efekt można zobaczyć podczas otwierania folderu z programu uruchamiającego.

Jeden pomysł, który miałem, to połączenie TranslateAnimationi ScaleAnimation. Czy jest inny sposób?

Edward Dale
źródło
1
Skorzystaj z łącza do animacji w DialogFragment.
ASH

Odpowiedzi:

170

Będąc DialogFragmentopakowaniem dla Dialogklasy, powinieneś ustawić motyw do swojej bazy, Dialogaby uzyskać pożądaną animację:

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

Następnie wystarczy zdefiniować motyw, który będzie zawierał żądaną animację. W styles.xml dodaj własny motyw:

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

Teraz dodaj pliki animacji w folderze res / anim :

(to android:pivotYjest klucz)

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>

Wreszcie, najtrudniejsze jest to, aby animacja rosła od środka każdego rzędu. Przypuszczam, że wiersz wypełnia ekran w poziomie, więc z jednej strony android:pivotXwartość będzie statyczna. Z drugiej strony nie można android:pivotYprogramowo modyfikować wartości.

Sugeruję, aby zdefiniować kilka animacji, z których każda ma inną wartość procentową android:pivotYatrybutu (i kilka motywów odnoszących się do tych animacji). Następnie, gdy użytkownik dotknie wiersza, oblicz pozycję Y w procentach wiersza na ekranie. Znając pozycję w procentach, przypisz temat do swojego okna dialogowego, który ma odpowiednią android:pivotYwartość.

Nie jest to idealne rozwiązanie, ale może załatwić sprawę. Jeśli nie podoba ci się wynik, proponuję zapomnieć DialogFragmenti ożywić prosty Viewwzrost z dokładnego środka rzędu.

Powodzenia!

Xavi Gil
źródło
Dobry pomysł z wieloma animacjami dla różnych lokalizacji na ekranie. To hack, ale wydaje się, że to jedyny sposób.
Edward Dale
To będzie działać tylko z> API 11 @Kiran Babu, odpowiedź jest obejściem
Blundell
Czy wiesz, czy istnieje możliwość uzyskania oddzwonienia po zakończeniu tych animacji? Chciałbym zrobić dwuczęściową animację, taką, w której wsuwa się okno dialogowe, a następnie zacienia się widoki. Jak dołączyć słuchacza do okna animacje?
android_student
Doskonały! Właśnie tego szukałem!
Aleksey Timoshchenko
2
Ustawienie motywu może być tak proste, jak zrobienie tego setStyle(DialogFragment.STYLE_NORMAL, R.style.MyCustomTheme)na stronie onCreate(bundle)See: developer.android.com/reference/android/app/DialogFragment.html
tropicalfish
121

Sprawdź ten kod, to działa dla mnie

// Animacja w górę

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

// Animacja slajdów

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

// Styl

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

// Fragment wewnętrznego okna dialogowego

@Override
public void onActivityCreated(Bundle arg0) {
    super.onActivityCreated(arg0);
    getDialog().getWindow()
    .getAttributes().windowAnimations = R.style.DialogAnimation;
}
Kiran Babu
źródło
8
Przepraszam, to w ogóle nie odpowiada na moje pytanie.
Edward Dale,
3
To może nie być dokładnie to, o co prosi OP, ale myślę, że jest to dobry punkt wyjścia.
mdelolmo,
2
Doskonały przykład! Jedyna próbka, która działała dla mnie. Sztuczka polega na tym, aby ustawić animację / motyw w metodzie onActivityCreated (...)
tomurka
3
Może to być przydatne, ale w ogóle nie odpowiada na pytanie.
Olayinka
Czy wiesz, czy istnieje możliwość uzyskania oddzwonienia po zakończeniu tych animacji? Chciałbym zrobić dwuczęściową animację, taką, w której wsuwa się okno dialogowe, a następnie zacienia się widoki. Jak dołączyć słuchacza do okna animacje?
android_student
22

DialogFragment ma publiczną metodę getTheme (), którą można zmienić z tego powodu. To rozwiązanie wykorzystuje mniej wierszy kodu:

public class MyCustomDialogFragment extends DialogFragment{
    ...
    @Override
    public int getTheme() {
        return R.style.MyThemeWithCustomAnimation;
    }
}
Siavash
źródło
1
Nigdy więcej zmartwień ... Proste i proste rozwiązanie.
Noundla Sandeep
To dla mnie najlepsza odpowiedź!
superuser
Chociaż nie było to związane z pierwotnym pytaniem, miałem galerię pokazaną w MainAcitvity, w której kliknięcie użytkownika aktywuje pokaz slajdów w DialogFragment. Jednak przy każdym powrocie z pokazu slajdów w MainActivity występuje szarpnięcie. Wynika to z używania MainActivity, AppTheme.NoActionBargdy DialogFragment używa domyślnej AppTheme. Powyższa metoda rozwiązała mój problem, mając spójny temat zarówno w fragmencie, jak i działaniu.
tingyik90
Bracie, jesteś geniuszem
Jacky Chong
To rozwiązanie zadziałało dla mnie. Jednak jedna rzecz mnie zdezorientowała; ustawienie windowEnterAnimation lub windowExitAnimation bezpośrednio w motywie nie wpłynie na moje animacje DialogFragments. Jedyne, co działało, to ustawienie windowAnimationStyle na osobny plik XML, który definiował styl i ustawienie tam animacji wejścia i wyjścia
szaske
10

Aby uzyskać pełnoekranowe okno dialogowe z animacją, napisz ...

Style:

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

Kod 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
źródło
4

Użyj widoku dekoru wewnątrz onStart w swoim fragmencie okna dialogowego

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


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

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

}
Horatio
źródło
1
Widok znajdujący się pod spodem nie wydaje się być później klikalny
HaydenKai
3

W DialogFragment animacja niestandardowa nosi nazwę onCreateDialog. „DialogAnimation” to niestandardowy styl animacji w poprzedniej odpowiedzi.

public Dialog onCreateDialog(Bundle savedInstanceState) 
{
    final Dialog dialog = super.onCreateDialog(savedInstanceState);
    dialog.getWindow().getAttributes().windowAnimations = R.style.DialogAnimation;
    return dialog;
}
Brownsoo Han
źródło
1

Czy obejrzałeś szkolenie dla programistów Androida na temat powiększania widoku ? To może być dobry punkt wyjścia.

Prawdopodobnie chcesz utworzyć rozszerzającą klasę niestandardową DialogFragment aby ta działała.

Przyjrzyj się również Jake Whartons NineOldAndroids pod kątem zgodności z interfejsem API Honeycomb Animation aż do poziomu API 1.

greve
źródło
1

Jeśli chcesz pracować nad interfejsami API, musisz to zrobić w swoim DialogFragemnt-> onStart, a nie w onCreateDialog

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

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

        super.onStart();
    }
Boczne
źródło
Najlepsze moim zdaniem rozwiązanie. Działa również dla AlertDialogs, po prostu użyj go w onShowListener. Dzięki!
Gabor Novak
0

Dodaj ten kod do wartości 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"/>

zadzwoń na styles.xml

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

W kodzie java: ustaw Onclick

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

    }

konfiguracja według metody:

alertDialog.getWindow().getAttributes().windowAnimations = type;
Mue
źródło