具有透明度

时间:2016-04-28 14:01:10

标签: android android-canvas transparency surfaceview

我的绘图应用程序有问题。我需要抓住正确的触摸屏并将它们绘制到画布上。改变画笔的大小是正常的。但是当我更改透明度设置时,程序无法正常工作。它在前一个路径上施加了新的路径,并且透明度丢失了。 Screenshot。哪里可能出错?我需要你的帮助。谢谢。

这是我的SurfaceView代码:

    public class PainterView extends SurfaceView implements SurfaceHolder.Callback {

    private PainterThread painterThread;
    private BrushParameters brushParameters;
    private Bitmap bitmap;


    public PainterView(Context context, AttributeSet attrs) {
        super(context, attrs);
        SurfaceHolder holder = getHolder();
        holder.addCallback(this);

        brushParameters = new BrushParameters();

    }

    @Override
    public void surfaceCreated(SurfaceHolder surfaceHolder) {
        setWillNotDraw(false);
        getThread().setRunning(true);
        getThread().start();
    }

    @Override
    public void surfaceChanged(SurfaceHolder surfaceHolder, int i, int width, int height) {
        if (bitmap == null) {
            bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
            getThread().setBitmap(bitmap, true);
        } else {
            getThread().setBitmap(bitmap, false);
        }

    }

    @Override
    public void surfaceDestroyed(SurfaceHolder surfaceHolder) {
        getThread().setRunning(false);
        boolean retry = true;
        while (retry) {
            try {
                getThread().join();
                retry = false;
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        painterThread = null;
    }

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

        switch (event.getAction()) {
            case MotionEvent.ACTION_DOWN:
                painterThread.startDraw(x, y);
                break;
            case MotionEvent.ACTION_MOVE:
                painterThread.continueDraw(x, y);
                break;
            case MotionEvent.ACTION_UP:
            case MotionEvent.ACTION_CANCEL:
                painterThread.finishDraw(x, y);
                break;
        }
        return true;
    }

    @Override
    protected void onDraw(Canvas canvas) {
        canvas.drawBitmap(bitmap, 0, 0, null);
    }

    public BrushParameters getBrushParameters() {
        return brushParameters;
    }

    public void setBrushColor(int color) {
        brushParameters.setColor(color);
        getThread().setBrushParameters(brushParameters);
    }

    public void setBrushSize(int size) {
        brushParameters.setSize(size);
        getThread().setBrushParameters(brushParameters);
    }

    public void setBrushAlpha(int alpha) {
        brushParameters.setAlpha(alpha);
        getThread().setBrushParameters(brushParameters);
    }

    public PainterThread getThread() {
        if (painterThread == null) {
            painterThread = new PainterThread(getHolder(), this);
        }
        return painterThread;
    }
}

我的Thread课程:

    public class PainterThread extends Thread {

    private SurfaceHolder surfaceHolder;
    private PainterView painterView;
    private boolean running = false;
    private Paint paint;
    private Path path;
    private Bitmap mBitmap;
    private Canvas mCanvas;

    private float lastX, lastY;

    private static float TOUCH_TOLERANCE = 4;

    public PainterThread(SurfaceHolder surfaceHolder, PainterView painterView) {
        this.surfaceHolder = surfaceHolder;
        this.painterView = painterView;

        path = new Path();
        paint = new Paint();
        paint.setAntiAlias(true);
        paint.setDither(true);
        paint.setColor(Color.BLACK);
        paint.setAlpha(255);
        paint.setStyle(Paint.Style.STROKE);
        paint.setStrokeWidth(5);
        paint.setStrokeJoin(Paint.Join.ROUND);
        paint.setStrokeCap(Paint.Cap.ROUND);
    }

    public void setRunning(boolean running) {
        this.running = running;
    }

    @Override
    public void run() {
        Canvas mCanvas;
        while (running) {
            mCanvas = null;
            try {
                mCanvas = surfaceHolder.lockCanvas(null);
                synchronized (surfaceHolder) {
                    if (mCanvas != null) {
                        mCanvas.drawBitmap(mBitmap, 0, 0, paint);
                        painterView.postInvalidate();
                    }
                }
            } finally {
                if (mCanvas != null) {
                    surfaceHolder.unlockCanvasAndPost(mCanvas);
                }
            }
        }
    }

    public void setBitmap(Bitmap bitmap, boolean clear) {
        mBitmap = bitmap;
        if (clear) {
            mBitmap.eraseColor(Color.WHITE);
        }
        mCanvas = new Canvas(mBitmap);
    }

    public void setBrushParameters(BrushParameters brushParameters) {
        paint.setColor(brushParameters.getColor());
        paint.setAlpha(brushParameters.getAlpha());
        paint.setStrokeWidth(brushParameters.getSize());
    }

    public void startDraw(float x, float y) {
        path.reset();
        path.moveTo(x, y);
        lastX = x;
        lastY = y;
    }

    public void continueDraw(float x, float y) {

        float dx = Math.abs(x - lastX);
        float dy = Math.abs(y - lastY);

        if (dx >= TOUCH_TOLERANCE || dy >= TOUCH_TOLERANCE) {
            path.quadTo(lastX, lastY, (x + lastX) / 2, (y + lastY) / 2);
            mCanvas.drawPath(path, paint);
            lastX = x;
            lastY = y;
        }
    }

    public void finishDraw(float x, float y) {

        path.moveTo(x, y);
        mCanvas.drawPath(path, paint);
    }
}

感谢您的帮助。找不到问题的原因,我失去了fiew的日子......

1 个答案:

答案 0 :(得分:0)

我建议摆脱SurfaceView。你有一些看起来很混乱的代码(例如setBitmap()设置mCanvas,但这会被run())循环覆盖,我认为你只是让自己的生活更加艰难

SurfaceViews有两个部分,Surface和View。 Surface是一个单独的图层(默认情况下)位于View图层后面。 SurfaceView的View部分通常只是一个透明孔,可让您“透视”后面的Surface层。

在您的情况下,您已在View对象中覆盖onDraw(),因此您实际上是在View中绘图。在你的另一个线程中,你将相同的Bitmap绘制到Surface上。即使您的位图具有透明像素,您也会看到两个相同的位图层叠在一起。

看起来你在两个同时执行的线程之间共享一个Bitmap和一个Canvas,这是一个不快乐的秘诀。

如果你摆脱SurfaceView,只使用custom View,我认为一切都会更有意义。另一种方法是摆脱onDraw()和调用postInvalidate()并在Surface上执行所有操作,但是为了利用硬件加速渲染,最好使用自定义视图。