android:固定帧率动画

时间:2016-11-14 10:52:17

标签: android animation frame-rate

我使用GLSurfaceView.RENDERMODE_WHEN_DIRTY模式来更新我的glSurfaceView。

要绘制平滑的动画,我需要一些控制器,它将以恒定的帧速率更新表面视图。我知道我可以用Looper类实现这一点,但我相信必须有本地方式来做到这一点。我真的需要一些东西像:

 Animation anim=new Animation(..);
 anim.setListener(this);
 anim.start();
 ...
private void onNextFrame(float pos) {
 //do my animation according to position value
}
private void onAnimFinished() {
//animation is finished
}

UPD:已解决,请参阅我的回答。

1 个答案:

答案 0 :(得分:0)

解决了以下类:

package tween_test;
import android.os.SystemClock;

public class Tween extends Thread {
      public interface OnTweenUpdate {
          public void onNextFrame(Tween tween,float position);
          public void onTweenFinish(Tween tween);
      }
      public enum Easing {
          REGULAR;
      }
      public enum Types {
          LINEAR(1000, false,Easing.REGULAR);
          private final long duration;
          private final boolean looped;
          private final Easing easing;
          Types(long duration, boolean looped,Easing easing) {
              this.duration = duration;
              this.looped = looped;
              this.easing=easing;
          }
          public Easing easing() {
              return this.easing;
          }
          public long duration() {
              return this.duration;
          }
          public boolean looped() {
        return looped;
    }
}
      private final int FPS=60;
      private final int FRAME_DELTA=1000/FPS;
      private long lastFrameTimestamp;
      private OnTweenUpdate listener;
      private Types type;
      private long startTS;
      public Tween(Types type) {
          super();
          this.type=type;
      }
      public void setListener(OnTweenUpdate listener) {
          this.listener=listener;
      }
      @Override
      public void start() {
          lastFrameTimestamp=startTS=SystemClock.elapsedRealtime();
          super.start();
      }
      @Override
      public void run() {
          while (!isInterrupted()) {
              long cts= SystemClock.elapsedRealtime();
              if (cts-lastFrameTimestamp>=FRAME_DELTA) {
                  lastFrameTimestamp=cts;
                  if (listener!=null)
                      listener.onNextFrame(this,ease((float)(cts-startTS)/type.duration()));
              }
              if(cts>=startTS+type.duration()) {
                  boolean looped=type.looped();
                  if (!looped) {
                      if (listener != null)
                          listener.onTweenFinish(this);
                      this.interrupt();
                  } else {
                      lastFrameTimestamp=startTS=cts;
                  }
              }
          }
      }
      public void fforward() {
          if (listener!=null)
              listener.onTweenFinish(this);
          this.interrupt();
      }
      private float ease(float pos) {
          switch (type.easing()) {
              case REGULAR:
                  return  pos;
          }
          return 0f;
      }
}