Android:完成后动画位置重置

时间:2010-10-07 14:44:06

标签: 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);
        }
    });

所以基本上发生的事情是我在一个下面膨胀一个视图。然后我在顶部向左侧显示视图的动画。一旦它离开屏幕并且动画结束,它就会重置它的位置。

10 个答案:

答案 0 :(得分:104)

最后有办法解决,正确的方法是 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标记中定义它,它将无效,可能是框架中的 bug !!

然后在代码中

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轴 top为0 ,因为我们没有动画y轴,现在我们已经完成了someView.getWidth() + 150我们基本上得到了视图的宽度并添加了 150 ,因为我们是left现在移动到 150 x轴,使视图宽度为原点1,底部等于视图高度。

我希望你们现在能够理解翻译的概念,但是你仍然可以在评论部分立即提出任何问题,我很乐意提供帮助:)

编辑不要使用layout()方法,因为当视图无效并且您的更改不会保留时,框架可以调用它,使用LayoutParams设置您的布局参数根据您的要求

答案 1 :(得分:80)

动画按预期工作。仅仅因为你动画的东西并不意味着你真的移动了它。动画仅影响动画本身的绘制像素,而不影响小部件的配置。

您需要添加AnimationListener,并在onAnimationEnd()方法中执行一些使您的移动永久化的内容(例如,从其父级移除顶部的视图,将顶部的视图标记为具有能见度GONE)。

答案 2 :(得分:23)

我回复可能有点迟,但我有解决方法:

只需添加android:fillAfter="true" 在你的xml中

答案 3 :(得分:9)

您可以使用

fillAfter=true
fillEnabled=true

您的视图不会重置为原始位置,但如果您的视图中有某些按钮或其他内容,则其位置不会更改。

您必须使用ObjectAnimator,它适用于API 11级别。它会自动更改“查看位置”,

这是示例

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

感谢JUL的answer

如果找不到您的应用object animator,请更改Project -> properties -> Android的API级别,而不是import android.animation.ObjectAnimator;

关心Hayk

答案 4 :(得分:7)

您需要添加以下命令:

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

答案 5 :(得分:1)

我去了同样的问题,并在OnAnimationEnd()设置marginLeft来解决它。

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

答案 6 :(得分:1)

这个问题困扰了一个多星期。 穆罕默德的回答指出了一种解决问题的明智方法。

我使用服务器布局来实现带动画的侧边菜单。 “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();
    }
}

答案 7 :(得分:0)

使用下面的帮助方法可以轻松地为视图添加动画。然后,您可以像这样动画并在完成后重置

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

Helper方法:

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

答案 8 :(得分:0)

fillAfter = true 将完成将视图转换为新动画位置的工作。

rotateAnimation.fillAfter = true;

如果有兴趣在回收视图中移动arrow_up和arrow_down动画的人会展开/折叠行为。

  1. 初始状态:折叠
  2. 调用带有子可见性标记(View.VISIBLE / View.GONE)的方法。

下面的代码属于动画。

fun setArrowImage(imageView: ImageView, childVisibility: Int) {

val angleRange = if (childVisibility == View.VISIBLE) Pair(0F, 180F) else 
Pair(100f, 0F)

val rotateAnimation = RotateAnimation(
    angleRange.first, angleRange.second,
    Animation.RELATIVE_TO_SELF, 0.5f,
    Animation.RELATIVE_TO_SELF, 0.5f
)
rotateAnimation.duration = 300
rotateAnimation.fillAfter = true;

imageView.startAnimation(rotateAnimation)

}

答案 9 :(得分:0)

答案中没有任何内容对我有用;尽管@Muhammad Babar 的回答启发了我找到解决方案:

他提到我们可以在动画结束时将视图布局到新位置:

@SpringBootApplication

虽然这对我不起作用;我必须在延迟 Runnable 的处理程序中使用略小于动画持续时间的延迟值来执行此操作。

所以,在我的例子中,动画持续时间是 500 毫秒,我在 450 毫秒上使用了一个处理程序,所以它在动画结束 50 毫秒之前被触发。

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