1

我需要写手指画应用程序。我需要对绘制的曲线进行一些计算,所以我认为使用SurfaceView但不是View.

我已经编写了绘图代码。我将点收集到 Path 中并绘制它。在 ACTION_UP 上,此路径正在重置。在绘图循环中,我只绘制最后一条路径。

但由于某种原因,以前的路径也被重新绘制。这会导致烦人的眨眼,这是我不想要的。我在每个绘制周期都改变了线条颜色,我看到,以前的路径改变了它们的颜色,尽管没有代码来收集和重绘它们。

为什么这样?有什么办法可以让 SurfaceView 不重复之前的所有图纸?

这是我的代码:

public class OtherDrawView extends SurfaceView implements SurfaceHolder.Callback {
    private DrawingThread mThread;

    private Path mPath;

    private static final Object lock = new Object();

    public OtherDrawView(Context context, AttributeSet attrs) {
        super(context, attrs);

        SurfaceHolder surfaceHolder = getHolder();
        surfaceHolder.addCallback(this);

        mThread = new DrawingThread(surfaceHolder);

        mPath = new Path();
    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        float x = event.getX();
        float y = event.getY();

        switch (event.getAction()) {
            case MotionEvent.ACTION_DOWN:
                mPath.moveTo(event.getX(), event.getY());
                continueDrawingThread();
                return true;

            case MotionEvent.ACTION_MOVE:
                mPath.lineTo(event.getX(), event.getY());
                continueDrawingThread();
                return true;

            case MotionEvent.ACTION_UP:
                mPath.reset();
                return true;
        }

        return false;
    }

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

    @Override
    public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
    }

    @Override
    public void surfaceDestroyed(SurfaceHolder holder) {
        boolean retry = true;
        mThread.setRunning(false);
        continueDrawingThread();

        while (retry) {
            try {
                mThread.join();
                retry = false;
            }
            catch (InterruptedException ignored) { }
        }
    }

    private void continueDrawingThread() {
        synchronized (lock) {
            try {
                lock.notifyAll();
            } catch (Exception ignored) {}
        }
    }

    private class DrawingThread extends Thread {
        private boolean mRunning;

        private Paint mPaint;
        private Random mRandom = new Random(System.currentTimeMillis());

        private final SurfaceHolder mSurfaceHolder;

        public DrawingThread(SurfaceHolder surfaceHolder) {
            mSurfaceHolder = surfaceHolder;

            mPaint = new Paint();
            mPaint.setColor(Color.GREEN);
            mPaint.setStrokeWidth(5);
            mPaint.setStyle(Paint.Style.STROKE);
        }

        public void setRunning(boolean running) {
            mRunning = running;
        }

        private void drawPath() {
            Canvas canvas = null;
            try {
                canvas = mSurfaceHolder.lockCanvas();
                synchronized (mSurfaceHolder) {
                    assert canvas != null;

                    mPaint.setColor(Color.rgb(mRandom.nextInt(255), mRandom.nextInt(255), mRandom.nextInt(255)));
                    canvas.drawPath(mPath, mPaint);
                }
            }
            catch (Exception ignored) { }
            finally {
                if (canvas != null) {
                    mSurfaceHolder.unlockCanvasAndPost(canvas);
                }
            }
        }

        @Override
        public void run() {
            while (mRunning) {
                drawPath();

                synchronized (lock) {
                    try {
                        lock.wait();
                    } catch (InterruptedException ignored) {
                    }
                }
            }
        }
    }
}
4

2 回答 2

0

我仍然不明白为什么会有这样SurfaceView的行为,但我找到了一种解决方法:不是直接在画布上而是在一些位图上绘制,然后在主画布上输出这个位图。本文全面描述:http ://android-coding.blogspot.ru/2012/01/flickering-problems-due-to-double.html

于 2013-10-28T17:49:46.423 回答
0

从 unlockCanvasAndPost(Canvas) 的文档中:

“在这个调用之后,Surface 的当前像素会显示在屏幕上,但是它的内容会丢失,特别是当再次调用 lockCanvas() 时,不能保证 Surface 的内容会保持不变。”

因此,当绘制到表面视图时,您总是必须先清除背景(通常通过重新绘制背景图像),然后再在顶部绘制任何其他内容,例如。你的情况下的路径。

于 2013-10-28T21:39:44.480 回答