如何减少动画中的 requestLayout() 延迟?
How to reduce requestLayout() lag in animations?
我正在尝试为 TextView
的宽度设置动画,在我的 Redmi Note 4 上它完美运行。然而,当在稍慢的 phone(1.2 GHz 四核)上进行测试时,动画非常滞后。
经过一些入门调试,原来调用requestLayout()
是罪魁祸首,它丢了很多帧,进一步检查,结果是onMeasure()
,这是第一个重绘 时调用的方法被调用很多,因为只有 1 TextView
被动画化。父层次结构的其余部分可能将其称为 bubblin' 到根。
这对我来说绝对不是什么好事。我正在尝试为宽度和高度设置动画。我使用 ValueAnimator
并在 onAnimationUpdate()
中调用 requestLayout
,我尝试仅在其中一个中调用 requestLayout()
,但几乎没有任何影响。
final ViewGroup.LayoutParams layoutParams = container.getLayoutParams();
ValueAnimator anim = ValueAnimator.ofInt(this.width, ((int) (this.screenWidth / 1.5)));
anim.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator valueAnimator) {
layoutParams.width = (int) (Integer) valueAnimator.getAnimatedValue();
}
});
anim.setDuration(duration);
anim.start();
anim = ValueAnimator.ofInt(this.height, this.screenHeight / 2);
anim.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator valueAnimator) {
layoutParams.height = (int) (Integer) valueAnimator.getAnimatedValue();
container.requestLayout();
}
});
anim.setDuration(duration);
anim.start();
我尝试自定义 StaticLayout
来利用这种方法的一些效率和性能优化,但它也没有帮助。毕竟 View
class 本身就是反复调用 onMeasure()
的东西,那么我怎样才能防止这种情况发生并且只更新我愿意调整大小的 TextView
?当然 invalidate()
不会工作,因为它会错过调整大小的工作。
我认为这取决于设备的图形渲染能力。
所以你在设备上有所不同。
如果出现掉帧现象,请不要大惊小怪
一个原因可能是:
- 你正在从某个宽度到 screenWidth/1.5 设置动画,我认为这很大。
假设您的动画从 48 变为 480
初始值:48
最终值:480
持续时间:200 毫秒
表示200毫秒内(480-48) = 432 steps/re-draw
然后,大约每毫秒绘制 2 次。
所以你给一张图不到一毫秒。
理想情况下,如果时间绘制时间超过 16 毫秒,则会出现丢帧。
在您的情况下,由于 requestLayout 调用,您尝试重新绘制的次数过多。
绘制 432 帧的理想条件如下:
1 frame -> 20 ms (some extra time given)
432 frames -> 8640 ms
尝试减少对 requestLayout 的调用次数以防止 onMeasure()
次调用。
经过一些挖掘,我发现在 ConstraintLayout
上使用 beginDelayedTransition()
和 ConstraintSet
被证明比手动动画更高效、更流畅。
我正在尝试为 TextView
的宽度设置动画,在我的 Redmi Note 4 上它完美运行。然而,当在稍慢的 phone(1.2 GHz 四核)上进行测试时,动画非常滞后。
经过一些入门调试,原来调用requestLayout()
是罪魁祸首,它丢了很多帧,进一步检查,结果是onMeasure()
,这是第一个重绘 时调用的方法被调用很多,因为只有 1 TextView
被动画化。父层次结构的其余部分可能将其称为 bubblin' 到根。
这对我来说绝对不是什么好事。我正在尝试为宽度和高度设置动画。我使用 ValueAnimator
并在 onAnimationUpdate()
中调用 requestLayout
,我尝试仅在其中一个中调用 requestLayout()
,但几乎没有任何影响。
final ViewGroup.LayoutParams layoutParams = container.getLayoutParams();
ValueAnimator anim = ValueAnimator.ofInt(this.width, ((int) (this.screenWidth / 1.5)));
anim.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator valueAnimator) {
layoutParams.width = (int) (Integer) valueAnimator.getAnimatedValue();
}
});
anim.setDuration(duration);
anim.start();
anim = ValueAnimator.ofInt(this.height, this.screenHeight / 2);
anim.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator valueAnimator) {
layoutParams.height = (int) (Integer) valueAnimator.getAnimatedValue();
container.requestLayout();
}
});
anim.setDuration(duration);
anim.start();
我尝试自定义 StaticLayout
来利用这种方法的一些效率和性能优化,但它也没有帮助。毕竟 View
class 本身就是反复调用 onMeasure()
的东西,那么我怎样才能防止这种情况发生并且只更新我愿意调整大小的 TextView
?当然 invalidate()
不会工作,因为它会错过调整大小的工作。
我认为这取决于设备的图形渲染能力。 所以你在设备上有所不同。 如果出现掉帧现象,请不要大惊小怪
一个原因可能是: - 你正在从某个宽度到 screenWidth/1.5 设置动画,我认为这很大。
假设您的动画从 48 变为 480
初始值:48
最终值:480
持续时间:200 毫秒
表示200毫秒内(480-48) = 432 steps/re-draw 然后,大约每毫秒绘制 2 次。
所以你给一张图不到一毫秒。 理想情况下,如果时间绘制时间超过 16 毫秒,则会出现丢帧。 在您的情况下,由于 requestLayout 调用,您尝试重新绘制的次数过多。
绘制 432 帧的理想条件如下:
1 frame -> 20 ms (some extra time given)
432 frames -> 8640 ms
尝试减少对 requestLayout 的调用次数以防止 onMeasure()
次调用。
经过一些挖掘,我发现在 ConstraintLayout
上使用 beginDelayedTransition()
和 ConstraintSet
被证明比手动动画更高效、更流畅。