1

What I'm trying to achieve:

This is the first time I've used a SurfaceView, mulitthreading and a touch events. I'm trying to mask a rectangular bitmap image using a circular bitmap mask. I've been attemping to do this in a thread inside a SurfaceView. This SurfaceView also has an onTouch() method where when I drag the image it will move relative to the mask which will remain stationary.

The problem:

The mask works with the following code but only on the first iteration of the while loop. When it hits unlockCanvasAndPost(canvas) the second time around it overlays the mask as an image on top of the underlying bitmap and masking ceases taking effect. Fixed, still having problems with the redraw in the ontouch event - see below.

@Override
public void run() {

    while(isRunnable){
        // draw to the canvas

        //if the surface isn't available go back to the top of the loop
        if(!surfaceHolder.getSurface().isValid()){
            continue;
        }
        result = Bitmap.createBitmap(maskImage.getWidth(), maskImage.getHeight(), Bitmap.Config.ARGB_8888);

        //lock the canvas before trying to draw to it
        canvas = surfaceHolder.lockCanvas();
        maskPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
        maskPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.DST_IN));


        Canvas tempCanvas = new Canvas(result);
        //draw the bitmaps to the canvas
        canvas.drawARGB(255, 255, 255, 255);
        tempCanvas.drawBitmap(userIconImage, imageX, imageY, null);
        tempCanvas.drawBitmap(maskImage, maskX, maskY, maskPaint);
        maskPaint.setXfermode(null);
        canvas.drawBitmap(result,0,0,new Paint());
        surfaceHolder.unlockCanvasAndPost(canvas);

        result = null;

    }

}// run()

What I've tried:

This basically works. But when I drag to reposition the imgage in onTouch() I get traces of the previously drawn image. According to android.developer.com you can avoid this by using drawBitmap() Canvas and Drawables - SurfaceView section. This is what I'm trying to do, but apparently incorrectly. I also don't like that I have to continually create objects inside the while loop and would like to avoid it if possible.

My onTouch() method is currently like so:

@Override
public boolean onTouch(View v, MotionEvent motionEvent) {

   try{
       Thread.sleep(50);
   }catch (InterruptedException e){
        e.printStackTrace();
   }

    switch (motionEvent.getAction()){

        case MotionEvent.ACTION_MOVE:
            imageX = motionEvent.getX();
            imageY = motionEvent.getY();
            break;
    }

    return true;
}
Community
  • 1
  • 1
Brian
  • 924
  • 13
  • 22
  • 1
    what is `maskPaint.setXfermode(null);` for? – pskink Apr 06 '16 at 12:31
  • @pskink Thanks, I edited my code to encompase the set up of xfermode inside the while loop. This solves the masking problem. Still getting after images/ or redraws of the bitmap when I drag. – Brian Apr 06 '16 at 12:46
  • `Still getting after images/ or redraws of the bitmap when I drag.` what does it mean? – pskink Apr 06 '16 at 12:47
  • @pskink when I drag the image, I instead of moving it, duplicate images are created which respond to the motion event. I want it to look like the original image is being moved on drag. Obviously without seeing duplicate images being laid down in the view. – Brian Apr 06 '16 at 12:56
  • then clear `result` Bitmap first, also use a BitmapShader instead – pskink Apr 06 '16 at 13:03
  • Clearing result works. I've edited my answer. I don't know about BitmapShaders, so I'll find out about them and come back and change my code when I have it working. I don't see how to mark your comments as helpful. If you want to make a post as an answer, I'll accept it. Thank you. – Brian Apr 06 '16 at 15:54
  • if i answered, i would say: use a `BitmapShader`, but then you would not notice that as it it a new concept to you and would prefer to go your way with porter duff stuff – pskink Apr 06 '16 at 16:01

0 Answers0