Android TranslateAnimation сбрасывается после анимации

Я создаю нечто вроде SlideDrawer, но с большинством настроек, в основном это работает, но анимация мелькает в конце.

Чтобы пояснить, я получил TranslateAnimation, после этой анимации он возвращается в исходную позицию, если я устанавливаю setFillAfter, тогда кнопки внутри макета перестают работать. Если я слушаю onAnimationEnd и устанавливаю другой макет в View.GONE, то макет раскладывается. Судя по тому, что на конце анимации представление возвращается в исходное положение до вызова View.GONE.

Любые советы были бы замечательными. Благодаря

Ответ 1

Вот фактическая ошибка, связанная с этой проблемой http://code.google.com/p/android-misc-widgets/issues/detail?id=8

В основном это означает, что метод onAnimationEnd не работает хорошо, когда AnimationListener подключен к анимации

Обходной путь заключается в прослушивании событий анимации в представлении, к которому вы применяли анимацию. Например, если изначально вы добавляли слушателя анимации к анимации, подобной этой

mAnimation.setAnimationListener(new AnimationListener() {
    @Override
    public void onAnimationEnd(Animation arg0) {
                       //Functionality here
    }

а затем применительно к анимации к ImageView, подобному этому

mImageView.startAnimation(mAnimation);

Чтобы обойти эту проблему, вы должны теперь создать собственный ImageView

public Class myImageView extends ImageView {

а затем переопределить метод onAnimationEnd класса View и предоставить всю функциональность там

@Override
protected void onAnimationEnd() {
    super.onAnimationEnd();
    //Functionality here
}

Это правильное решение этой проблемы, обеспечивающее функциональность в методе over-riden View → onAnimationEnd, в отличие от метода onAnimationEnd AnimationListener, связанного с анимацией.

Это работает правильно, и в конце анимации больше не мерцает. Надеюсь, что это поможет

Ответ 2

Из API 11 вы можете использовать ObjectAnimator, который фактически изменяет свойства вида, т.е. в случае перевода, представление останется в позиции, которую он достигнет после анимации.

ObjectAnimator objectAnimator= ObjectAnimator.ofFloat(mContent_container, "translationX", startX, endX);
objectAnimator.setDuration(1000);
objectAnimator.start();

Подробнее здесь.

Ответ 3

Пожалуйста, смотрите: этот вопрос и отличный ответ за отличное исправление! Намного проще реализовать и более универсальный, чем ответ выше.

Ответ 4

Ответ Soham выше работает для меня, хотя стоит отметить (поскольку для первого чтения этой темы сразу не было очевидно, что вы все равно получите почти такое же поведение, как прослушиватель анимации, установив отдельный прослушиватель на вид, который будет запущен в конце вашего представления onAnimationStart() и onAnimationEnd().

Например, если вашему коду нужно отключить кнопку для продолжительности анимации:

Animation a = getAnimation(/* your code */);
a.setDuration(1000);
a.setAnimationListener(new AnimationListener() {
   @Override
   public void onAnimationStart(Animation arg0) {
     myButton.setEnabled(false);
   }

   @Override
   public void onAnimationEnd(Animation arg0) {
     myButton.setEnabled(true);
   }
});
someView.startAnimation(a);

В настоящее время someView не знает о myButton, и я хотел бы сохранить его таким образом. Вы можете просто создать слушателя в своем пользовательском классе представления, который вызывается тем же способом:

public final class SomeView extends View {
    // other code

    public interface RealAnimationListener {
      public void onAnimationStart();
      public void onAnimationEnd();
    }

    private RealAnimationListener mRealAnimationListener;

    public void setRealAnimationListener(final RealAnimationListener listener) {
      mRealAnimationListener = listener;
    }

    @Override
    protected void onAnimationStart() {
      super.onAnimationStart();
      if (mRealAnimationListener != null) {
         mRealAnimationListener.onAnimationStart();
      }
    }

    @Override
    protected void onAnimationEnd() {
      super.onAnimationEnd();
      if (mRealAnimationListener != null) {
         mRealAnimationListener.onAnimationEnd();
      }
    }
}

И затем обратно в ваш другой код (возможно, активность):

Animation a = getAnimation(/* your code */);
a.setDuration(1000);
someView.setRealAnimationListener(new RealAnimationListener() {
   @Override
   public void onAnimationStart() {
     myButton.setEnabled(false);
   }

   @Override
   public void onAnimationEnd() {
     myButton.setEnabled(true);
   }
});
someView.startAnimation(a);

Таким образом, вы сохраняете свои компоненты в чистоте, сохраняя при этом работу AnimationListener.

Ответ 5

Используя ответ Soham, вот ImageView, специфичный для анимации затухания:

import android.content.Context;
import android.util.AttributeSet;
import android.view.View;
import android.widget.ImageView;

/*
 * Custom view to prevent flickering on animation end
 * 
 * http://stackoverflow.com/questions/2650351/android-translateanimation-resets-after-animation
 */
public class FadeableImageView extends ImageView {

public FadeableImageView(Context context) {
    super(context);
}

public FadeableImageView(Context context, AttributeSet attrs) {
    super(context, attrs);
}

public FadeableImageView(Context context, AttributeSet attrs, int defStyle) {
    super(context, attrs, defStyle);
}

@Override
protected void onAnimationEnd() {
    super.onAnimationEnd();
    this.setVisibility(View.GONE);
}
}

И вот мой код анимации:

protected void startSplash() {
    final FadeableImageView splash = (FadeableImageView) findViewById(R.id.splash);

    Animation fadeOut = new AlphaAnimation(1, 0);
    fadeOut.setDuration(2000);
    splash.startAnimation(fadeOut);
}

Ответ 6

Избавьтесь от setFillAfter и просто используйте View.GONE в onAnimationEnd(). См. здесь для образца пользовательского вида, который реализует скользящую панель с помощью TranslateAnimation.

Ответ 7

Итак, я искал ответ на этот вопрос для моего проекта Xamarin, но я предполагаю, что он также должен применяться к Java. Реализация, которую я имел, заключалась в том, что LinearLayout, анимированный ALWAYS, имел ту же позицию (скажем, это было при x = 100, y == 100), и ваши анимации должны относиться к этой позиции. ObjectAnimator определенно был способ, и вот мое решение:

Прежде всего, простой макет с текстом наверху и LinearLayout ниже того, что является целью для анимации....

<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:p1="http://schemas.android.com/apk/res/android"
    p1:minWidth="25px"
    p1:minHeight="25px"
    p1:layout_width="match_parent"
    p1:layout_height="match_parent"
    p1:id="@+id/frameLayout1">
    <TextView
        p1:text="Some text at the top"
        p1:textAppearance="?android:attr/textAppearanceLarge"
        p1:id="@+id/txtSomeTextAtTheTop"
        p1:layout_width="wrap_content"
        p1:layout_height="wrap_content"
        p1:layout_gravity="center_horizontal" />
    <LinearLayout
        p1:orientation="vertical"
        p1:minWidth="25px"
        p1:minHeight="25px"
        p1:layout_width="wrap_content"
        p1:layout_height="wrap_content"
        p1:id="@+id/linMySlider"
        p1:layout_gravity="center_horizontal|bottom">
        <LinearLayout
            p1:orientation="horizontal"
            p1:minWidth="25px"
            p1:minHeight="25px"
            p1:layout_width="match_parent"
            p1:layout_height="wrap_content"
            p1:id="@+id/linAlwaysDisplay"
            p1:layout_marginBottom="10px">
            <TextView
                p1:text="ALWAYS ON DISPLAY"
                p1:textAppearance="?android:attr/textAppearanceLarge"
                p1:id="@+id/txtAlwaysDisplay"
                p1:layout_width="wrap_content"
                p1:layout_height="wrap_content"
                p1:layout_gravity="center_horizontal" />
        </LinearLayout>
        <LinearLayout
            p1:orientation="horizontal"
            p1:minWidth="25px"
            p1:minHeight="25px"
            p1:layout_width="match_parent"
            p1:layout_height="wrap_content"
            p1:id="@+id/linToHideLineOne">
            <TextView
                p1:text="To Hide Line One"
                p1:textAppearance="?android:attr/textAppearanceLarge"
                p1:id="@+id/txtHideLineOne"
                p1:layout_width="wrap_content"
                p1:layout_height="wrap_content"
                p1:layout_gravity="center_horizontal" />
        </LinearLayout>
        <LinearLayout
            p1:orientation="horizontal"
            p1:minWidth="25px"
            p1:minHeight="25px"
            p1:layout_width="match_parent"
            p1:layout_height="wrap_content"
            p1:id="@+id/linHideLineTwo">
            <TextView
                p1:text="To Hide Line Two"
                p1:textAppearance="?android:attr/textAppearanceLarge"
                p1:id="@+id/txtHideLineTwo"
                p1:layout_width="wrap_content"
                p1:layout_height="match_parent" />
        </LinearLayout>
    </LinearLayout>
</FrameLayout>