Android:在画布上反复绘制相同的位图时出现问题

时间:2011-03-11 20:21:49

标签: android image canvas bitmap

所以我有一个从资源文件(PNG图像)加载的位图:

Bitmap map = BitmapFactory.decodeResource(getResources(), R.drawable.wave);

如果我使用canvas.drawBitmap(...);仅绘制一次此位图,则没有问题。但是,如果我多次绘制相同的位图,那么图像会一直闪烁,而不像以前那样稳定。

我怀疑我不能多次使用相同的位图,因此我每次想要绘制相同的图片时都尝试将图像加载到新的位图中,但它没有帮助,行为仍然存在。

程序很复杂,但基本上,我想绘制海浪。我有一个小波浪的图像。使波浪的效果从屏幕的左边缘移动到右边缘。我跟踪位图左边缘的位置。

// The ocean.
private ArrayList<Wave> waves;

            // Draw the waves and update their positions.
    for (int i = 0; i < this.waves.size(); i++)
    {
        Wave wave = this.waves.get(i);

        // Go through each of the sub-waves of this current wave.
        for (int j = 0; j < wave.getSubWaveEdges().size(); j++)
        {
            // Get the sub wave.
            final float subWaveEdge = wave.getSubWaveEdges().get(j);

            canvas.drawBitmap( wave.getSubWave(j), subWaveEdge, 40, brush);

            wave.setSubWaveEdge(j, subWaveEdge + (float) 0.5);
        }

        // Update this current wave.
        wave.update();

        // If the wave has passed the left edge of the screen then add a new sub-wave.
        if (wave.getFarthestEdge() >= 0)
            wave.addSubWaveEdges(wave.getFarthestEdge() - this.getWidth());
    }

如果位图的左边缘在屏幕内,那么我从同一图像文件创建一个新的位图并绘制。这是Wave类:

    private class Wave
{
    private Bitmap wave;
    private float farthestEdge;
    private ArrayList<Float> subWaveEdges;
    private ArrayList<Bitmap> subWaves;

    public Wave(Bitmap wave)
    {   
        this.wave = wave;

        this.farthestEdge = 0;

        this.subWaveEdges = new ArrayList<Float>();

        this.subWaves = new ArrayList<Bitmap>();
    }

    public Bitmap getWave ()
    { return this.wave; }

    public void setWave (Bitmap wave)
    { this.wave = wave; }

    public float getFarthestEdge ()
    { return this.farthestEdge; }

    public void setFarthestEdge (final float furthestEdge)
    { this.farthestEdge = furthestEdge; }

    public ArrayList<Float> getSubWaveEdges ()
    { return subWaveEdges; }

    public void setSubWaveEdge (final int index, final float value)
    {
        this.subWaveEdges.remove(index);

        this.subWaveEdges.add(value);
    }

    public void addSubWaveEdges (final float edge)
    {
        this.subWaveEdges.add(edge);

        Bitmap newSubWave = BitmapFactory.decodeResource(getResources(), R.drawable.wave);

        newSubWave = Bitmap.createScaledBitmap(newSubWave, MasterView.this.getWidth(), newSubWave.getHeight(), true);

        this.subWaves.add(newSubWave);
    }

    public Bitmap getSubWave(final int index)
    { return this.subWaves.get(index); }

    public void update ()
    {

        // Check to see if there is any sub-wave going outside of the screen.
        // If there is then remove that wave.
        for (int index = 0; index < this.subWaveEdges.size(); index++)
            if (this.subWaveEdges.get(index) > MasterView.this.getWidth())
            {
                this.subWaveEdges.remove(index);

                this.subWaves.remove(index);
            }

        // Set the farthest edge to the other side of the screen.
        this.farthestEdge = MasterView.this.getWidth();

        // Get the farthest edge of the wave.
        for (int index = 0; index < this.subWaveEdges.size(); index++)
            if (this.subWaveEdges.get(index) < this.farthestEdge)
                this.farthestEdge = this.subWaveEdges.get(index);
    }
}

我怀疑的另一个可能是当我从同一资源文件创建两个位图时,图像的像素被分成两个位图,这意味着每个位图只获得部分像素,而不是全部。我怀疑这是因为当绘制位图时,它们重叠的部分会稳定地绘制,不会闪烁。

任何人都偶然发现了这个问题并知道如何修复?

谢谢,

3 个答案:

答案 0 :(得分:1)

ViktorLannér,谢谢你的帮助,但我认为这不是问题所在。我知道很难阅读我的代码,因为它只是大型程序的一小部分。

然而,我发现了问题:我的原始问题中没有提到这个问题,但是为了模拟两个波浪相继移动,我必须在第一个波进入屏幕后立即绘制下一个波。但是,每个波长都比屏幕的宽度长。因此,如果您知道我的意思,我必须从屏幕的“外部”绘制下一波。这意味着下一个波是从屏幕外部的负x坐标绘制的:

    // If the wave has passed the left edge of the screen then add a new sub-wave.
    if (wave.getFarthestEdge() >= 0)
        wave.addSubWaveEdges(wave.getFarthestEdge() - this.getWidth());

我发现它不喜欢这个。这就是导致闪烁来回的原因。

为了解决这个问题,我不是从屏幕外部绘制下一个波形,而是使用这个方法:

     canvas.drawBitmap (Bitmap bitmap, Rect source, Rect destination, Paint paint)

此方法允许您在要绘制到屏幕的位图上指定矩形区域,并在屏幕上指定将绘制位图部分的矩形区域。我用这种方法绘制下一波。当下一个波移动到屏幕时,我会相应地更改“源”和“目标”以绘制位图的一部分。

答案 1 :(得分:1)

我只想说我有一个问题,我的画布上的图像来回闪烁,或者在黑色和我的第一帧之间闪烁,直到我做出一个动作,几乎就像画布快速切换当前和最后一张图片。

这可能与你的情况有关,并且修复它我发现这是因为我每帧都锁定画布,即使我没有任何东西可以绘制。无论出于何种原因,我认为这种锁定造成了这种情况。

通过做这样的事情我解决了这个问题:

if (needToRedraw == true) {
      canvas = mSurfaceHolder.lockCanvas(null);
      ... logic to eventually draw on that canvas ...
   }

答案 2 :(得分:0)

canvas.drawBitmap(...)致电之前;尝试使用canvas.drawColor(Color.BLACK)清除之前图纸中的Canvas

示例代码:

// Stuff.
canvas.drawColor(Color.BLACK);
canvas.drawBitmap(wave.getSubWave(j), subWaveEdge, 40, brush);
// Stuff.