Search code examples
androiddrag-and-dropsurfaceviewscalingrect

SurfaceView Rect objects get deleted android


I'm developing a draw view with multiple rectangles which can be re-sized and dragged (on a camera preview). I think I got it to work. But the thing is, the rectangles appeared to be get deleted some how. they sometimes disappear from the view and get removed from the Rect array while dragging or resizing. Can somebody point out the bug?? thanks in advanced.

here is my DrawView class

import java.util.ArrayList;
import java.util.List;

import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Rect;
import android.util.Log;
import android.view.SurfaceView;

public class DrawView extends SurfaceView {

    private Paint textPaint = new Paint();
    private List<Rect> Rectangles;
    private float x_axis;
    private float y_axis;
    private boolean found;
    private String TAG="DrawView";
    private Rect tempRect;



    public DrawView(Context context) {
        super(context);
        // Create out paint to use for drawing
        textPaint.setARGB(255, 200, 0, 0);
        textPaint.setStyle(Paint.Style.STROKE);
        textPaint.setColor(Color.RED);
        textPaint.setStrokeWidth(3);
        textPaint.setAlpha(200);
        /* This call is necessary, or else the 
         * draw method will not be called. 
         */
        Rectangles=new ArrayList<Rect>();

        setWillNotDraw(false);
    }


    public void setCoordinates (float x1, float y1) {

        x_axis=x1;
        y_axis=y1;

        Rectangles.add(new Rect(Math.round(x_axis)-150, Math.round(y_axis)-70, Math.round(x_axis)+150, Math.round(y_axis)+70));
        // indicate view should be redrawn
        postInvalidate();

    }

    public void tryDrag(float x, float y){

        if(tempRect!=null){
            tempRect.set(Math.round(x-tempRect.width()/2),Math.round(y+tempRect.height()/2)
                    ,Math.round(x+tempRect.width()/2),Math.round(y-tempRect.height()/2));
            postInvalidate();
        }

    }
    public void DrawNow(){
        postInvalidate();
    }

    public void   animateDrag(float x, float y){
        found=false;
        tempRect=null;
        for(Rect R: Rectangles){

            if(R.contains(Math.round(x), Math.round(y))){
                found=true;
                tempRect =R;
                break;
            }

        }


        if(found){

            Log.d(TAG, "inside a rectange");        
        }

    }

    public void doScale(float x, float y){
        if(tempRect!=null){

            int tempWidth=Math.round((tempRect.width()*x)/2);
            int tempHeight=Math.round((tempRect.height()*y)/2);

            tempRect.set(tempRect.centerX()-tempWidth,tempRect.centerY()+tempHeight,tempRect.centerX()+tempWidth,tempRect.centerY()-tempHeight);

            postInvalidate();

        }

    }


    @Override
    protected void onDraw(Canvas canvas){
        // A Simple Text Render to test the display

        for(Rect R: Rectangles)
            canvas.drawRect(R.left,R.top,R.right,R.bottom, textPaint);


    }
}

here is my code part from the Activity class

    private float scaleFactorY;
    private float scaleFactorX;

    @Override 
    public boolean onTouchEvent(MotionEvent event){ 


        mScaleDetector.onTouchEvent(event);

        if(mScaleDetector.isInProgress()) return false;
        //let the ScaleGestureDetector try first

        // if scale detector is not in progress 
        mDetector.onTouchEvent(event);
        super.onTouchEvent(event);
        return true;

    }

    @Override
    public boolean onDown(MotionEvent event) { 
        Log.d(DEBUG_TAG,"onDown: " ); 
        if(scaling==0)
        dv.animateDrag(event.getX(),event.getY());
        return true;
    }

    @Override
    public boolean onFling(MotionEvent event1, MotionEvent event2, 
            float velocityX, float velocityY) {
        Log.d(DEBUG_TAG, "onFling: " );
        return true;
    }

    @Override
    public void onLongPress(MotionEvent event) {
        Log.d(DEBUG_TAG, "onLongPress: "); 


    }

    @Override
    public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX,
            float distanceY) {
        if(scaling>0) return false;
        dv.tryDrag(e2.getX(),e2.getY());
        return true;
    }

    @Override
    public void onShowPress(MotionEvent event) {
        Log.d(DEBUG_TAG, "onShowPress: ");
    }

    @Override
    public boolean onSingleTapUp(MotionEvent event) {
        Log.d(DEBUG_TAG, "onSingleTapUp: " );
        return true;
    }

    @Override
    public boolean onDoubleTap(MotionEvent event) {
        Log.d(DEBUG_TAG, "onDoubleTap: ");
        return true;
    }

    @Override
    public boolean onDoubleTapEvent(MotionEvent event) {
        Log.d(DEBUG_TAG, "onDoubleTapEvent: ");
        return true;
    }

    @Override
    public boolean onSingleTapConfirmed(MotionEvent event) {
        Log.d(DEBUG_TAG, "onSingleTapConfirmed: ");

        int pointerIndex0 = event.findPointerIndex(event.getPointerId(0));
        // Get the 1st pointer's current position
        float x0 = event.getX(pointerIndex0);
        float y0 = event.getY(pointerIndex0);
        Log.d(TAG, "X0= "+x0+ " Y0=" + y0);

        if(RactangleCount<5){

            dv.setCoordinates(x0, y0);

            if (safeToTakePicture && prvw) {

                ((FrameLayout) findViewById(R.id.preview)).addView(dv);

                safeToTakePicture = false;
                preview.camera.takePicture(shutterCallback, rawCallback, jpegCallback); 
                prvw=false; 

            }

            RactangleCount++;
        }


        return true;
    }





    @Override
    public boolean onDrag(View v, DragEvent event) {
        // TODO Auto-generated method stub
        Log.d(TAG,"on Drag");
        // dv.animateDrag(event.getX(),event.getY());

        //dv.tryDrag(e2.getX(),e2.getY());
        return false;
    }





    @Override
    public boolean onScale(ScaleGestureDetector detector) {
        scaling++;
        Log.d(TAG,"on scale");

            scaleFactorX= detector.getCurrentSpanX()/detector.getPreviousSpanX();
            scaleFactorY= detector.getCurrentSpanY()/detector.getPreviousSpanY();
            Log.d(TAG,"on" + "Xfactor"+scaleFactorX+"Yfactor"+scaleFactorY);



        dv.doScale(scaleFactorX,scaleFactorY);

        return true;
    }





    @Override
    public boolean onScaleBegin(ScaleGestureDetector detector) {
        // TODO Auto-generated method stub

        scaling=1;
        Log.d(TAG,"on scale begin");


        return true;
    }





    @Override
    public void onScaleEnd(ScaleGestureDetector detector) {
        // TODO Auto-generated method stub
        Log.d(TAG,"on scale end");

        scaling=0;
    }
}

Solution

  • solved..! if anyone has a same kind of a problem, the answer is check the rectangle boundaries. The top y coordinates always should be smaller than bottom y coordinates. Otherwise the surface view may give unexpected results.

    this is the line with an error.

     tempRect.set(tempRect.centerX()-tempWidth,tempRect.centerY()+tempHeight,tempRect.centerX()+tempWidth,tempRect.centerY()-tempHeight);
    

    it should be corrected as

    tempRect.set(tempRect.centerX()-tempWidth,tempRect.centerY()-tempHeight,tempRect.centerX()+tempWidth,tempRect.centerY()+tempHeight);