Показать DialogFragment с ростом анимации от точки

94

Я показываю, DialogFragmentкогда пользователь нажимает строку в ListView. Я бы хотел оживить показ диалога так, чтобы он увеличивался из центра строки. Подобный эффект можно увидеть при открытии папки из лаунчера.

Одна идея, которая у меня возникла, - это комбинация TranslateAnimationи ScaleAnimation. Есть другой способ?

Эдвард Дейл
источник
1
См. Ссылку для анимации на DialogFragment.
ASH

Ответы:

171

Будучи DialogFragmentоболочкой для Dialogкласса, вы должны установить тему для своей базы, Dialogчтобы получить желаемую анимацию:

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

Затем вам просто нужно определить тему, которая будет включать желаемую анимацию. В styles.xml добавьте свою собственную тему:

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

Теперь добавьте файлы анимации в папку res / anim :

( android:pivotYэто ключ)

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>

Наконец, самая сложная вещь - заставить вашу анимацию расти из центра каждой строки. Я предполагаю, что строка заполняет экран по горизонтали, поэтому, с одной стороны, android:pivotXзначение будет статическим. С другой стороны, вы не можете изменить android:pivotYзначение программно.

Я предлагаю вам определить несколько анимаций, каждая из которых имеет разное процентное значение android:pivotYатрибута (и несколько тем, ссылающихся на эти анимации). Затем, когда пользователь касается строки, вычислите позицию Y в процентах от строки на экране. Зная положение в процентах, назначьте своему диалогу тему, имеющую соответствующее android:pivotYзначение.

Это не идеальное решение, но оно может помочь вам. Если вам не нравится результат, я бы посоветовал забыть DialogFragmentи анимировать простой Viewрост от точного центра ряда.

Удачи!

Хави Гил
источник
Хорошая идея с множеством анимаций для разных мест на экране. Это взлом, но, кажется, единственный выход.
Эдвард Дейл
Это будет работать только с> API 11 @ Ответ Кирана Бабу - это обходной путь
Бланделл
Знаете ли вы, есть ли способ получить обратный вызов, когда эти анимации будут завершены? Я хотел бы сделать анимацию из двух частей, в которой диалоговое окно вставляется, а затем постепенно появляются представления. Как мне прикрепить слушателя к windowAnimations?
android_student
Отлично! Это именно то, что я искал!
Алексей Тимощенко
2
Установить тему так же просто, как это сделать setStyle(DialogFragment.STYLE_NORMAL, R.style.MyCustomTheme)на onCreate(bundle)См .: developer.android.com/reference/android/app/DialogFragment.html
tropicalfish
121

Проверьте этот код, он работает для меня

// Анимация скольжения вверх

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

// Слайд-анимация

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

// Стиль

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

// Фрагмент внутреннего диалога

@Override
public void onActivityCreated(Bundle arg0) {
    super.onActivityCreated(arg0);
    getDialog().getWindow()
    .getAttributes().windowAnimations = R.style.DialogAnimation;
}
Киран Бабу
источник
8
Извините, это вообще не отвечает на мой вопрос.
Эдвард Дейл
3
Возможно, это не совсем то, о чем просит OP, но я думаю, это хорошая отправная точка.
mdelolmo
2
Отличный пример! Единственный образец, который у меня сработал. Уловка заключается в том, чтобы установить анимацию / тему в методе onActivityCreated (...)
tomurka 01
3
Это может быть полезно, но совсем не отвечает на вопрос.
Olayinka
Знаете ли вы, есть ли способ получить обратный вызов, когда эти анимации будут завершены? Я хотел бы сделать анимацию из двух частей, в которой диалоговое окно вставляется внутрь, а затем постепенно появляются представления. Как мне прикрепить слушателя к windowAnimations?
android_student
22

DialogFragment имеет общедоступный метод getTheme (), который вы можете игнорировать именно по этой причине. В этом решении используется меньше строк кода:

public class MyCustomDialogFragment extends DialogFragment{
    ...
    @Override
    public int getTheme() {
        return R.style.MyThemeWithCustomAnimation;
    }
}
Сиаваш
источник
1
Больше никаких забот ... Простое и понятное решение.
Нундла Сандип
Это лучший ответ для меня!
superuser
Хотя это не связано с исходным вопросом, у меня была галерея, показанная в MainAcitvity, где щелчок пользователя активирует слайд-шоу в DialogFragment. Однако при возврате из слайд-шоу в MainActivity возникает рывок. Это связано с использованием MainActivity, в AppTheme.NoActionBarто время как DialogFragment использует значение по умолчанию AppTheme. Вышеупомянутый метод решил мою проблему, имея согласованную тему как во фрагменте, так и в действии.
tingyik90
Братан, ты гений
Джеки Чонг
Это решение сработало для меня. Однако меня смущало одно; установка windowEnterAnimation или windowExitAnimation непосредственно в теме не повлияет на мои анимации DialogFragments. Единственное, что сработало для меня, - это установить windowAnimationStyle в отдельный XML-файл, который определил стиль и установил там анимацию входа и выхода
szaske
10

Чтобы получить полноэкранный диалог с анимацией, напишите следующее ...

Стили:

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

Код 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
источник
4

Используйте вид декора внутри onStart во фрагменте диалога

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


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

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

}
Горацио
источник
1
Основной вид, кажется, не может быть кликабельным после этого
HaydenKai
3

В DialogFragment настраиваемая анимация вызывается onCreateDialog. DialogAnimation - это пользовательский стиль анимации в предыдущем ответе.

public Dialog onCreateDialog(Bundle savedInstanceState) 
{
    final Dialog dialog = super.onCreateDialog(savedInstanceState);
    dialog.getWindow().getAttributes().windowAnimations = R.style.DialogAnimation;
    return dialog;
}
Браунсу Хан
источник
1

Вы смотрели тренинг для разработчиков Android по изменению масштаба изображения ? Может быть хорошей отправной точкой.

Вы, вероятно, захотите создать собственный класс, расширяющийся, DialogFragmentчтобы это работало.

Кроме того, взгляните на Jake Whartons NineOldAndroids для совместимости с API-интерфейсом Honeycomb Animation вплоть до уровня API 1.

Greve
источник
1

Если вы хотите работать с API, вы должны делать это внутри DialogFragemnt-> onStart, а не внутри onCreateDialog

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

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

        super.onStart();
    }
Боковой
источник
На мой взгляд, лучшее решение. Он также работает для AlertDialogs, просто используйте его в onShowListener. Благодарность!
Габор Новак
0

Добавьте этот код в значения 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"/>

вызовите styles.xml

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

В коде Java: установите Onclick

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

    }

настройка по методу:

alertDialog.getWindow().getAttributes().windowAnimations = type;
Муэ
источник