Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to set ontouch listener for something drawn using canvas: Android

I have a custom view in which i am drawing one big circle and a small circle on the edge of this big circle.

I would like to move the small circle and so would like to have a ontouch listener only for the small circle.

Could some please tell me how to set the ontouch listener for only the small circle.

public class ThermoView extends View{

    private ImageView mThermostatBgrd;
    private ImageView mCurTempArrow;
    private ImageView mSetPointIndicator;
    public static final int THEMROSTAT_BACKGROUND = 0;
    public static final int THEMROSTAT_CURR_TEMP = 1;
    public static final int THEMROSTAT_SET_POINT = 2;

    private float mViewCentreX;
    private float mViewCentreY;
    private float mThermostatRadius;

    private Canvas mCanvas;
    private Paint mPaint;
    private Paint mPaintCurTemp;
    private Paint mPaintSetTemp;
    private Paint mPaintOverrideTemp;
    private Paint mPaintCurTempIndicator;

    private Boolean mManualOverride = false;
    private double mManualOverrideAngle;

    private int mMaxTemp = 420;
    private int mMinTemp = 120;

    private RectF mCurrTempBox;
    private float mCurTempCircleX;
    private float mCurTempCircleY;
    private Matrix mMatrix;



    public double getManualOverrideAngle() {
        return mManualOverrideAngle;
    }

    public void setManualOverrideAngle(double mManualOverrideAngle) {
        this.mManualOverrideAngle = mManualOverrideAngle;
    }

    public RectF getCurrTempBox() {
        if (mCurrTempBox == null){
            mCurrTempBox = new RectF();
        }
        return mCurrTempBox;
    }

    public void setCurrTempBox(RectF mCurrTempBox) {
        this.mCurrTempBox = mCurrTempBox;
    }


    public Boolean getManualOverride() {
        return mManualOverride;
    }

    public void setManualOverride(Boolean mManualOverride) {
        this.mManualOverride = mManualOverride;
    }

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

    }



    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);

        Path smallCirle = new Path();
        int viewWidth = getMeasuredWidth();
        int viewHeight = getMeasuredHeight();
        mViewCentreX = viewWidth/2;
        mViewCentreY = viewHeight/2;
        float paddingPercent = 0.2f;
        int thermostatThickness = 20;
        mThermostatRadius = (int) ((Math.min(mViewCentreX, mViewCentreY)*(1- paddingPercent))); 

        if (mPaint == null){
            mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
        }
        mPaint.setStyle(Paint.Style.STROKE);
        mPaint.setStrokeWidth(thermostatThickness);

        mPaint.setColor(0xffff0000); 

        Path arcPath = new Path();

        RectF container = new RectF();
        container.set(mViewCentreX - mThermostatRadius, mViewCentreY - mThermostatRadius, 
                                    mViewCentreX + mThermostatRadius, mViewCentreY + mThermostatRadius);
        arcPath.addArc(container, 120, 300);
        canvas.drawPath(arcPath, mPaint);



        int dummyCurTemp = 200;
        if (mPaintCurTemp == null){
            mPaintCurTemp = new Paint(Paint.ANTI_ALIAS_FLAG);
        }
        mPaintCurTemp.setTextAlign(Align.CENTER);
        mPaintCurTemp.setTextSize(100);
        canvas.drawText(String.valueOf(dummyCurTemp), mViewCentreX, mViewCentreY, mPaintCurTemp);


        if (this.mManualOverride == false){

            double angle = (360-120-(300/(mMaxTemp - mMinTemp))*(dummyCurTemp-mMinTemp))*(Math.PI/180);

            this.mCurTempCircleX = (float) (mViewCentreX + mThermostatRadius*(Math.cos(angle)));
            this.mCurTempCircleY = (float) (mViewCentreY - mThermostatRadius*(Math.sin(angle)));

            if (mCurrTempBox == null){
                mCurrTempBox = new RectF();
            }
            if (mPaintCurTempIndicator == null){
                mPaintCurTempIndicator = new Paint(Paint.ANTI_ALIAS_FLAG);
            }


            mPaintCurTempIndicator.setStyle(Paint.Style.STROKE);
            mPaintCurTempIndicator.setStrokeWidth(thermostatThickness/2);
            mPaintCurTempIndicator.setColor(Color.GREEN);
            mCurrTempBox.set(mCurTempCircleX-50, mCurTempCircleY-50, mCurTempCircleX+50, mCurTempCircleY+50);
            smallCirle.addCircle(mCurTempCircleX, mCurTempCircleY, 50, Direction.CW);
            canvas.drawPath(smallCirle, mPaintCurTempIndicator);





        }else{



            if (mCurrTempBox == null){
                mCurrTempBox = new RectF();
            }
            if (mPaintCurTempIndicator == null){
                mPaintCurTempIndicator = new Paint(Paint.ANTI_ALIAS_FLAG);
            }
            if (mMatrix == null){
                mMatrix = new Matrix();
            }
            //mMatrix.reset();


            mMatrix.postRotate((float) (mManualOverrideAngle), mViewCentreX,mViewCentreY);

            //mMatrix.postTranslate(mViewCentreX, mViewCentreY);
            mPaintCurTempIndicator.setStyle(Paint.Style.STROKE);
            mPaintCurTempIndicator.setStrokeWidth(thermostatThickness/2);
            mPaintCurTempIndicator.setColor(Color.GREEN);



            canvas.concat(mMatrix);

            smallCirle.addCircle(mCurTempCircleX, mCurTempCircleY, 50, Direction.CW);
            canvas.drawPath(smallCirle, mPaintCurTempIndicator);


        }





    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {
                    switch (event.getAction()) {

                case MotionEvent.ACTION_DOWN:


                    mInitialX = event.getX();
                    mInitialY = event.getY();

                    RectF touchedAt = new RectF(mInitialX-10, mInitialY-10, mInitialX+10, mInitialY+10);
                    RectF indicatorAt = mThermoStatView.getCurrTempBox();
                    if (RectF.intersects(indicatorAt, touchedAt)){
                        this.isIndicatorSelected = true;
                        mThermoStatView.setManualOverride(true);

                    }
                    break;

                case MotionEvent.ACTION_MOVE:

                    if (this.isIndicatorSelected == true){

                        float angle = (float) (180*Math.atan2(event.getY() - mThermostatHeight/2, event.getX() - mThermostatWidth/2) / Math.PI);
                        mThermoStatView.setManualOverrideAngle(angle);
                        mThermoStatView.invalidate();
                        //mThermoStatView.requestLayout();


                    }
                    break;

                case MotionEvent.ACTION_UP:
                    if (this.isIndicatorSelected == true){
                        this.isIndicatorSelected = false;

                    }
                    break;
            }


            return true;


    }
}
like image 648
Sunny Avatar asked Dec 13 '13 15:12

Sunny


People also ask

How to draw ball view using ontouch and ondraw?

// Create a ontouch listener object. // Set drawBallView currX and currY value to user finger x y ordinate value.. // Set ball color to blue. // Notify drawBallView to redraw. This will invoke DrawBallView's onDraw () method. // Return true means this listener has complete process this event successfully.

What happens if ontouch returns false in Java activity?

Activity Java Code. Please Note: If the on touch listener’s onTouch method return true, then the on click listener will not be invoked. So the onTouch method return false by default. Of course if you want to avoid on click after on touch, you can make the onTouch method return true.

What is Android canvas?

If you know the basics and directly want to view the code, find the entire source code here on GitHub. So what exactly is Android Canvas ? The Android framework APIs provides a set of 2D drawing APIs that allow you to render your own custom graphics onto a canvas or to modify existing Views to customize their look and feel.

How do you render a ball on Touch in Java?

Use The Custom View Component. CustomViewActivity.java uses the DrawBallView component to render the color ball that follows the user finger touch and move. // Get the root Linearlayout object. // Create the DrawBallView custom view object. //set min width and height. // Create a ontouch listener object.


2 Answers

try this (this is a little modified version of MyView i already posted as an answer for your previous question):

public class MyView extends View {
    private final static String TAG = "Main.MyView";

    private static final float CX = 0;
    private static final float CY = 0;
    private static final float RADIUS = 20;
    private static final float BIGRADIUS = 50;
    private static final int NORMAL_COLOR = 0xffffffff;
    private static final int PRESSED_COLOR = 0xffff0000;

    private Paint mPaint;
    private Path mSmallCircle;
    private Path mCircle;
    private Matrix mMatrix;
    private float mAngle;

    private int mSmallCircleColor;

    public MyView(Context context) {
        super(context);
        mPaint = new Paint();

        mSmallCircle = new Path();
        mSmallCircle.addCircle(BIGRADIUS + RADIUS + CX, CY, RADIUS, Direction.CW);
        mSmallCircleColor = NORMAL_COLOR;

        mCircle = new Path();
        mCircle.addCircle(0, 0, BIGRADIUS, Direction.CW);

        mMatrix = new Matrix();
    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        int action = event.getAction();
        if (action == MotionEvent.ACTION_UP) {
            mSmallCircleColor = NORMAL_COLOR;
            invalidate();
            return false;
        }
        float w2 = getWidth() / 2f;
        float h2 = getHeight() / 2f;
        float r = 0;
        if (action == MotionEvent.ACTION_DOWN) {
            float[] pts = {
                    BIGRADIUS + RADIUS + CX, CY
            };
            mMatrix.mapPoints(pts);
            r = (float) Math.hypot(event.getX() - pts[0], event.getY() - pts[1]);
        }
        if (r < RADIUS) {
            mSmallCircleColor = PRESSED_COLOR;
            mAngle = (float) (180 * Math.atan2(event.getY() - h2, event.getX() - w2) / Math.PI);
            invalidate();
            return true;
        }
        return false;
    }

    @Override
    protected void onDraw(Canvas canvas) {
        float w2 = getWidth() / 2f;
        float h2 = getHeight() / 2f;
        mMatrix.reset();
        mMatrix.postRotate(mAngle);
        mMatrix.postTranslate(w2, h2);

        canvas.concat(mMatrix);
        mPaint.setColor(0x88ffffff);
        canvas.drawPath(mCircle, mPaint);
        mPaint.setColor(mSmallCircleColor);
        canvas.drawPath(mSmallCircle, mPaint);
    }
}
like image 79
pskink Avatar answered Nov 08 '22 10:11

pskink


You can get the rectangle of your touch point and the rectangle(position) of your inner circle and check if they cross over with the Intersects method.

http://docs.oracle.com/javase/7/docs/api/java/awt/Rectangle.html#intersects(java.awt.Rectangle)

Your canvas onTouchListener can do whatever it needs to do if the touchpoint intersect your circle.

e.g:

    // Create a rectangle from the point of touch
    Rect touchpoint = new Rect(x,y,10,10);

    // Create a rectangle from the postion of the circle.
    Rect myCircle=new Rect(10,10,20,20);

    if (Rect.intersects(myCircle,touchpoint)){
        Log.d("The circle was touched");
    }
like image 24
Kuffs Avatar answered Nov 08 '22 10:11

Kuffs