Vikash Kumar Verma
Vikash Kumar Verma

Reputation: 1078

android canvas not drawing on touched position

I am using canvas to make a simple drawing app. I am using onTouchEvent to handle touch event. I am facing a problem on vertical axis drawn point is differentfrom touched position. the vertical separation in between touched position and drawn position increases as I move upward. To make my problem more clear i am attaching screenshot of my app. screen shot

Blue line shows actual touched position and red drawn position.

Here is my code Mainactivity

public class MainActivity extends AppCompatActivity{
    Path mPath;
    Canvas canvas;
    Paint paint;
    float pointX;
    float pointY;
    int height;
    RelativeLayout layout;
    int layoutHeight;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        layout=(RelativeLayout)findViewById(R.id.main_layout);
        DisplayMetrics dp=getResources().getDisplayMetrics();

        WindowManager windowManager=getWindowManager();
        height=windowManager.getDefaultDisplay().getHeight();
        int width =windowManager.getDefaultDisplay().getWidth();

        Bitmap bg = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
        layout.setBackground(new BitmapDrawable(bg));
        canvas=new Canvas(bg);
        paint=new Paint(Paint.ANTI_ALIAS_FLAG);
        paint.setColor(Color.RED);
        paint.setStyle(Paint.Style.STROKE);
        paint.setStrokeWidth(4);
        mPath=new Path();
        canvas.drawPath(mPath,paint);
        canvas.drawBitmap(bg,0,0,paint);
    }

    public void clearCanvas(View v) {
        mPath.reset();
        canvas.drawColor(0, PorterDuff.Mode.CLEAR);
        layout.invalidate();
    }
    //override the onTouchEvent
    @Override
    public boolean onTouchEvent(MotionEvent event) {
        pointX = event.getX();
        pointY = event.getY();
        switch (event.getAction()) {
            case MotionEvent.ACTION_DOWN:
                Log.v("TAG"," action down x:"+pointX+" y:"+pointY);
                mPath.moveTo(pointX,pointY);
                break;
            case MotionEvent.ACTION_MOVE:
                Log.v("TAG"," actionmove x:"+pointX+" y:"+pointY);
                mPath.lineTo(pointX,pointY);
                canvas.drawPath(mPath,paint);
                break;
            case MotionEvent.ACTION_UP:
                break;
        }
        layout.invalidate();
        return true;
    }
} 

xml layout

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/main_layout"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context="com.example.vikash.mydrawingapp.MainActivity">

    <Button
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="clear"
        android:onClick="clearCanvas"
        android:layout_alignParentBottom="true"
        android:layout_centerHorizontal="true" />
</RelativeLayout>

Upvotes: 1

Views: 1920

Answers (2)

Igor
Igor

Reputation: 456

Use: event.getRawX()

Returns the original raw X coordinate of this event. For touch events on the screen, this is the original location of the event on the screen, before it had been adjusted for the containing window and views.

UPD: I just tried to repeat your app and all works correctly

activity.xml

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
     android:orientation="vertical"
     android:layout_width="match_parent"
     android:layout_height="match_parent">

     <com.example.Test
        android:layout_width="match_parent"
        android:layout_height="match_parent"/>

</LinearLayout>

Test.java

public class Test extends View {

    private Path path = new Path();
    private Paint paint = new Paint();
    {
        paint.setColor(Color.GREEN);
        paint.setStrokeWidth(4);
        paint.setStyle(Paint.Style.STROKE);
    }

    public Test(Context context) {
        super(context);
    }

    public Test(Context context, AttributeSet attrs) {
        super(context, attrs);
    }

    public Test(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
    }

    @TargetApi(Build.VERSION_CODES.LOLLIPOP)
    public Test(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
        super(context, attrs, defStyleAttr, defStyleRes);
    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        canvas.drawPath(path, paint);
    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        switch (event.getAction()) {
            case MotionEvent.ACTION_DOWN:
                path.moveTo(event.getX(), event.getY());
                break;
            case MotionEvent.ACTION_MOVE:
                path.lineTo(event.getX(), event.getY());
                break;
        }
        invalidate();
        return true;
    }

}

Upvotes: 4

Nestoraj
Nestoraj

Reputation: 762

Your problem is that your Canvas X-Axis has the same position of the Screen X-Axis, but your Canvas Y-Axis is offset from Screen Y-Axis (The "MyDrawingApp" bar sets that offset with its height).

What is happening is that when you "getY()" it returns the position of the touch taking as reference the entire screen not your canvas.

One solution is to get the position of the canvas on the screen and minus it to the "getY()" value. Doing this you will get a touch inside of your canvas.

I hope you will understand me, I am not English.

Greetings

Upvotes: 0

Related Questions