表面视图闪烁

发布于 2024-10-31 22:24:32 字数 3633 浏览 0 评论 0原文

我有闪烁问题。 这是我的代码。

public class Tutorial2D3 extends Activity {

Panel panel;
/** Called when the activity is first created. */
@Override
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    panel = new Panel(this);
    setContentView(panel);
}

@Override
public boolean onCreateOptionsMenu(Menu menu) {
    menu.add(1, 1, 1, "Clean Canvas");
    return super.onCreateOptionsMenu(menu);
}

@Override
public boolean onMenuItemSelected(int featureId, MenuItem item) {
    panel.cleanCanvas();
    return true;
}

class Panel extends SurfaceView implements SurfaceHolder.Callback {
    TutorialThread thread;
    Bitmap icon;
    int iconWidth;
    int iconHeight;
    int touchX;
    int touchY;
    int mCount = 0;

    public Panel(Context context) {
        super(context);
        icon = BitmapFactory
                .decodeResource(getResources(), R.drawable.icon);
        iconWidth = icon.getWidth();
        iconHeight = icon.getHeight();
        getHolder().addCallback(this);
        thread = new TutorialThread(getHolder(), this);
        setFocusable(true);
    }

    @Override
    protected void onDraw(Canvas canvas) {
        int x = touchX - (iconWidth / 2);
        int y = touchY - (iconHeight / 2);
        if(mCount>0) {
            canvas.drawColor(Color.BLACK);
            mCount--;
        }
        canvas.drawBitmap(icon, (x > 0 ? x : 0), (y > 0 ? y : 0), null);    
    }

    @Override
    public void surfaceChanged(SurfaceHolder holder, int format, int width,
            int height) {
        // TODO Auto-generated method stub

    }

    @Override
    public void surfaceCreated(SurfaceHolder holder) {
        thread.setRunning(true);
        thread.start();
    }

    @Override
    public void surfaceDestroyed(SurfaceHolder holder) {
        boolean retry = true;
        thread.setRunning(false);
        do {
            try {
                thread.join();
                retry = false;
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        } while (retry);
    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        switch (event.getAction()) {
        case MotionEvent.ACTION_DOWN:
            touchX = (int) event.getX();
            touchY = (int) event.getY();
            break;
        case MotionEvent.ACTION_MOVE:
            touchX = (int) event.getX();
            touchY = (int) event.getY();
            break;
        case MotionEvent.ACTION_UP:
            break;
        default:
            break;
        }
        return true;
    }

    private void cleanCanvas() {
        mCount = 2;
    }
}



class TutorialThread extends Thread {
    private SurfaceHolder _surfaceHolder;
    private Panel _panel;
    private boolean _run = false;

    public TutorialThread(SurfaceHolder surfaceHolder, Panel panel) {
        _surfaceHolder = surfaceHolder;
        _panel = panel;
    }

    public void setRunning(boolean run) {
        _run = run;
    }

    @Override
    public void run() {
        Canvas c;
        while (_run) {
            c = null;
            try {
                c = _surfaceHolder.lockCanvas(null);
                synchronized (_surfaceHolder) {
                    _panel.onDraw(c);
                }
            } finally {
                if (c != null) {
                    _surfaceHolder.unlockCanvasAndPost(c);
                }
            }
        }
    }
}

绘制

的图像闪烁。 看起来在一个点上绘制的位图是在一个表面上绘制的,而不是在另一个表面上绘制的,所以它看起来像闪烁,当我们触摸action_up完成时绘制的位图,这是一个实体图像并且不闪烁。有人可以帮我解决这个问题吗? 谢谢

I have a problem with the flickering.
Here is my code.

public class Tutorial2D3 extends Activity {

Panel panel;
/** Called when the activity is first created. */
@Override
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    panel = new Panel(this);
    setContentView(panel);
}

@Override
public boolean onCreateOptionsMenu(Menu menu) {
    menu.add(1, 1, 1, "Clean Canvas");
    return super.onCreateOptionsMenu(menu);
}

@Override
public boolean onMenuItemSelected(int featureId, MenuItem item) {
    panel.cleanCanvas();
    return true;
}

class Panel extends SurfaceView implements SurfaceHolder.Callback {
    TutorialThread thread;
    Bitmap icon;
    int iconWidth;
    int iconHeight;
    int touchX;
    int touchY;
    int mCount = 0;

    public Panel(Context context) {
        super(context);
        icon = BitmapFactory
                .decodeResource(getResources(), R.drawable.icon);
        iconWidth = icon.getWidth();
        iconHeight = icon.getHeight();
        getHolder().addCallback(this);
        thread = new TutorialThread(getHolder(), this);
        setFocusable(true);
    }

    @Override
    protected void onDraw(Canvas canvas) {
        int x = touchX - (iconWidth / 2);
        int y = touchY - (iconHeight / 2);
        if(mCount>0) {
            canvas.drawColor(Color.BLACK);
            mCount--;
        }
        canvas.drawBitmap(icon, (x > 0 ? x : 0), (y > 0 ? y : 0), null);    
    }

    @Override
    public void surfaceChanged(SurfaceHolder holder, int format, int width,
            int height) {
        // TODO Auto-generated method stub

    }

    @Override
    public void surfaceCreated(SurfaceHolder holder) {
        thread.setRunning(true);
        thread.start();
    }

    @Override
    public void surfaceDestroyed(SurfaceHolder holder) {
        boolean retry = true;
        thread.setRunning(false);
        do {
            try {
                thread.join();
                retry = false;
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        } while (retry);
    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        switch (event.getAction()) {
        case MotionEvent.ACTION_DOWN:
            touchX = (int) event.getX();
            touchY = (int) event.getY();
            break;
        case MotionEvent.ACTION_MOVE:
            touchX = (int) event.getX();
            touchY = (int) event.getY();
            break;
        case MotionEvent.ACTION_UP:
            break;
        default:
            break;
        }
        return true;
    }

    private void cleanCanvas() {
        mCount = 2;
    }
}



class TutorialThread extends Thread {
    private SurfaceHolder _surfaceHolder;
    private Panel _panel;
    private boolean _run = false;

    public TutorialThread(SurfaceHolder surfaceHolder, Panel panel) {
        _surfaceHolder = surfaceHolder;
        _panel = panel;
    }

    public void setRunning(boolean run) {
        _run = run;
    }

    @Override
    public void run() {
        Canvas c;
        while (_run) {
            c = null;
            try {
                c = _surfaceHolder.lockCanvas(null);
                synchronized (_surfaceHolder) {
                    _panel.onDraw(c);
                }
            } finally {
                if (c != null) {
                    _surfaceHolder.unlockCanvasAndPost(c);
                }
            }
        }
    }
}

}

The drawn image flickers.
It looks like the bitmap that is drawn at one point is drawn on one surface and not the other so it looks like flickering, the bitmap that is drawn when we touch action_up is done, that is a solid image and does not flickers. Could someone please help me with this one.
Thanks

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

悲念泪 2024-11-07 22:24:33

我没有阅读您的全部代码,但我认为这篇文章将会有所帮助。

本文的本质是,闪烁是由于双缓冲造成的,可以通过不绘制到参数 Canvas 而是绘制到用作画布的位图,然后将该位图绘制到 arg Canvas 来消除:

int myCanvas_w, myCanvas_h;
Bitmap myCanvasBitmap = null;
Canvas myCanvas = null;
Matrix identityMatrix;

@Override
public void surfaceCreated(SurfaceHolder holder) {

myCanvas_w = getWidth();
myCanvas_h = getHeight();
myCanvasBitmap = Bitmap.createBitmap(myCanvas_w, myCanvas_h, Bitmap.Config.ARGB_8888);
myCanvas = new Canvas();
myCanvas.setBitmap(myCanvasBitmap);

identityMatrix = new Matrix();
}

@Override
protected void onDraw(Canvas canvas) {

paint.setStyle(Paint.Style.STROKE);
 paint.setStrokeWidth(3);

 //int w = myCanvas.getWidth();
 //int h = myCanvas.getHeight();
 int x = random.nextInt(myCanvas_w-1);
 int y = random.nextInt(myCanvas_h-1);
 int r = random.nextInt(255);
 int g = random.nextInt(255);
 int b = random.nextInt(255);

 paint.setColor(0xff000000 + (r << 16) + (g << 8) + b);
 myCanvas.drawPoint(x, y, paint); // <--------- Here's where you draw on your bitmap

 canvas.drawBitmap(myCanvasBitmap, identityMatrix, null);
 // ^---------- And here's where you draw that bitmap to the canvas

}

I didn't read through all of your code, but I think this article will help.

The essence of the article is that flickering is due to double buffering and can be eliminated by drawing not to the argument Canvas but to a bitmap used as the canvas and then drawing that bitmap to the arg Canvas:

int myCanvas_w, myCanvas_h;
Bitmap myCanvasBitmap = null;
Canvas myCanvas = null;
Matrix identityMatrix;

@Override
public void surfaceCreated(SurfaceHolder holder) {

myCanvas_w = getWidth();
myCanvas_h = getHeight();
myCanvasBitmap = Bitmap.createBitmap(myCanvas_w, myCanvas_h, Bitmap.Config.ARGB_8888);
myCanvas = new Canvas();
myCanvas.setBitmap(myCanvasBitmap);

identityMatrix = new Matrix();
}

@Override
protected void onDraw(Canvas canvas) {

paint.setStyle(Paint.Style.STROKE);
 paint.setStrokeWidth(3);

 //int w = myCanvas.getWidth();
 //int h = myCanvas.getHeight();
 int x = random.nextInt(myCanvas_w-1);
 int y = random.nextInt(myCanvas_h-1);
 int r = random.nextInt(255);
 int g = random.nextInt(255);
 int b = random.nextInt(255);

 paint.setColor(0xff000000 + (r << 16) + (g << 8) + b);
 myCanvas.drawPoint(x, y, paint); // <--------- Here's where you draw on your bitmap

 canvas.drawBitmap(myCanvasBitmap, identityMatrix, null);
 // ^---------- And here's where you draw that bitmap to the canvas

}
舟遥客 2024-11-07 22:24:32

当您在 SurfaceView 的 Canvas 中绘图时,您必须始终绘制表面的每个像素
在这里,您并不总是在 onDraw() 中清除 Canvas,因此会闪烁。

When you are drawing in the Canvas of a SurfaceView, you must always draw every pixel of the surface.
Here you are not always clearing the Canvas in onDraw(), hence the flickering.

温柔一刀 2024-11-07 22:24:32

您可以做的一件事来减轻这种情况(并且有点矛盾 Guillaume :))是使用 surfaceholder.lockCanvas(rectangle) ,其中它只是画布的指定矩形部分,然后绘制(但您必须绘制每个像素)那个矩形)。这是从 LunarLandar 样本中截取的:

@Override
    public void run() {
        while (mRun) {
            Canvas c = null;
            try {
                c = mSurfaceHolder.lockCanvas(Rectangle);
                synchronized (mSurfaceHolder) {
                    if (mMode == STATE_RUNNING) updatePhysics();
                    doDraw(c);
                }
            } finally {
                // do this in a finally so that if an exception is thrown
                // during the above, we don't leave the Surface in an
                // inconsistent state
                if (c != null) {
                    mSurfaceHolder.unlockCanvasAndPost(c);
                }
            }
        }
    }

One thing you could do to mitigate that (and to kinda contradict Guillaume :)) is to use surfaceholder.lockCanvas(rectangle), where it is only the specified rectangle part of the canvas which is then drawn (but you must draw every pixel of that rect). Here it is, ripped from the LunarLandar sample:

@Override
    public void run() {
        while (mRun) {
            Canvas c = null;
            try {
                c = mSurfaceHolder.lockCanvas(Rectangle);
                synchronized (mSurfaceHolder) {
                    if (mMode == STATE_RUNNING) updatePhysics();
                    doDraw(c);
                }
            } finally {
                // do this in a finally so that if an exception is thrown
                // during the above, we don't leave the Surface in an
                // inconsistent state
                if (c != null) {
                    mSurfaceHolder.unlockCanvasAndPost(c);
                }
            }
        }
    }
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文