Android:完成后会重置动画位置


67

我正在使用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);
        }
    });

所以基本上发生的是我将一个视图下的视图充气。然后为左上方的顶部动画。一旦离开屏幕并且动画完成,它将重置其位置。

Answers:


86

动画按预期方式工作。仅仅因为您对某物进行了动画处理并不意味着您实际上在移动它。动画仅在动画本身期间影响绘制的像素,而不影响小部件的配置。

您需要添加一个AnimationListener,然后在onAnimationEnd()方法中执行一些使您的移动永久化的操作(例如,从其父级移除顶部的视图,将顶部的视图标记为具有可见性GONE)。


4
但是如果同样要滑入我该怎么办。由于它实际上没有移动,那么我该如何在我有SlideOut的对象中滑动?
广告

即使你做你permeneny移动你ViewonAnimationEnd()闪烁。检查:stackoverflow.com/questions/2650351/...
萨罗Taşciyan

6
slideLeftOut.setFillAfter(true)吗?
Deepscorn

115

终于有方法来解决,要做到这一点,正确的做法是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轴顶部为0,因为我们没有设置y轴的动画,在右边我们已经完成了someView.getWidth() + 150基本上,我们获得了视图的宽度,并增加了150,因为我们现在向左移动了150 x轴,以使视图宽度变为原始宽度,而底部等于视图的高度。

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

编辑不要使用layout()方法,因为当视图无效并且您的更改将不存在时,框架可以调用该方法,LayoutParams请根据需要设置您的布局参数


感谢您的解释,我也使用这种方法,这种方法的唯一问题是动画结束时动画视图闪烁。
user65721 2013年

1
@ user65721您是否将视图移到新位置??你有尝试过setFillEnabled()吗?
穆罕默德·巴巴尔

2
我在做同样的@CommonsWare告诉我,但在闪烁。设置setFillAfter(true)可以解决问题,谢谢!
Sulpkain 2014年

30

我的回复可能有点晚,但是我有解决方案:

只需添加android:fillAfter="true" 您的xml


16
它不适用于翻译动画。它仅适用于比例动画。
广告

@NicolasTyler,确保在动画xml中添加fillAfterfillEnabled到根元素。
加根

作为xml顺序加载动画并开始,使用fillafter true的一个动画可以完美地解决此问题
Ucdemir

@Ads这适用于my_scale_and_rotate_animation.xml动画。也许如果您将一个虚拟<scale.../>元素(实际上并没有任何改变)添加到您的translate_only_animation.xml动画中,那么添加android:fillAfter="true"到父<set.../>元素也可以为您工作吗?
ban-geoengineering

这对我有用,我将AnimationSet与alpha一起使用并转换了动画,将它们添加到根元素(AnimationSet)将会起作用
两次编码

9

您可以使用

fillAfter=true
fillEnabled=true

您的视图不会重置为原始位置,但是如果视图中有一些按钮或其他内容,它们的位置将不会改变。

您必须使用 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;

问候海克


7

您需要添加以下命令:

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

1

我去了同一个问题,并通过在OnAnimationEnd()处设置marginLeft解决了它。

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


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

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

辅助方法:

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

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)

}

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.