android:fixed帧率动画
android:fixed frame rate animation
我使用 GLSurfaceView.RENDERMODE_WHEN_DIRTY 模式来更新我的 glSurfaceView。
为了绘制流畅的动画,我需要一些控制器,它将以恒定的帧更新表面视图-rate.I 知道我可以使用 Looper class 实现这一点,但我相信必须有本地方式做 this.Ideally 我需要这样的东西:
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: 解决了,看我的回答。
解决方法如下Class:
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;
}
}
我使用 GLSurfaceView.RENDERMODE_WHEN_DIRTY 模式来更新我的 glSurfaceView。
为了绘制流畅的动画,我需要一些控制器,它将以恒定的帧更新表面视图-rate.I 知道我可以使用 Looper class 实现这一点,但我相信必须有本地方式做 this.Ideally 我需要这样的东西:
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: 解决了,看我的回答。
解决方法如下Class:
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;
}
}