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

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

8 51

8 ответов:

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

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

наконец-то есть способ обойти,правильный способ сделать это 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-axis до 150 x-axis

Итак, что мы делаем, это установить

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 чтобы ширина вида была равна его исходной единице, а дно равно высоте нашего вида.

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

EDIT не используйте layout() метод как он может быть вызван фреймворком, когда когда-либо просмотр будет признан недействительным, и ваши изменения не будут присутствовать, используйте LayoutParams для того чтобы установить ваши параметры плана согласно вашему требованию

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

просто добавить android:fillAfter=true в XML

можно использовать

fillAfter=true
fillEnabled=true

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

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

вот пример

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

спасибо Джул за его ответ

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

С Уважением Гайк

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

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

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

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

эта проблема беспокоит уже больше недели. И ответ Мухаммеда указал мне прямой путь к его решению.

я использовал sever 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();
    }
}

использовать вспомогательные методы ниже чтобы легко анимировать Ваше мнение. Тогда вы можете анимация и сброс после завершения такой:

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