运行 多个动画没有明显的延迟
Run multiple animations without noticeable lag
我正在开发一个简单的 2D 游戏。游戏从一个动画开始,然后玩家点击屏幕,另一个动画应该 运行 在切换到下一个动画时没有 明显的滞后 。我的第一种方法是将 AnimationDrawable 与 40 个 PNG [帧] 的动画列表一起使用。我想使用两个这样的 AnimationDrawables。由于 android 在播放动画之前加载动画的所有帧的行为,这种方法会导致 OOM。然后我决定将我的单个动画拆分为 4 个动画,每个动画 10 帧。第一个 10 帧的动画 运行s 完美,但是当我播放第二个时 [在第一个停止后立即播放] 我得到 OOM 并且应用程序关闭。
1) 我遇到了这个解决方案:
这看起来像是解决我的问题的完美方法。但我不知道解决方案中使用的 OnAnimationStoppedListener 对象。 developers.android.com 或其他任何地方都没有关于它的信息。我想在评论下直接问@Pinhassi 但无法添加评论,感谢 50 声望限制。
编辑: 我找到了几乎相似的解决方案 here
工作没有任何错误 :D 但是和我在 4) 中提到的一样滞后
我什至设置了 delayMillis = 0;它仍然 运行s 大约 10fps [观察]
2) post 已有 5 年历史了,所以我想,现在应该有一个预定义的 class 来使用长动画而不会导致 OOM。如果存在 class,请指出它的 link。
3) 朋友建议我用gif代替动画。但我想没有办法以编程方式 stop/play gif。此外,一张 40 帧的 gif 似乎是天方夜谭。如果有人知道用gif相当于动画,请遮光。
4) 我以前的方法 [当我不知道 AnimationDrawable class] 是使用 SurfaceView 并在 canvas 上循环绘制 40 个位图来模拟动画。它有效,但帧速率慢得令人讨厌。当玩家点击屏幕时,它会变慢。此外,不同手机的帧率也有很大差异。有些人建议我降低图像分辨率。我将图像从 720p 缩小到 320p,但并没有太大区别。有什么方法可以用这种方法加速动画吗?
如果有人能回答 1) 和 2).,我将不胜感激
你的问题比较宽泛,我会尽量帮助一下(不知道是否能给出完整的答案)。当我在 Android 中制作动画时,我会尽可能多地尝试使用原生视图,因为性能几乎总是最好的,即使对于较旧的设备也是如此。如果你需要做一些更复杂的事情,也许你可以考虑使用 Animator
class.
ObjectAnimator
是继承 Animator
的 class 之一,它允许您基于对象的单个 属性 创建自定义动画。我的建议是创建一个自定义视图,其中包含一个名为 animationFrame
的 属性,其值在 0-39
范围内。然后当设置值时,正确的图像被加载为视图的背景。您可以使用像 Glide 这样的库来优化图像的加载。
因此您的代码应如下所示:
private class MyAnimation extends View {
private ObjectAnimator animator = new ObjectAnimator();
public MyAnimation(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
@Override
protected void onFinishInflate() {
super.onFinishInflate();
animator.setTarget(this);
// the value must match a function with the signature "void setAnimationFrame(int frame)" (using the magic of reflection)
animator.setPropertyName("animationFrame");
animator.setIntValues(0, 39);
animator.setRepeatCount(ObjectAnimator.INFINITE);
animator.setRepeatMode(ObjectAnimator.RESTART);
animator.setDuration(1000 / 60 * 40);
animator.setInterpolator(new LinearInterpolator());
animator.addListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationEnd(Animator animation) {
// If you need to do something at the end of the animation
}
});
}
public void startAnimation() {
animator.start();
}
private void setAnimationFrame(int frame) {
setBackground(getDrawableForFrame(frame));
}
private Drawable getDrawableForFrame(int frame) {
// Here you implement the loading from Glide or any other library or custom code
return null;
}
}
我正在开发一个简单的 2D 游戏。游戏从一个动画开始,然后玩家点击屏幕,另一个动画应该 运行 在切换到下一个动画时没有 明显的滞后 。我的第一种方法是将 AnimationDrawable 与 40 个 PNG [帧] 的动画列表一起使用。我想使用两个这样的 AnimationDrawables。由于 android 在播放动画之前加载动画的所有帧的行为,这种方法会导致 OOM。然后我决定将我的单个动画拆分为 4 个动画,每个动画 10 帧。第一个 10 帧的动画 运行s 完美,但是当我播放第二个时 [在第一个停止后立即播放] 我得到 OOM 并且应用程序关闭。
1) 我遇到了这个解决方案: 这看起来像是解决我的问题的完美方法。但我不知道解决方案中使用的 OnAnimationStoppedListener 对象。 developers.android.com 或其他任何地方都没有关于它的信息。我想在评论下直接问@Pinhassi 但无法添加评论,感谢 50 声望限制。
编辑: 我找到了几乎相似的解决方案 here 工作没有任何错误 :D 但是和我在 4) 中提到的一样滞后 我什至设置了 delayMillis = 0;它仍然 运行s 大约 10fps [观察]
2) post 已有 5 年历史了,所以我想,现在应该有一个预定义的 class 来使用长动画而不会导致 OOM。如果存在 class,请指出它的 link。
3) 朋友建议我用gif代替动画。但我想没有办法以编程方式 stop/play gif。此外,一张 40 帧的 gif 似乎是天方夜谭。如果有人知道用gif相当于动画,请遮光。
4) 我以前的方法 [当我不知道 AnimationDrawable class] 是使用 SurfaceView 并在 canvas 上循环绘制 40 个位图来模拟动画。它有效,但帧速率慢得令人讨厌。当玩家点击屏幕时,它会变慢。此外,不同手机的帧率也有很大差异。有些人建议我降低图像分辨率。我将图像从 720p 缩小到 320p,但并没有太大区别。有什么方法可以用这种方法加速动画吗?
如果有人能回答 1) 和 2).,我将不胜感激
你的问题比较宽泛,我会尽量帮助一下(不知道是否能给出完整的答案)。当我在 Android 中制作动画时,我会尽可能多地尝试使用原生视图,因为性能几乎总是最好的,即使对于较旧的设备也是如此。如果你需要做一些更复杂的事情,也许你可以考虑使用 Animator
class.
ObjectAnimator
是继承 Animator
的 class 之一,它允许您基于对象的单个 属性 创建自定义动画。我的建议是创建一个自定义视图,其中包含一个名为 animationFrame
的 属性,其值在 0-39
范围内。然后当设置值时,正确的图像被加载为视图的背景。您可以使用像 Glide 这样的库来优化图像的加载。
因此您的代码应如下所示:
private class MyAnimation extends View {
private ObjectAnimator animator = new ObjectAnimator();
public MyAnimation(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
@Override
protected void onFinishInflate() {
super.onFinishInflate();
animator.setTarget(this);
// the value must match a function with the signature "void setAnimationFrame(int frame)" (using the magic of reflection)
animator.setPropertyName("animationFrame");
animator.setIntValues(0, 39);
animator.setRepeatCount(ObjectAnimator.INFINITE);
animator.setRepeatMode(ObjectAnimator.RESTART);
animator.setDuration(1000 / 60 * 40);
animator.setInterpolator(new LinearInterpolator());
animator.addListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationEnd(Animator animation) {
// If you need to do something at the end of the animation
}
});
}
public void startAnimation() {
animator.start();
}
private void setAnimationFrame(int frame) {
setBackground(getDrawableForFrame(frame));
}
private Drawable getDrawableForFrame(int frame) {
// Here you implement the loading from Glide or any other library or custom code
return null;
}
}