【问题标题】:How can I draw an animated view in android?如何在android中绘制动画视图?
【发布时间】:2011-10-01 12:15:21
【问题描述】:

我从头开始创建了一个自定义视图。扩展 View 并覆盖 onDraw()。 当在动画视图中下降时,我使用偏移量生成自定义动画。 例如。

while(!isOnTop){
mOffset++;

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

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

}

我的想法是我的框架来自 invalidate it self。问题是这个视图的失效可以通过在同一屏幕上滚动列表视图来实现。

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

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

是否只有在 10 个无效请求中以较大步长执行动画的解决方案?它会缓解延迟,但我认为我可以使用不同的方法。

【问题讨论】:

    标签: android android-layout android-canvas android-view


    【解决方案1】:

    “什么是最好的”当然在很大程度上取决于你想要做什么。你还没有说你想要完成什么,所以我们只能猜测什么可能最适合你。

    这里有一些简单的事情:

    这是一个简单的使用 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);
    }
    

    【讨论】:

    • invalidate() 不是即时的。可能需要超过 20 毫秒,因为需要使大量视图无效。视图必须等到所有视图都完成(至少在 3.0 之前)。 postDelayed 然后会引入更多的延迟。那样限制fps不好。如果我错了,请纠正我。
    • 并非如此。如果 invalidate() 花费的时间超过 20 毫秒,那么您在如何构建视图层次结构方面会遇到严重问题。标准平台窗口中的绝大多数动画都使用带有invalidate()的常规视图,并且可以达到60fps。你只需要确保你不会在你的视图层次结构中做任何事情,比如有多个大的不透明位图在彼此之上或缩放使绘制它们变慢......但无论如何你不想这样做。
    • fps 不依赖于硬件和当前的 cpu/gpu/memory 负载吗? IE。如果一致的动画时间很重要,我认为应该(有效地)在运行时测量 fps 并相应地确定延迟时间。
    【解决方案2】:

    由于这个问题有点兴趣,所以我会回答。

    最好的方法是有一个单独的画布线程。 “单独的”画布只能通过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 {
    

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

    【讨论】:

    • 抱歉,这方式比通常需要的要复杂,SurfaceView 有许多折衷方案,因此通常不是最佳解决方案。
    • 是的,但最好是同时拥有多个动画视图。问题是什么是“最好”的方式,虽然谢谢你的回答
    • 这个其实是我从j2me熟悉的方式。如果您不喜欢这些计算,您可以随时跳过它并在固定的时间内休眠。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-06-05
    • 1970-01-01
    • 1970-01-01
    • 2019-04-10
    • 1970-01-01
    相关资源
    最近更新 更多