How to set ontouch listener for something drawn us

2019-03-20 17:28发布

问题:

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;


    }
}

回答1:

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);
    }
}


回答2:

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");
    }