我正在尝试制作一个节拍器,针头像倒立摆一样移动。 我已经尝试过使用Android的RotationAnimation进行此操作,但似乎在几次运行后减速。 我尝试了LinearInterpolator和自定义插值器(MetronomeInterpolator)。
以下代码来自Android How to rotate needle when speed changes?,感谢IHaN JiTHiN。
RotateAnimation needleDeflection = new RotateAnimation(
this.previousAngle, this.currentAngle, this.pivotX, this.pivotY) {
protected void applyTransformation(float interpolatedTime,
Transformation t) {
currentDegrees = previousAngle + (currentAngle - previousAngle)
* interpolatedTime;
currentValue = (((currentDegrees - minAngle) * (maxValue - minValue)) / (maxAngle - minAngle))
+ minValue;
if (NDL != null)
NDL.onDeflect(currentDegrees, currentValue);
super.applyTransformation(interpolatedTime, t);
}
};
needleDeflection.setAnimationListener(new AnimationListener() {
@Override
public void onAnimationStart(Animation arg0) {
}
@Override
public void onAnimationRepeat(Animation arg0) {
}
@Override
public void onAnimationEnd(Animation arg0) {
previousAngle = currentAngle;
}
});
needleDeflection.setDuration(this.deflectTime);
needleDeflection.setInterpolator(new MetronomeInterpolator());
needleDeflection.setFillBefore(true);
needleDeflection.setFillAfter(false);
needleDeflection.setStartOffset(0);
needleDeflection.setRepeatMode(Animation.RESTART);
needleDeflection.setRepeatCount(Animation.INFINITE);
this.gaugeNeedle.startAnimation(needleDeflection);
this.gaugeNeedle.refreshDrawableState();
动画将无限次重启。
public class MetronomeInterpolator implements Interpolator {
private double p=0.5;
@Override
public float getInterpolation(float t) {
// a: amplitude, p: period/2
//https://stackoverflow.com/questions/1073606/is-there-a-one-line-function-that-generates-a-triangle-wave
double a=1;
return (float)((a/p) * (p - Math.abs(t % (2*p) - p)));
}
}
MetronomeInterpolator正在形成三角波。该公式取自Is there a one-line function that generates a triangle wave?,谢谢Lightsider。
除时间外,整个动画效果很好。动画第一次正确开始和结束。但是,动画似乎比重复几次后应该更慢。即,在背景处播放嘀嗒声,这被证实是准确的,但旋转动画在几次重复之后滞后。
其中一个原因是某些代码在重复之前正在运行。你可以建议一种方法来使用任何可以在android中使用的解决方案制作精确的钟摆的动画吗?非常感谢你。
答案 0 :(得分:0)
我通过在动画监听器中添加代码来解决。 我记录动画开始时的开始时间。 重复时,我会计算动画应该使用的预期持续时间。 将它与动画使用的时间进行比较。 如果动画使用的时间超过预期,则缩短动画持续时间。 如果动画使用的时间少于预期,则重置为定义的持续时间。
needleDeflection.setAnimationListener(new AnimationListener() {
@Override
public void onAnimationStart(Animation arg0) {
long startTime=AnimationUtils.currentAnimationTimeMillis();
GaugeView.this.animateRepeatedTimes=0;
GaugeView.this.animateStartTime = startTime;
}
@Override
public void onAnimationRepeat(Animation arg0) {
//duration of the animation * number of runs of animation + (long)starttime
long expectedEndTime = GaugeView.this.deflectTime* ++GaugeView.this.animateRepeatedTimes + GaugeView.this.animateStartTime;
long repeatTime=AnimationUtils.currentAnimationTimeMillis();
long timeExcessUsed = repeatTime - expectedEndTime;
if(timeExcessUsed>0){
//reduce the animation duration
arg0.setDuration(GaugeView.this.deflectTime-timeExcessUsed);
}else{
//reset the animation duration to normal
arg0.setDuration(GaugeView.this.deflectTime);
}
}
@Override
public void onAnimationEnd(Animation arg0) {
previousAngle = currentAngle;
}
});