5

I'm developing an app that need the feature in object.

I have an Image A that cover an Image B. With finger I need to erase the Image A to show the Image B. Erase must follow your finger flowing image A

I'm trying some code but still I couldn't erase the image A. this is the code that i'm using to draw a line on image (_imageToErase is Image A):

Canvas canvas;
Paint paint;
float downx = 0, downy = 0, upx = 0, upy = 0;
ImageView _imageToErase;

@Override
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);

    setContentView(R.layout.g_layout);

    _imageToErase = (ImageView) findViewById(R.id.image_to_erase);

    _imageToErase.setOnTouchListener(this);
}

@Override
public void onWindowFocusChanged(boolean hasFocus){

    int width = _imageToErase.getWidth();
    int height = _imageToErase.getHeight();

    Bitmap bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
    canvas = new Canvas(bitmap);
    paint = new Paint();
    paint.setColor(Color.WHITE);
    paint.setStrokeWidth(25);
    paint.setAntiAlias(true);
    _imageToErase.setImageBitmap(bitmap);
}

public boolean onTouch(View v, MotionEvent event) {
    int action = event.getAction();

    switch (action){
        case MotionEvent.ACTION_DOWN:
            downx = event.getX();
            downy = event.getY();
            break;
        case MotionEvent.ACTION_MOVE:
            upx = event.getX();
            upy = event.getY();
            canvas.drawLine(downx, downy, upx, upy, paint);
            _imageToErase.invalidate();
            downx = upx;
            downy = upy;
            break;
        case MotionEvent.ACTION_UP:
            break;
        case MotionEvent.ACTION_CANCEL:
            break;
        default:
            break;
    }

    return true;
}

This code produce only a line that follow the finger but not erase the image.

How to modify this code to erase the image? Thanks

EDIT

The link suggested in comments not solved my problem. Simply add this line:

 paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_OUT));

not work for me.

Ilario
  • 5,979
  • 2
  • 32
  • 46
  • your paint is white. At the very least you need a transparent paint. – njzk2 Jul 20 '15 at 13:30
  • possible duplicate of [Drawing with Transparent Paint on Android](http://stackoverflow.com/questions/27982853/drawing-with-transparent-paint-on-android) – njzk2 Jul 20 '15 at 13:31
  • @njzk2 yes I know, and in fact i'm tried with transparent, but simply i can't see the line but the image A is always there.. and that question not work for me – Ilario Jul 20 '15 at 13:31
  • where do you draw the image that you want to erase? it does not seem to be on the canvas that you erase? – njzk2 Jul 20 '15 at 13:37
  • @njzk2 in onWindowFocusChanged i build Bitmap, create Canvas with that Bitmap and the setImageBitmap on image – Ilario Jul 20 '15 at 13:42
  • yes, but you are never actually drawing the image on the bitmap. I suspect the image is set as background to your imageview? – njzk2 Jul 20 '15 at 13:52
  • @njzk2 yes image is set like background image to _imagetoerase – Ilario Jul 20 '15 at 13:54
  • it shouldn't. The image and its background are separate things. You need to draw your image on your canvas in order to be able to erase it. – njzk2 Jul 20 '15 at 14:01
  • You will need to play with PorterDuff Xfer modes. By masking what you draw on a 3rd image which cuts the second one, making the first one be visible under the second one. Maybe I wasn't very clear. But it's not too complicate. And, yes, the "first" image, as suggested by @njzk2 could simply be a background. – Phantômaxx Jul 20 '15 at 14:01

2 Answers2

2

PaintView.java

public class PaintView extends View implements View.OnTouchListener {

    private static final String TAG = "PaintView";
    Bitmap Bitmap1, Bitmap2;
    Bitmap Transparent;
    int X = -100;
    int Y = -100;
    Canvas c2;
    private boolean isTouched = false;

    Paint paint = new Paint();

    Path drawPath = new Path();

public PaintView(Context context) {
    super(context);
    setFocusable(true);
    setFocusableInTouchMode(true);
    this.setOnTouchListener(this);

    DisplayMetrics metrics = context.getResources().getDisplayMetrics();
    int width = metrics.widthPixels;
    int height = metrics.heightPixels;

    Transparent = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
    Bitmap1 = BitmapFactory.decodeResource(getResources(), R.drawable.cake1);
    Bitmap2 = BitmapFactory.decodeResource(getResources(), R.drawable.cake2);

    c2 = new Canvas();
    c2.setBitmap(Transparent);
    c2.drawBitmap(Bitmap2, 0, 0, paint);

    paint.setAlpha(0);
    paint.setStyle(Paint.Style.STROKE);
    paint.setStrokeJoin(Paint.Join.ROUND);
    paint.setStrokeCap(Paint.Cap.ROUND);
    paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.CLEAR));
    paint.setAntiAlias(true);
}

private static Point getDisplaySize(final Display display) {
    final Point point = new Point();
    point.x = display.getWidth();
    point.y = display.getHeight();
    return point;
}

@Override
protected void onDraw(Canvas canvas) {
    System.out.println("onDraw");

    if(isTouched)
    {
        canvas.drawBitmap(Bitmap1, 0, 0, null);

    }
    canvas.drawBitmap(Transparent, 0, 0, null);
}

@Override
public boolean onTouch(View v, MotionEvent event) {
    isTouched = true;
    X = (int) event.getX();
    Y = (int) event.getY();

    paint.setStrokeWidth(60);

    switch (event.getAction()) {
        case MotionEvent.ACTION_DOWN:
            drawPath.moveTo(X, Y);
            c2.drawPath(drawPath, paint);
            break;
        case MotionEvent.ACTION_MOVE:
            drawPath.lineTo(X, Y);
            c2.drawPath(drawPath, paint);
            break;
        case MotionEvent.ACTION_UP:
            drawPath.lineTo(X, Y);
            c2.drawPath(drawPath, paint);
            drawPath.reset();
            count=0;
            break;
        default:
            return false;
    }

    invalidate();
    return true;}}class Point {
float x, y;

@Override
public String toString() {
    return x + ", " + y;
}}

MainActivity.java

public class MainActivity extends Activity {

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(new PaintView(this));
}}
  • would it be possible to calculate the percentage of the Image that has been erased? – Ale Mar 04 '17 at 23:43
1

Finally I found a library that works very well for me and implementation is pretty simple

https://github.com/winsontan520/Android-WScratchView

Import library in your project and then in layout.xml

 <com.winsontan520.WScratchView
  android:layout_width="287dp"
  android:layout_height="212dp"
  android:layout_centerHorizontal="true"
  android:layout_marginTop="80dp"
  android:adjustViewBounds="true"
  android:scaleType="centerInside"
  android:id="@+id/image_to_erase"/>

in onCreate:

_imageToErase = (WScratchView) findViewById(R.id.image_to_erase);
Bitmap bitmap = BitmapFactory.decodeResource(getResources(), R.drawable.img_erase);

_imageToErase.setScratchBitmap(bitmap);


_imageToErase.setOnScratchCallback(new WScratchView.OnScratchCallback() {
        @Override
        public void onScratch(float percentage) {
            updatePercentage(percentage);
        }

        @Override
        public void onDetach(boolean fingerDetach) {
            if (mPercentage > 40) {
                _imageToErase.setScratchAll(true);
                updatePercentage(100);
            }
        }
    });

and

private void updatePercentage(float percentage) {

    mPercentage = percentage;
 //   System.out.println("percentage = "+percentage);
}

Thanks everybody

Ilario
  • 5,979
  • 2
  • 32
  • 46