2014-12-06 4 views
0

Я пытаюсь сделать метроном с иглой, движущейся как перевернутый маятник. Я пробовал RotationAnimation of android, чтобы сделать это, но, похоже, он замедляется после нескольких запусков. Я пробовал как LinearInterpolator, так и пользовательский интерполятор (MetronomeInterpolator).Android RotateAnimation замедляется после повторения нескольких раз

Следующий код взято из 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

Я решил добавить коды в прослушиватель анимации. Я записал начальное время начала анимации. При повторении вычисляется ожидаемая продолжительность анимации. Сравните его со временем, используемым анимацией. Сократите продолжительность анимации, если анимация использовала больше времени, чем ожидалось. Сброс до заданной продолжительности, если анимация использует меньше времени, чем ожидалось.

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; 
     } 
    }); 
Смежные вопросы