Android: Сброс позиции анимации после завершения

Я использую анимацию, определенную в xml, чтобы сдвинуть представление с экрана. Проблема в том, что, как только анимация завершается, она возвращается в исходное положение. Мне нужно знать, как это исправить. Здесь xml:

<set xmlns:android="http://schemas.android.com/apk/res/android" android:interpolator="@android:anim/accelerate_interpolator">
   <translate android:fromXDelta="0" android:toXDelta="-100%p" android:duration="500"/></set>

Здесь Java, который я использую для его вызова:

    homeScrn = (View)findViewById(R.id.homescreen);
    slideLeftOut = AnimationUtils.loadAnimation(this, R.anim.slide_left_out);

    //Set Click Listeners For Menu
    btnHelp.setOnClickListener(new OnClickListener() {
        public void onClick(View v) {
            LayoutInflater.from(getApplicationContext()).inflate(R.layout.help, (ViewGroup)findViewById(R.id.subpage), true);
            homeScrn.startAnimation(slideLeftOut);
        }
    });

Итак, в основном, я раздуваю представление под ним. Затем я анимирую вид сверху слева. Как только он выходит из экрана и анимация завершена, он возвращается обратно.

Ответ 1

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

Вам нужно добавить AnimationListener и в методе onAnimationEnd() сделать что-то, что делает ваш перенос постоянным (например, удаляет верхний вид из его родительского элемента, помечает вид сверху как имеющий видимость GONE).

Ответ 2

Наконец-то появился способ работать, правильный способ сделать это: setFillAfter(true),

если вы хотите определить свою анимацию в xml, вы должны сделать что-то вроде этого

<set xmlns:android="http://schemas.android.com/apk/res/android"
     android:interpolator="@android:anim/decelerate_interpolator"
     android:fillAfter="true">

    <translate 
        android:fromXDelta="0%"
        android:toXDelta="-100%"
        android:duration="1000"/>

</set>

вы можете видеть, что я определил filterAfter="true" в теге set, если вы попытаетесь определить его в теге translate, он не будет работать, может быть ошибка в рамках!

а затем в коде

Animation anim = AnimationUtils.loadAnimation(this, R.anim.slide_out);
someView.startAnimation(anim);

ИЛИ

TranslateAnimation animation = new TranslateAnimation(-90, 150, 0, 0);

animation.setFillAfter(true);

animation.setDuration(1800);

someView.startAnimation(animation);

то он, безусловно, будет работать!

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

public TranslateAnimation (float fromXDelta, float toXDelta, float fromYDelta, float toYDelta)

new TranslateAnimation(-90, 150, 0, 0);

теперь, как мы видим, наша анимация начнется с -90 по оси x до 150 по оси x

то, что мы делаем, установлено

someView.setAnimationListener(this);

и в

public void onAnimationEnd(Animation animation)
{
   someView.layout(150, 0, someView.getWidth() + 150, someView.getHeight());
}

теперь позвольте мне объяснить public void layout (int left, int top, int right, int botton)

он перемещает ваш макет в новую позицию, первый аргумент определяет левый, мы 150, потому что анимация трансляции анимировала наш вид 150 x-axis, top - 0, потому что мы не анимировали ось y, теперь мы в праве сделали someView.getWidth() + 150, в основном, мы получили ширину нашего представления и добавили 150, потому что мы слева теперь переходим к 150 x-axis, чтобы сделать ширину просмотра исходной, а нижняя равна высоте нашего представления.

Надеюсь, вы поняли концепцию перевода, и все еще у вас есть вопросы, которые вы можете задать сразу в разделе комментариев, я с удовольствием помогу:)

РЕДАКТИРОВАТЬ Не используйте метод layout(), поскольку он может быть вызван инфраструктурой, когда когда-либо вид недействителен и ваши изменения не будут выдаваться, используйте LayoutParams, чтобы установить параметры макета в соответствии с к вашему требованию

Ответ 3

Я могу немного опоздать с ответом, но у меня есть решение для этого:

Просто добавьте android:fillAfter="true" в ваш xml

Ответ 4

Вы можете использовать

fillAfter=true
fillEnabled=true

ваше представление будет не в reset в исходное положение, но если у вас есть какие-то кнопки или что-то еще в вашем представлении, их позиция не изменится.

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

вот пример

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

Спасибо JUL за его ответ

Если ваше приложение не найдено object animator, измените уровень API с Project -> properties -> Android, чем import android.animation.ObjectAnimator;

С уважением Айк

Ответ 5

Вам нужно добавить эту команду:

final Animation animSlideLeft = new TranslateAnimation(0, -80, 0,-350, 0, 0, 0, 0);
animSlideLeft.setFillAfter(true);

Ответ 6

Я пошел на тот же вопрос и решил его с установкой marginLeft на OnAnimationEnd()..

MarginLayoutParams params = (MarginLayoutParams) this.getLayoutParams(); params.setMargins(this.getWidth()*position, 0,0,0); this.setLayoutParams(params);

Ответ 7

Эта проблема беспокоит более недели. И Мухаммад ответил мне на первый план, чтобы решить его.

Я использовал разметку для реализации боковых меню с анимацией. "view.layout не будет постоянным. Вы должны использовать LayoutParams, который будет постоянным".

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

@Override
public void onAnimationEnd(Animation animation) {
FrameLayout.LayoutParams layoutParams=new FrameLayout.LayoutParams(screenWidth, screenHeight);
layoutParams.setMargins((int) -(screenWidth * RATE), 0,
            (int) (screenWidth - screenWidth * RATE), screenHeight);
    for(View v:views) {

        v.setLayoutParams(layoutParams);
        //v.layout((int) -(screenWidth * RATE), 0, (int) (screenWidth - screenWidth * RATE), screenHeight);
        v.clearAnimation();
    }
}

Ответ 8

Используйте вспомогательные методы ниже, чтобы легко оживить ваш вид. Затем вы можете анимировать и сбросить после завершения, как это:

// Animate the view:

fly(
  view1,
  (float) 0,
  (float) 0,
  (float) 0,
  (float) 1000,
  250,
  null,
  null,
  () -> {

    // Return the view to initial position on animation end:  

    fly(
      view1,
      (float) 0,
      (float) 0,
      (float) 0,
      (float) 0,
      0);

    return null;
  });

Вспомогательные методы:

/**
 * Translation of a view.
 */
public static void fly(
  View view,
  float fromXDelta,
  float toXDelta,
  float fromYDelta,
  float toYDelta,
  int duration) {

  fly(
    view,
    fromXDelta,
    toXDelta,
    fromYDelta,
    toYDelta,
    duration,
    null,
    null,
    null);
}

/**
 * Translation of a view with handlers.
 *
 * @param view       A view to animate.
 * @param fromXDelta Amount to shift by X axis for start position.
 * @param toXDelta   Amount to shift by X axis for end position.
 * @param fromYDelta Amount to shift by Y axis for start position.
 * @param toYDelta   Amount to shift by Y axis for end position.
 * @param duration   Animation duration.
 * @param start      On animation start. Otherwise NULL.
 * @param repeat     On animation repeat. Otherwise NULL.
 * @param end        On animation end. Otherwise NULL.
 */
public static void fly(
  View view,
  float fromXDelta,
  float toXDelta,
  float fromYDelta,
  float toYDelta,
  int duration,
  Callable start,
  Callable repeat,
  Callable end) {

  Animation animation;

  animation =
    new TranslateAnimation(
      fromXDelta,
      toXDelta,
      fromYDelta,
      toYDelta);

  animation.setDuration(
    duration);

  animation.setInterpolator(
    new DecelerateInterpolator());

  animation.setFillAfter(true);

  view.startAnimation(
    animation);

  animation.setAnimationListener(new AnimationListener() {

    @Override
    public void onAnimationStart(Animation animation) {

      if (start != null) {
        try {

          start.call();

        } catch (Exception e) {
          e.printStackTrace();
        }
      }

    }

    @Override
    public void onAnimationEnd(Animation animation) {

      if (end != null) {
        try {

          end.call();

        } catch (Exception e) {
          e.printStackTrace();
        }
      }
    }

    @Override
    public void onAnimationRepeat(
      Animation animation) {

      if (repeat != null) {
        try {

          repeat.call();

        } catch (Exception e) {
          e.printStackTrace();
        }
      }  
    }
  });
}