Как устранить задержку перед анимацией LayoutTransition - PullRequest
10 голосов
/ 08 марта 2011

Я пробую новый класс LayoutTransition в сотах. Я установил анимацию, которая перемещает View на место при добавлении его к ViewGroup. Я заметил, что существует небольшая задержка (около 20 мс) между моментом, когда представление отображается впервые, и началом анимации LayoutTransition.APPEARING. Другими словами, после того, как вид появляется на экране, он на мгновение зависает в воздухе, а затем начинает анимироваться на месте. Вы можете заметить это даже в примере проекта ApiDemos. В примерах анимации макета всегда есть задержка до запуска анимации ViewGroup APPEARING. Я даже пытался установить другие LayoutTransition анимации на ноль или, наконец, дать им очень короткие промежутки времени, но анимация APPEARING все же задерживается. Вот мой код:

public class DebugExampleFour extends Activity {
    private int numButtons = 1;

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.debug_example_four);

        final ViewGroup frame = (ViewGroup) findViewById(R.id.frame_container);
        LayoutTransition transitioner = new LayoutTransition();

        Animator appearingAnimation = ObjectAnimator.ofFloat(null, "translationX", 600, 0);
        appearingAnimation.setDuration(45);
        appearingAnimation.setStartDelay(0);
        appearingAnimation.setInterpolator(new DecelerateInterpolator());
        appearingAnimation.addListener(new AnimatorListenerAdapter() {
            public void onAnimationEnd(Animator anim) {
                View view = (View) ((ObjectAnimator) anim).getTarget();
                view.setTranslationX(0f);
            }
        });
        transitioner.setAnimator(LayoutTransition.APPEARING, appearingAnimation);
        Animator dummyAnimation = ObjectAnimator.ofInt(0, 1);
        dummyAnimation.setDuration(1);
        dummyAnimation.setStartDelay(0);
        transitioner.setAnimator(LayoutTransition.CHANGE_APPEARING, dummyAnimation);
        transitioner.setAnimator(LayoutTransition.CHANGE_DISAPPEARING, dummyAnimation);
        transitioner.setAnimator(LayoutTransition.DISAPPEARING, dummyAnimation);

        frame.setLayoutTransition(transitioner);

        Button addButton = (Button) findViewById(R.id.addNewButton);
        addButton.setOnClickListener(new View.OnClickListener() {
            public void onClick(View v) {
                Button newButton = new Button(DebugExampleFour.this);
                newButton.setText("Click To Remove " + (numButtons++));
                newButton.setOnClickListener(new View.OnClickListener() {
                    public void onClick(View v) {
                        frame.removeView(v);
                    }
                });
                frame.addView(newButton, new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT));

            }
        });    
    }

}

Вот файл макета, который идет вместе с примером:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent" android:layout_height="match_parent"
    android:orientation="vertical">
    <Button android:layout_width="wrap_content"
        android:layout_height="wrap_content" android:text="Add Button"
        android:id="@+id/addNewButton" />
    <LinearLayout android:orientation="vertical"
        android:layout_width="match_parent" android:layout_height="match_parent"
        android:id="@+id/frame_container" android:animateLayoutChanges="true" />
</LinearLayout>

Как устранить задержку перед анимацией APPEARING?

Ответы [ 2 ]

28 голосов
/ 05 апреля 2011

Справа - задержка на обоих уровнях. Когда вы запускаете Animator в контексте LayoutTransition, вы хотите установить продолжительность и startDelay для объекта LayoutTransition, а не для базового Animator (поскольку объект перехода будет предоставлять свои собственные значения для этих свойств аниматорам, которые он работает).

Причина этого в том, что LayoutTransition обычно представляет собой последовательность анимаций, которые запускаются на объектах внутри контейнера. Так, например, если вы хотите, чтобы объект «появлялся» в контейнере, тогда переход сначала оживит другие объекты, а затем оживит новый объект на месте. Представьте себе, что вы добавляете элемент в середину набора объектов (как в случае, который вы видите в приложениях ApiDemos); сначала он создает пространство, а затем затухает в объекте.

В случае исходного кода, приведенного выше, вы хотите, чтобы появляющаяся анимация запускалась немедленно, поэтому вы должны установить для перехода startDelay для APPEARING значение 0 (как вы делали в ответе выше).

В противном случае анимации DISAPPEARING по умолчанию не имеют startDelay, но анимации CHANGE_DISAPPEARING имеют startDelay, равный длительности анимации DISAPPEARING, в предположении, что сначала вы хотите удалить элемент, а затем анимировать другие элементы в контейнер на свои новые места.

Поскольку эти предположения не обязательно применимы к каждой ситуации, в LayoutTransition есть свойства duration / startDelay для управления поведением в соответствии с тем, как оно должно работать в ваших конкретных случаях.

Обратите также внимание, что если вы не хотите запускать один из типов анимации, вам следует установить для этой анимации значение null (см. Документацию для LayoutTransition.setAnimator (int, Animator)). Установка его в ваш dummyAnimator не будет иметь тот же эффект. Во-первых, значения длительности / startDelay по умолчанию в LayoutTransition будут по-прежнему применяться, даже если для этих анимаций вы предоставляете пользовательские аниматоры.

Что еще нужно знать: базовый механизм синхронизации (для Android, а также для большинства других платформ, над которыми я когда-либо работал) будет иметь некоторое минимальное разрешение. Таким образом, вы устанавливаете длительность '1', что может не привести к тому, что анимация заканчивается 1 мс. Вместо этого он будет работать в течение одного кадра, затем в следующем кадре (как правило, частота обновления устройства в приложении с хорошим поведением, если система не зависает) он увидит, что анимация должна завершиться.

7 голосов
/ 10 марта 2011

Оказывается, что и Animator, и LayoutTransition каждый имеет значение задержки запуска.Задержка запуска Animator уже равна нулю, поэтому изменение не помогло.Что странно, так это то, что задержка запуска для LayoutTransition кажется больше нуля, по крайней мере, для случая LayoutTransition.APPEARING.Вот рабочий код:

public class DebugExampleFour extends Activity {
    private int numButtons = 1;

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.debug_example_four);

        final ViewGroup frame = (ViewGroup) findViewById(R.id.frame_container);
        LayoutTransition transitioner = new LayoutTransition();

        Animator appearingAnimation = ObjectAnimator.ofFloat(null, "translationX", 600, 0);
        appearingAnimation.addListener(new AnimatorListenerAdapter() {
            public void onAnimationEnd(Animator anim) {
                View view = (View) ((ObjectAnimator) anim).getTarget();
                view.setTranslationX(0f);
            }
        });
        transitioner.setAnimator(LayoutTransition.APPEARING, appearingAnimation);
        transitioner.setDuration(LayoutTransition.APPEARING, 300);
        transitioner.setStartDelay(LayoutTransition.APPEARING, 0);

        frame.setLayoutTransition(transitioner);

        Button addButton = (Button) findViewById(R.id.addNewButton);
        addButton.setOnClickListener(new View.OnClickListener() {
            public void onClick(View v) {
                Button newButton = new Button(DebugExampleFour.this);
                newButton.setText("Click To Remove " + (numButtons++));
                newButton.setOnClickListener(new View.OnClickListener() {
                    public void onClick(View v) {
                        frame.removeView(v);
                    }
                });
                frame.addView(newButton, new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT));

            }
        });    
    }
}
...