在画布上延迟绘制 - “让onDraw()减速”

6

我在安卓中使用像“drawCircle”和“drawPoint”这样的canvas函数,效果很好。

但是现在的问题是如何延迟绘制这些不同的图形,以使其看起来像动画。

我应该使用什么样的机制?尝试了异步方式,但我不喜欢它。

我应该使用一种定时器来定时绘制,还是有其他聪明的方法来做到这一点?

3个回答

3

我使用这种策略,首先声明一个 Handler 和一个 Runnable:

    private final Observable mObservable = new Observable();
    private final static int TIME_STEP_MS = 5;
    private final Handler mHandler = new Handler();
    private final Runnable mTimeManager = new Runnable() 
    {
        public void run() 
        {
            mObservable.notifyObservers(TIME_STEP_MS);
            mHandler.postDelayed(mTimeManager, TIME_STEP_MS);
        }
    };

当我想要启动我的时间管理器时,只需调用mTimeManager.run(),它将开始定期通知已添加的观察者(Observer)。

如果由于某种原因需要停止计时器或其他操作,只需执行以下操作:

    mHandler.removeCallbacks(mTimeManager);

[ 编辑 - 更完整的代码 ]

好的,那么让我们更清晰地阐述一下。首先,我创建了一个自定义的可观察对象,就像这样[这是可选的]:

    private final Observable mObservable = new Observable()
    {
        public void notifyObservers()
        {
            setChanged();
            super.notifyObservers();
        };

        @Override
        public void notifyObservers(Object data) 
        {
            setChanged();
            super.notifyObservers(data);
        };
    };

那是因为我无法在Observable类之外调用setChanged()方法——它是受保护的,如果没有更改,就不会通知任何观察者。其他声明与之前相同,现在我需要在某个地方启动这个TimeManager,我的应用程序是一个LiveWallpaper,我将所有渲染内容放入一个扩展Thread类的类中,但您不一定需要这样做,我创建了一个名为resumeDrawing()的方法,它在我的public synchronized void start()方法的@Override中的super.start()后立即调用,该方法如下:
    public void resumeDrawing()
    {
        if (!mTimeManagerRunning) // just a boolean field in my class
        {
            System.err.println("Resuming renderer."); // just for debug
            mTimeManager.run();
            mTimeManagerRunning = true;
        }
        else
        {
            System.err.println("Renderer already running."); // just for debug
        }
    }

并且它的对偶:

    public void pauseDrawing()
    {
        if (mTimeManagerRunning)
        {
            System.err.println("Pausing renderer.");
            mHandler.removeCallbacks(mTimeManager);
            mTimeManagerRunning = false;
        }
        else
        {
            System.err.println("Renderer already paused.");
        }
    }

好的,现在我们可以启动和停止时间管理器,但是有谁在监听呢?没有人!所以让我们添加它们:在我的渲染器的构造函数中,我向我的mObservable对象添加了一些Observer s,其中之一就是渲染器本身,因此我的渲染器扩展了Thread并实现了Observer

    @Override // from Observer interface
    public void update(Observable arg0, Object arg1) 
    {
        mElapsedMsRedraw += (Integer) arg1; 

        if (mElapsedMsRedraw >= mDrawingMsPerFrame)
        {
            mElapsedMsRedraw = 0;
            drawEm(); // refresh the canvas and stuff
        }
    }

要添加观察者,只需执行mObservable.addObserver(THE_OBJECT - Implements Observer)
您可以看到,每次收到通知时,我不重新渲染我的内容,因为我使用此TimeManager进行其他操作,而不仅仅是刷新Canvas,例如更新我想要绘制的对象的位置。
因此,要减慢绘图速度,您需要更改对象在时间流逝时内部的变化方式,例如圆和点等,或者更改时间步长,我建议您选择第一种方法。
清楚了吗?希望能对您有所帮助。

谢谢,但您能否提供一个更完整的示例?展示实现过程。 - FooBar
当然,我现在正在工作,这是我能记得的代码片段。我将在20分钟内离开,所以尽快给你更完整的代码。 - HericDenis
好的 @FooBar,我现在回家了,我会帮助你的 (: - HericDenis
@FooBar,请考虑为我点赞并将其标记为答案,如果它对您有用的话。 - HericDenis
谢谢你的回答。它对我有所帮助,现在我走在了正确的道路上。 - FooBar
不客气,@FooBar,如果可以的话,您能否将其标记为答案(即在投票下面的那个勾选框),这样它就会变成绿色了 :) 如果您对此有任何其他问题,请随时提出。 - HericDenis

1
我会使用计时器或创建动画。您可以创建各种动画,包括随时间改变透明度等功能。
这里是Android文档中有关动画资源的内容。

0

我相信可能有更复杂的方法来实现这个,但是对于我的需求,我使用了一个简单的方法,它有很多优点: 我首先为每个绘图点创建坐标(和任何其他所需数据)的记录,而不是在现场绘制点,然后使用计时器(最好是Android处理程序)进行复制。这也提供了许多实际绘图时的可能性:暂停、加快/减慢速度、倒退等等。 我不知道这种方法是否适用于复杂的绘图,但对于绘制形状、曲线、表面等来说是可以的。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接