Подтвердить что ты не робот

Сохранить анимационный просмотр в финальной анимационной позиции

Итак, я оживляю вид с использованием анимации:

<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android"
    android:interpolator="@android:anim/accelerate_interpolator" >

    <translate
        android:duration="1000"
        android:fromYDelta="0%"
        android:toYDelta="-75%" />

</set>

Это визуально то, что я хочу, но я также хочу заморозить результат этой анимации. Как мне нужно как-то получить результирующие параметры макета (или что-то еще?) После анимации и установить его в макет. Предположим, что Y-координата меняется от 0 до 100, но я действительно не знаю, что начиналось с коордов и в результате были созданы коорды. Мне нужно получить результирующие координаты и установить его в макет, потому что если бы не сделать, макет вернется в исходное положение после анимации, но мне нужно заставить его остаться в новой позиции, а не возвращаться обратно. Также мне нужно решение 2.3.x.
ОБНОВЛЕНИЕ 1
Я также попробовал NineOldAndroids:

ObjectAnimator.ofFloat(rootWrapper, "translationY", -rootWrapper.getHeight()*75/100).start();

это оживляет вид и просмотр остается на анимированной позиции - именно этого я и хочу достичь.
Однако все элементы управления практически находятся на своих позициях. Даже ваш макет отображается только на 25% его нижней части, а 75% экрана останова выглядит пустым, если я коснусь этой пустой области экрана, а затем кнопки (которая была там b4-анимация) onClick. То же самое происходит с xml-animaions, если установлено

animation.setFillAfter(true); 

Как исправить эту проблему? Все элементы управления должны перемещаться с видом.
ОБНОВЛЕНИЕ 2
Код:

    public void showAbout(){

        final Animation animShow = AnimationUtils.loadAnimation(this, R.anim.about_in_from_bottom);
        animShow.setFillAfter(true); 

        //ObjectAnimator.ofFloat(rootWrapper, "translationY", -rootWrapper.getHeight()*75/100).start();

        animShow.setAnimationListener(new AnimationListener() {

            @Override
            public void onAnimationStart(Animation animation) {
            }

            @Override
            public void onAnimationRepeat(Animation animation) {}

            @Override
            public void onAnimationEnd(Animation animation) {
                LinearLayout.LayoutParams rootlp = (LinearLayout.LayoutParams) rootWrapper.getLayoutParams();
                Log.i(this,"rootlp: h: "+rootlp.topMargin+ " / w: "+rootlp.bottomMargin);
                rootlp.topMargin = -rootlp.height*75/100;
                rootWrapper.setLayoutParams(rootlp);
            }
        });

        rootWrapper.startAnimation(animShow);
    }

У меня возникла проблема - rootlp.height возвращает 0, потому что это похоже на MATCH_PARENT или подобное. Он не вернет РЕАЛЬНЫЕ пиксели, а некоторое значение, представляющее некоторую константу! Так что, похоже, у меня 2 игры с .getViewTreeObserver().addOnGlobalLayoutListener.
Хорошо, я получил реальную высоту rootWrapper через getViewTreeObserver(). И теперь, используя формулу rootlp.topMargin = -rootlp.height*75/100;, я получаю еще больше проблем.
1) После анимации View перемещается вверх (из-за установки LP).
2) Элементы управления, которые поддерживает анимированный вид (кнопки, которые должны перемещаться вверх с родительским представлением) остаются на своих позициях практически (они невидимы, но доступны для кликов)! Визуально эти элементы управления перемещаются вверх с анимированным представлением, и я не могу его достичь (он отключается от экрана). Но если я коснусь области, где они были до анимации, соответствующие триггеры onClick()! Какая радость!
ОБНОВЛЕНИЕ 3
Наконец, я достиг своей цели! Проблема заключалась в перемещении дочерних контейнеров View. Я думал, что если я переведу некоторый вид, все его детские представления также будут перемещаться. Но это не так, и мне пришлось перемещать дочерние представления вручную после завершения анимации, чтобы исправить призрачные кнопки.

4b9b3361

Ответ 1

Пожалуйста, рассмотрите setFillAfter (boolean);, установив его в true, сделайте просмотр в анимированной позиции.

Animation anim = new TranslateAnimation(0, 0, 0, 100);

// or like this
Animation anim = AnimationUtils.loadAnimation(this, R.anim.animation_name);

anim.setFillAfter(true); 
anim.setDuration(1000);

Это можно сделать еще проще, используя ViewPropertyAnimator, доступный из API 14 и далее:

int animationpos = 500;
View.animate().y(animationpos).setDuration(1000); // this will also keep the view at the animated position

Или рассмотрите AnimationListener, чтобы получить LayoutParams именно после анимации:

anim.setAnimationListener(new AnimationListener() {

            @Override
            public void onAnimationStart(Animation animation) {}

            @Override
            public void onAnimationRepeat(Animation animation) {}

            @Override
            public void onAnimationEnd(Animation animation) {
                  // get layoutparams here and set it in this example your views 
                  // parent is a relative layout, please change that to your desires

                  RelativeLayout.LayoutParams lp = (RelativeLayout.LayoutParams) View.getLayoutParams();
                  lp.topMargin = yournewtopmargin // use topmargin for the y-property, left margin for the x-property of your view
                  View.setLayoutParams(lp);
                }
            });

    View.startAnimation(anim);

UPDATE:

Как узнать, сколько пикселей перемещено в зависимости от процентные значения анимации?

Процентное значение в вашей анимации .xml относится к анимированным размерам View (например, ширине и высоте). Поэтому вам просто нужно использовать ваши свойства ширины и высоты просмотра (в зависимости от погоды u используйте x или y анимацию, чтобы получить фактическое расстояние анимации в пикселях).

Например:

Ваш вид имеет ширину 400 пикселей. Ваша анимация оживляет x-свойство от 0% до 75%, что означает, что ваше представление будет перемещать 300 пикселей (400 * 0,75) в правую сторону. Итак, onAnimationEnd(), установите LayoutParams.leftMargin в 300, и ваш View будет иметь нужную позицию.

Ответ 2

Я нахожу, что просто установка fillEnabled и fillAfter в TRUE не решает проблему, когда речь идет о таких вещах, как клики/клики. Настройка заливки включена и заполняется после того, как она верна, просто гарантирует, что пиксели представления будут DRAWN в правильном конечном месте. Однако предположим, что анимация вида имеет связанный с ней прослушиватель onclick. Щелчок на представлении в его новой видимой позиции ничего не сделает, однако щелчок по экрану в позиции, изначально изначально вызывающей функцию onClick.

Ниже приведен пример того, как обойти это:

Предположим, что у нас есть представление с установленным в нем набором onClickListener. Предположим также, что границы представлений равны 0, 0, 0, 0 (слева, сверху, справа, внизу). Предположим, что теперь мы хотим переместить представление вправо на 200. Следующий код продемонстрирует, как сделать это таким образом, который будет перемещать как пиксели, подлежащие рисованию, так и основной объект представления в правильное положение, следовательно, корректировка onClick для вызывать из правильного положения.

private Animation generateMoveRightAnimation() {
    final Animation animation = new TranslateAnimation(Animation.ABSOLUTE, 0, Animation.ABSOLUTE, 200,
            Animation.ABSOLUTE, 0, Animation.ABSOLUTE, 0);
    animation.setDuration(300);
    animation.setFillAfter(true);
    animation.setFillEnabled(true);

    animation.setAnimationListener(new Animation.AnimationListener() {
        @Override
        public void onAnimationStart(Animation animation) {

        }

        @Override
        public void onAnimationEnd(Animation animation) {
            RelativeLayout.LayoutParams lp = (RelativeLayout.LayoutParams) view.getLayoutParams();
            // change the coordinates of the view object itself so that on click listener reacts to new position
            view.layout(view.getLeft()+200, view.getTop(), view.getRight()+200, view.getBottom());
            repeatLevelSwitch.clearAnimation();
        }

        @Override
        public void onAnimationRepeat(Animation animation) {

        }
    });

    return animation;
}

Ответ 3

Вы можете использовать NineOldAndroid прокси-библиотеку для использования ObjectAnimator по вашему желанию. он поддерживает более низкие уровни api и использует собственную библиотеку для новых уровней api.

Просто импортируйте как LibraryProject, и все будет хорошо.