简体   繁体   中英

OnTouchListener not working on canvas

I need to:

  1. Paint a circle and
  2. get the coordinates on the point

where my finger is touching the view.

Fragment

..
mPaintSurface = (PaintSurface) view.findViewById(R.id.image_body);
// Paint a circle when touched
mPaintSurface.setOnTouchListener(mPaintSurface);
// Get coordinates when touched
mPaintSurface.setOnTouchListener(new OnTouchListener() {
            @Override
            public boolean onTouch(View v, MotionEvent event) {
                if(event.getAction() == MotionEvent.ACTION_UP){
                    // Do what you want
                    Log.d("Fragment_Point", "X: "+mPaintSurface.getRelativeXpos()+" Y: "+mPaintSurface.getRelativeYpos());
                    return true;
                }
                return false;
            }
        });
..

PaintSurface

public class PaintSurface extends SurfaceView implements Runnable, OnTouchListener{

    // Surface holder allows to control and monitor the surface
    private SurfaceHolder mHolder;

    // A thread where the painting activities are taking place
    private Thread mThread;

    // A flag which controls the start and stop of the repainting of the SurfaceView
    private boolean mFlag = false;

    // X coordinate of the touched position
    private float mX;

    // Y Coordinate of the touched position
    private float mY;

    // Paint
    private Paint mPaint;

    // Widths and Heights
    private int mWidth;
    private int mHeight;


    public PaintSurface(Context context, AttributeSet attrs) {
        super(context, attrs);

        // Getting the holder
        mHolder = getHolder();

        // Initializing the X position
        mX = -100;

        // Initializing the Y position
        mY = -100;

        // Initializing the paint object mPaint
        mPaint = new Paint();

        // Setting the color for the paint object
        mPaint.setColor(Color.RED);

    }

    public void resume(){
        // Instantiating the thread
        mThread = new Thread(this);

        // setting the mFlag to true for start repainting
        mFlag = true;

        // Start repaint the SurfaceView
        mThread.start();
    }

    public void pause(){
        mFlag = false;
    }

    @Override
    public boolean onTouch(View v, MotionEvent event) {
        switch(event.getAction()){
            case MotionEvent.ACTION_DOWN:
                // Getting the X-Coordinate of the touched position
                mX = event.getX();
                // Getting the Y-Coordinate of the touched position
                mY = event.getY();

                Log.d("PaintSurface", "getWidth(): " + getWidth() + " getHeight(): " + getHeight());
                Log.d("PaintSurface", "X: " + mX/getWidth() + " Y: " + mY/getHeight());

                break;
        }
        return true;
    }

    @Override
    public void run() {
        while(mFlag){
            // Check whether the object holds a valid surface
            if(!mHolder.getSurface().isValid())
                continue;
            // Start editing the surface
            Canvas canvas = mHolder.lockCanvas();
            // Draw a body image from Drawables
            Bitmap b=BitmapFactory.decodeResource(getResources(), R.drawable.body_50);
            b = getResizedBitmap(b, getWidth(), getHeight());
            Paint p=new Paint();
            canvas.drawBitmap(b, 0, 0, p);
            // Draw a circle at (mX,mY) with radius 5
            canvas.drawCircle(mX, mY, 10, mPaint);
            // Finish editing the canvas and show to the user
            mHolder.unlockCanvasAndPost(canvas);
        }
    }

    public float getRelativeXpos(){
        return mX/getWidth();
    }

    public float getRelativeYpos(){
        return mX/getHeight();
    }

    private Bitmap getResizedBitmap(Bitmap bm, int newWidth, int newHeight) {
        int width = bm.getWidth();
        int height = bm.getHeight();
        float scaleWidth = ((float) newWidth) / width;
        float scaleHeight = ((float) newHeight) / height;
        // CREATE A MATRIX FOR THE MANIPULATION
        Matrix matrix = new Matrix();
        // RESIZE THE BIT MAP
        matrix.postScale(scaleWidth, scaleHeight);

        // "RECREATE" THE NEW BITMAP
        Bitmap resizedBitmap = Bitmap.createBitmap(bm, 0, 0, width, height, matrix, false);
        return resizedBitmap;
    }

}

There are 2 on touch listeners to perform this action. The first touchlistener is working (paints the circle on the point I touch). However, the second touch listeners that tries to listen to touch events on the custom view doesn't work (No logging when touched). OnTouch only works inside Paint Surface custom view but not inside my fragment anymore.

*I need a way to extract the coordinates that is touching on the canvas to my fragments.

I've also tried onClickListeners, same results. Maybe I've understood touchlisteners wrongly, but why is it that one touchlistener is working but the other isn't? Thanks for any hints. (:

UPDATE I've tried to wrap the entire view and setting it to an onclick listener. Everything else is able to listen for onclick, except for the canvas. Why is the canvas ignoring onclick events? Is there a way to bypass this?

I've thought a way to cheat this, which is to use SharedPref to pass information between both classes. But I hope that this would be the final alternative.

Make next :

/**
 * @author Sergey Shustikov (pandarium.shustikov@gmail.com)
 */
public class PaintSurface implements View.OnTouchListener {

    private List<View.OnTouchListener> mOnTouchListenerList = new ArrayList<>();


    public void addOnTouchListener(View.OnTouchListener listener) {
        mOnTouchListenerList.add(listener);
    }

    @Override
    public boolean onTouch(View v, MotionEvent event) {
        for (View.OnTouchListener listener : mOnTouchListenerList) {
            listener.onTouch(v, event);
        }
        return true;
    }
}

Usage :

// Paint a circle when touched
mPaintSurface.addOnTouchListener(mPaintSurface);
// Get coordinates when touched
mPaintSurface.addOnTouchListener(new OnTouchListener() {
            @Override
            public boolean onTouch(View v, MotionEvent event) {
                if(event.getAction() == MotionEvent.ACTION_UP){
                    // Do what you want
                    Log.d("Fragment_Point", "X: "+mPaintSurface.getRelativeXpos()+" Y: "+mPaintSurface.getRelativeYpos());
                    return true;
                }
                return false;
            }
        });

if you want to reject some touch replace

    @Override
    public boolean onTouch(View v, MotionEvent event) {
        for (View.OnTouchListener listener : mOnTouchListenerList) {
            listener.onTouch(v, event);
        }
        return true;
    }

to

    @Override
    public boolean onTouch(View v, MotionEvent event) {
        for (View.OnTouchListener listener : mOnTouchListenerList) {
            if(!listener.onTouch(v, event))return false;
        }
        return true;
    }

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM