如何在android中绘制动画视图?

wea*_*ire 8 android android-layout android-canvas android-view

我从头开始创建自定义视图.扩展View和覆盖onDraw().当关闭动画视图时,我使用偏移生成自定义动画.例如.

while(!isOnTop){
mOffset++;

//draw the component a a it higher using the offset

if(position == 0)
isOnTop==true;
invalidate();

}
Run Code Online (Sandbox Code Playgroud)

我的想法是我的框架来自于自我.问题是只能通过在同一屏幕上滚动列表视图来使此视图无效.

这种"共享失效()"导致我的动画滞后.那么有没有办法摆脱这种滞后?

您是否有其他建议在共享环境中执行动画?使用计算偏移量的单独线程创建动画也需要强制invalidation()调用来显示动画(如果我错了,请纠正我).

唯一的解决方案是执行动画,例如10个具有更大步骤的失效请求?它将缓解延迟,但我认为我可以使用不同的方法.

hac*_*bod 22

"什么是最好的"当然在很大程度上取决于你想要做什么.你还没有说你想要完成什么,所以我们只能猜测你最适合自己的东西.

这是一些简单的事情:

这是使用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);
}
Run Code Online (Sandbox Code Playgroud)

  • 不是20ms 50fps? (12认同)
  • 并不是的.如果invalidate()花费的时间超过20毫秒,那么您在构建视图层次结构方面遇到了严重问题.标准平台中Windows中的绝大多数动画使用带有invalidate()的常规视图,并且可以达到60fps.您只需要确保在视图层次结构中不执行任何操作,例如将多个大的不透明位图叠加在一起,或者缩放使得绘制它们变慢...但是您仍然不想这样做. (2认同)

wea*_*ire 4

由于这个问题有一些兴趣,我会回答。

最好的方法是拥有一个单独的画布线程。“单独的”画布只能通过SurfaceView. LunarLanding 就是这种用途的一个很好的例子。每个帧都是单独计算的,主视图只共享 CPU 时间,而不共享绘制时间。因此,即使结合顶部的常规视图和底部的动画视图,速度也会更快。

但如果您处于该共享环境中,则必须设置一个间隔。该间隔用于 FPS 上限。如果您不设置 FPS 上限,那么 CPU 将疯狂运行,以获取良好的动画(如果SurfaceView它是单独的)。将其限制在 60fps 甚至更低,可以有效地绘制所有视图,而不会造成 CPU 过载。

因此,请从 API 演示中查看登月的绘制线程并设置 FPS 上限。

private long timeNow;
    private long timeDelta;
    private long timePrevFrame;

    private void capFps(int fps) {  
            timeNow = System.currentTimeMillis();
            timeDelta = timeNow - timePrevFrame;        

            try {
Run Code Online (Sandbox Code Playgroud)

//ps 对于60FPS你总是可以设置16而不是1000/fps以避免每次计算

Thread.sleep((1000 / fps) - timeDelta);
            } catch (InterruptedException e) {

            }   

            timePrevFrame = System.currentTimeMillis();
    }
Run Code Online (Sandbox Code Playgroud)

然后绘图线程将如下所示:

@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);
                }
            }

        }
    }
Run Code Online (Sandbox Code Playgroud)