0

So I'm currently building kids coloring book app. I want to restrict the draw area so it will only can draw path in the selected area. For example, if I touch the horn, then the draw area is only the space inside the border of the horn. For now, I only able to draw the path in the bitmap (the draw area is not restricted).

Touched area I only can draw path in the blue color

First picture: Touched area.

Second picture: User can only draw path inside the blue space.

For now, this is my onDraw code:

    protected void onDraw(Canvas canvas) {
        canvas.drawBitmap(mBitmapCanvas, 0f, 0f, paintCanvas);
        canvas.drawPath(mPaths, drawPaint);
    }

onTouch:

@Override
    public boolean onTouch(View view, MotionEvent motionEvent) {
        float x = motionEvent.getX();
        float y = motionEvent.getY();
        if (isEditable){
            switch (motionEvent.getAction()) {
                case 0:
                    if (paths.isEmpty()) {
                        mBitmap = Bitmap.createBitmap(mBitmapCanvas);
                        paths.add(mBitmap);
                    }
                    mPaths.reset();
                    setColor(ShaderInt);
                    mPaths.moveTo(x, y);
                    mX = x;
                    mY = y;
                    invalidate();
                    break;
                case 1:
                    mPaths.lineTo(mX, mY);
                    mCanvas.drawPath(mPaths, drawPaint);
                    mCanvas.drawPath(mPaths, drawPaint);
                    mBitmap = Bitmap.createBitmap(mBitmapCanvas);
                    paths.add(mBitmap);
                    mPaths.reset();
                    invalidate();
                    break;
                case 2:
                    float abs = Math.abs(x - this.mX);
                    float abs2 = Math.abs(y - this.mY);
                    if (abs >= TOUCH_TOLERANCE || abs2 >= TOUCH_TOLERANCE) {
                        this.mPaths.quadTo(this.mX, this.mY, (this.mX + x) / 2.0f, (this.mY + y) / 2.0f);
                        this.mX = x;
                        this.mY = y;
                    }
                    invalidate();
                    break;
                default:
                    return false;
            }

        } else {
            return false;
        }
        invalidate();
        return true;
    }

Is there any way so I can make the draw area restricted to the touched/selected area? Any help will be so appreciated, thank you!

William Edward
  • 142
  • 2
  • 11

1 Answers1

0

I would recommend creating a path initialized to your horn shape, and using Porter Duff operations to composite the desired result. The Porter Duff operation of interest for your use-case is probably DST_IN.

To achieve the effect you want, the code is pretty straight forward. Inside of your onDraw(Canvas) callback the first thing you want to do is draw your custom "horn" path using a paint object that has a PorterDuffXfermode set, with DST_IN set as it's mode. All subsequent calls will be masked to the bounds of your "horn" path. Next, perform your custom drawing logic on your canvas as you normally would.

To perform drawing outside outside of your "horn" path, just remove the Porter Duff xfermode from your paint object and resume drawing as you normally would. I recommend viewing the PortDuff documentation and become intimately familiar with the order of draw codes to make sure your get the expected results as well as understand why your final result may be different than what you'd expect. When using Porter Duff compositing, you draw your destination before your source; which may not make sense at first.

If you're manually handling drawing your background image (the goat), you may have to pay special care to make sure it's completely drawn and not just the portion contained inside of your "horn" path. If you're letting the View framework draw the background i.e. using set setBackround(Drawable) you should be good.

Here is a link to an example limiting drawing a bitmap inside of a "circle" path.

cincy_anddeveloper
  • 1,140
  • 1
  • 9
  • 19
  • Hi, thanks for your comment. So basically I have to draw the custom horn path in the onDraw callback. The app that I'm building is coloring book, so if the user touch any part of the goat, they only can draw inside the touched area. In order to do that, do I have to draw all part of the goat first? Such as the horn 1, horn 2, eye, head, body, etc? And if I have other image, then I have to draw the part of that image too? Thanks. – William Edward Nov 06 '21 at 02:08
  • @William Edward Yes, you need to draw the full background image; on your specific case the entire goat. Then inside of your onTouchEvent(MotionEvent) callback you'd listen for touches inside the sections of your goat that you'd like to "restrict" drawing to and follow the steps I've outlined in my answer. – cincy_anddeveloper Nov 07 '21 at 03:30