【问题标题】:LiveWallpaper with SurfaceHolder.lockCanvas(Rect dirty)带有 SurfaceHolder.lockCanvas(矩形脏)的 LiveWallpaper
【发布时间】:2011-03-04 07:10:36
【问题描述】:

我想问一个在这里已经解决过一两次的问题,但我找到的信息都无法帮助我克服几天前遇到的问题。

我想使用画布为 android 制作动态壁纸 - 它的图形不够复杂,不需要 OpenGL。为简单起见,假设它由纯色背景和两个较小的矩形组成。 绘图由三个独立的阶段组成(在单线程中):

  1. backgroundDraw() 请求整个画布锁定并在其上绘制纯色
  2. draw1() 请求部分 (Rect r1) 锁定并仅在锁定的矩形上绘制
  3. draw2() 请求部分 (Rect r2) 锁定并仅在锁定的矩形上绘制

我在多个 Android 版本(模拟器和设备)上对其进行了测试:2.1、2.2、2.3.3。它似乎只在后一个上正常工作(这里:http://home.elka.pw.edu.pl/~pgawron/include/Android/android_233.jpg)。在以前的 Android 版本上,SurfaceHolder.lockCanvas(Rect dirty) resized(!)dirty 作为参数传递给全屏大小,并使用它进一步绘制会导致在整个屏幕上绘制(这里:http://home.elka.pw.edu.pl/~pgawron/include/Android/android_22.jpg)。事实上,我可以看到每个矩形是如何画得不好的(全屏):整个屏幕的颜色变化非常快。

不幸的是,谷歌无法为我找到任何适当的 lockCanvas(Rect dirty) 用法示例。下面我附上我完整且唯一的用于测试目的的课程。只需在提供的屏幕截图放置位置即可访问完整的 Eclipse 项目。

如果有人最终能帮助我并更正我的代码,我将不胜感激(如果问题出在我的代码中)。我真的在这上面浪费了太多时间。

BR,

佩特雷利

package sec.polishcode.test;

import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Rect;
import android.os.SystemClock;
import android.service.wallpaper.WallpaperService;
import android.util.Log;
import android.view.SurfaceHolder;

public class TestLiveWallpaper extends WallpaperService{

@Override
public Engine onCreateEngine() {
    return new MyEngine();
}

class MyEngine extends Engine implements SurfaceHolder.Callback {

    private final String LOGTAG = MyEngine.class.getSimpleName();
    private Paint backgroundPaint = new Paint();
    private Paint mPaint1 = new Paint();
    private Paint mPaint2 = new Paint();
    private long lastVisibilityOnChange;

    private final Rect r1 = new Rect(20, 20, 60, 280);
    private final Rect r2 = new Rect(70, 20, 110, 280);

    public MyEngine() {

        getSurfaceHolder().addCallback(this);

        backgroundPaint.setColor(Color.YELLOW);
        mPaint1.setColor(Color.LTGRAY);
        mPaint2.setColor(Color.MAGENTA);
    }

    @Override
    public void surfaceChanged(SurfaceHolder arg0, int arg1, int arg2,
            int arg3) {
        drawSurface();
    }

    @Override
    public void surfaceCreated(SurfaceHolder arg0) {
        Log.i(LOGTAG, "surfaceCreated");
    }

    @Override
    public void surfaceDestroyed(SurfaceHolder arg0) {
        Log.i(LOGTAG, "surfaceDestroyed");
    }

    @Override
    public void onCreate(SurfaceHolder surfaceHolder) {
        super.onCreate(surfaceHolder);

        setTouchEventsEnabled(true);
    }

    @Override
    public void onVisibilityChanged(boolean visible) {
        if (!visible)
            return;

        lastVisibilityOnChange = SystemClock.elapsedRealtime();
        drawSurface();
    }

    @Override
    public void onOffsetsChanged(float xOffset, float yOffset, float xStep,
            float yStep, int xPixels, int yPixels) {

        if (SystemClock.elapsedRealtime() - lastVisibilityOnChange > 30)
            return;

        Log.i(LOGTAG, "onOffsetsChanged filtered");
        drawSurface();
    }

    private void drawSurface() {
        backgroundDraw();
        draw1();
        draw2();
    }

    private void backgroundDraw() {
        final SurfaceHolder holder = getSurfaceHolder();

        Canvas c = null;
        try {
            c = holder.lockCanvas();
            if (c != null) {
                c.drawRect(holder.getSurfaceFrame(), backgroundPaint);
            }
        } finally {
            if (c != null)
                holder.unlockCanvasAndPost(c);
        }
    }

    private void draw1() {
        final SurfaceHolder holder = getSurfaceHolder();

        Canvas c = null;
        try {
            c = holder.lockCanvas(r1);
            if (c != null) {
                c.drawRect(r1, mPaint1);
            }
        } finally {
            if (c != null)
                holder.unlockCanvasAndPost(c);
        }
    }

    private void draw2() {
        final SurfaceHolder holder = getSurfaceHolder();

        Canvas c = null;
        try {
            c = holder.lockCanvas(r2);
            if (c != null) {
                c.drawRect(r2, mPaint2);
            }
        } finally {
            if (c != null)
                holder.unlockCanvasAndPost(c);
        }
    }
}
}

【问题讨论】:

  • 你找到解决这个问题的方法了吗?我想知道如何为动态壁纸使用脏矩形,但没有任何运气。

标签: android surfaceholder


【解决方案1】:

lockCanvas(Rect dirty) 非常简单。请记住,在 Android 表面上,默认情况下是双缓冲的。这意味着您不仅需要重新绘制当前表面的脏区,还需要重新绘制前一个表面的脏区以使其正常工作。这就是为什么 lockCanvas() 将调整您传递的矩形的大小:它告诉真正的脏区域是什么。脏区域也可能因为表面被丢弃和重新创建等而改变。使用 lockCanvas(Rect) 的正确方法是传递脏矩形,然后检查它的新值并尊重它们。

【讨论】:

  • 感谢您的解释,这正是我的问题......不幸的是,检查官方 API 并没有说明当整个屏幕变脏时自动调整脏矩形的大小
  • 当然可以:“例如,如果表面已调整大小或表面的先前内容不可用,此函数可能会选择扩展脏矩形。”
  • 啊刚刚发现在Surface..在看SurfaceHolder
猜你喜欢
  • 2010-09-09
  • 2021-06-03
  • 2011-07-21
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-09-21
相关资源
最近更新 更多