Mark Cameron
Mark Cameron

Reputation: 2369

Android Canvas: make a drawn line fade/alphaAnimation away on touch

I have a Canvas on which I am drawing lines bewteen points in a onTouchEvent(). When the user makes an invalid selection on where to place the line, I draw a red line instead of a black one. However I want the red line to fade away over the next 500-1000ms.

I haven't been able to figure out how to do it, and if it is even possible to animate a single line inside a Canvas.

I have split the dots, the valid black lines and the invalid red line(s) between 3 different bitmaps inside my:

public void onDraw(Canvas canvas) {
    // Fade Red Line
    canvas.drawBitmap(fBitmap, 0, 0, null);
    // Lines
    canvas.drawBitmap(mBitmap, 0, 0, null);
    // Dots
    canvas.drawBitmap(iBitmap, 0, 0, null); 
}

and inside my onTouch function are my drawLines().

I was wondering if I can use an AlphaAnimation for this, or if I have to use a timer system to loop over the fBitmap with the red line I want to fade out over time.

Any Ideas?

EDIT: Okay here's how I eventually solved it after coming back to it a year later:

I implemented a SurfaceView and created a thread to continuously update the Canvas.

@Override
public void run() {
    while (isRunning) {
        if (!surfaceHolder.getSurface().isValid()) {
            continue;
        }

        decreaseLineOpacity();
        drawLinesInvalid();

        /* Other things to draw*/

        Canvas canvas = surfaceHolder.lockCanvas();

        canvas.drawBitmap(fBitmap, centerPointWidth, centerPointHeight, null);
        // mBitmap is the middleground with the line that fades away.
        // and is bound to mCanvas for drawing
        canvas.drawBitmap(mBitmap, centerPointWidth, centerPointHeight, null);
        canvas.drawBitmap(iBitmap, centerPointWidth, centerPointHeight, null);

        surfaceHolder.unlockCanvasAndPost(canvas);
    }
}

And then the methods that take care of changing the opacity and drawing the line, I store each line I draw in a Queue, until it reaches an opacity of 0, and then I remove it so only the lines that need to be animated are left:

    private void drawLinesInvalid() {
        Iterator<int[]> iterator = invalidLines.iterator();
        // Loop through each element in the Queue, delete it from the bitmap with the porter
        // duff mode to keep the transparancy of the layer. Then draw line with the given opacity
        while (iterator.hasNext()) {
            int[] invalidLine = iterator.next();
            float[] line = {invalidLine[1], invalidLine[2], invalidLine[3], invalidLine[4]};
            Xfermode originalXfermode = paint.getXfermode();
            paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.CLEAR));
            mCanvas.drawLines(line, paint);
            paint.setXfermode(originalXfermode);

            paint.setColor(Color.RED);
            paint.setAlpha(invalidLine[0]);

            mCanvas.drawLines(line, paint);

        }
    }

// Call this function in the onTouch method
    private void addLineToInvalidList(float[] line) {
        // Store each line a queue with its current opacity
        int[] lineWithOpacity = new int[5];
        lineWithOpacity[0] = 250;
        lineWithOpacity[1] = (int) line[0];
        lineWithOpacity[2] = (int) line[1];
        lineWithOpacity[3] = (int) line[2];
        lineWithOpacity[4] = (int) line[3];
        invalidLines.add(lineWithOpacity);
    }

    private void decreaseLineOpacity() {
        Iterator<int[]> iterator = invalidLines.iterator();
        // Remove all lines that are finished animating (opacity = 0)
        while (iterator.hasNext()) {
            int[] line = iterator.next();
            if (line[0] == 0) {
                iterator.remove();
            }
        }

        // Decrease opacity on lines that are left
        iterator = invalidLines.iterator();
        while (iterator.hasNext()) {
            int[] line = iterator.next();
            line[0] -= 10;
        }
    }

Upvotes: 0

Views: 2707

Answers (1)

Che Jami
Che Jami

Reputation: 5151

Considering you are drawing all three bitmaps on the same view, using an AlphaAnimation may be a bit tricky.

I would suggest spawning a thread that changes the alpha value of the invalid red line(s) bitmap over time (sleeping for set intervals with Thread.sleep). However, for this to perform well you should look into using a SurfaceView as calling postInvalidate multiple times may be quite costly (unless this is running on Android 3.0+ with hardware acceleration).

Upvotes: 1

Related Questions