我从头开始创建自定义视图。延长View
并覆盖onDraw()
。
当关闭动画视图时,我使用偏移生成自定义动画。
例如。
while(!isOnTop){
mOffset++;
//draw the component a a it higher using the offset
if(position == 0)
isOnTop==true;
invalidate();
}
我的想法是我的框架来自于自我失效。问题是这个视图的失效只能通过在同一个屏幕上滚动列表视图来实现。
这种“共享失效()”导致我的动画滞后。那么有没有办法摆脱这种滞后?
您是否有其他建议在共享环境中执行动画? 使用计算偏移的单独线程创建动画也需要强制invalidation()调用来显示动画(如果我错了,请纠正我)。
执行动画的唯一解决方案是,例如10个失效请求的步长更大?它会缓解延迟,但我想我可以采用不同的方法。
答案 0 :(得分:22)
“什么是最好的”当然在很大程度上取决于你想要做什么。你还没有说出你想要完成什么,所以我们只能猜测你最适合的事情。
以下是一些简单的事情:
如果要为位图帧设置动画,请使用AnimationDrawable:http://developer.android.com/reference/android/graphics/drawable/AnimationDrawable.html
如果要为层次结构中的视图移动设置动画,请使用视图动画框架:http://developer.android.com/guide/topics/graphics/view-animation.html
新的更通用的动画框架可以做更多的东西,通常更容易使用:http://developer.android.com/guide/topics/graphics/animation.html。这在Android 3.0+中原生可用,但也可以在支持v7库的Android API 7级中使用。
如果您想编写一个自定义窗口小部件,它是视图层次结构的集成部分并手动执行自己的动画绘制,您可以使用处理程序为更新计时(通常您需要60fps或20ms之间的时间)每个invalidate())然后在你的onDraw()方法中,基于SystemClock.uptimeMillis()将视图的状态绘制为动画开始时的增量。
这是使用Handler的简单重复无效:
long mAnimStartTime;
Handler mHandler = new Handler();
Runnable mTick = new Runnable() {
public void run() {
invalidate();
mHandler.postDelayed(this, 20); // 20ms == 60fps
}
}
void startAnimation() {
mAnimStartTime = SystemClock.uptimeMillis();
mHandler.removeCallbacks(mTick);
mHandler.post(mTick);
}
void stopAnimation() {
mHandler.removeCallbacks(mTick);
}
答案 1 :(得分:4)
由于这个问题有一些兴趣,我会回复。
最好的方法是使用单独的画布线程。只能使用SurfaceView
来实现“单独”画布。 LunarLanding是这种用法的一个很好的例子。每个帧的分别计算的主视图仅共享CPU时间,而不是绘图时间。因此,即使结合了例如顶部的常规视图和底部的动画视图,也会更快。
但如果您在共享环境中,则必须设置间隔。该间隔用于FPS上限。如果你没有设置FPS上限,那么CPU将运行疯狂管理以获得SurfaceView
的好动画(如果它是独自的话)。以60fps甚至更低的速度限制它将有效地绘制所有视图而无CPU过载。
请参阅API演示中的Lunar Landing绘图线程并设置FPS上限。
private long timeNow;
private long timeDelta;
private long timePrevFrame;
private void capFps(int fps) {
timeNow = System.currentTimeMillis();
timeDelta = timeNow - timePrevFrame;
try {
// ps你可以为60FPS设置16而不是1000 / fps,以避免每次计算
Thread.sleep((1000 / fps) - timeDelta);
} catch (InterruptedException e) {
}
timePrevFrame = System.currentTimeMillis();
}
然后绘图线程看起来像这样:
@Override
public void run() {
Canvas c;
while (run) {
c = null;
sleepFps(60, false);
try {
synchronized (surfaceHolder) {
c = surfaceHolder.lockCanvas(null);
widgetView.doDraw(c);
}
} finally {
if (c != null) {
surfaceHolder.unlockCanvasAndPost(c);
}
}
}
}