Search code examples
javaandroidondraw

How can I set the dimension and position of a custom view drawn via onDraw?


I have implemented a custom view by extending View. This class implements a constructor and the onDraw method. With these the view is correctly drawn. However, its dimensions are those of its parent. I have tried to add onMeasure and onLayout methods (commented in the code below) but then the custom view is not drawn anymore...

My final goal is to be able to draw several of these custom views in the same FrameLayout and be able to attach a SimpleOnGestureListener to each of them. How can I fix this issue?

public class ScArc extends View {
RectF oval = new RectF();
Path path = new Path();
Paint paint = new Paint();
float left = 0;
float top = 0;
float right = 0;
float bottom = 0;
float startAngle = 0;
float sweepAngle;

public ScArc(Context context, float X1, float Y1, float X2, float Y2, ScMain.Azimuth azimuth, int sweepAngle,
             String strokeWidthName, String strokeColorName, int idx, boolean isForcingChain) {
    super(context);

    ...
    
    oval.set(left, top, right, bottom);
    path.addArc(oval, startAngle, sweepAngle);

    this.setClickable(true);
    this.setEnabled(true);
}

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

//    @Override
//    public boolean onTouchEvent (MotionEvent event) {
//        if (((event.getSource() == SOURCE_MOUSE) || (event.getSource() == SOURCE_TOUCHPAD))
//                && (event.getAction() == MotionEvent.ACTION_DOWN)
//                && event.isButtonPressed(MotionEvent.BUTTON_SECONDARY)) {
//    
//            int tag = (int) this.getTag();
//            drawnStrongLinks.remove(drawnStrongLinks.indexOf(tag));
//    
//            FrameLayout drawingFrame = (FrameLayout) this.getParent();
//            drawingFrame.removeView(this);
//        }
//        return true;
//    }

//    @Override
//    protected void onLayout (boolean changed, int left, int top, int right, int bottom) {
//        super.onLayout(changed, (int) oval.left, (int) oval.top, (int) oval.right, (int) oval.bottom);
//    }

//    @Override
//    protected void onMeasure (int widthMeasureSpec, int heightMeasureSpec) {
//        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
//        this.setMeasuredDimension((int) (oval.right - oval.left), (int) (oval.bottom - oval.top));
//    }

}

Solution

  • Instead of working at the view level, I have implemented the logic at the parent level:

    • the custom view only has a constructor and the onDraw method

    • the parent has got a SimpleOnGestureListener in which I analyse the touch event coordinates to determine which view has been clicked

       @Override
       public boolean onDown(MotionEvent event) {
           if (((event.getSource() == SOURCE_MOUSE) || (event.getSource() == SOURCE_TOUCHPAD))
                   && (event.isButtonPressed(MotionEvent.BUTTON_SECONDARY))) {
               FrameLayout drawingFrame = SCFrame.findViewById(R.id.drawingFrame);
               if (drawingFrame.getChildCount() > 0) {
                   alignmentSquare = SCFrame.findViewById(R.id.alignmentSquare);
                   RectF touchZone = new RectF();
                   touchZone.set((float) (event.getX() - alignmentSquare.getWidth() - 0.5 * textViewWidth),
                               (float) (event.getY() - alignmentSquare.getHeight() - 0.5 * textViewHeight),
                               (float) (event.getX() - alignmentSquare.getWidth() + 0.5 * textViewWidth),
                               (float) (event.getY() - alignmentSquare.getHeight() + 0.5 * textViewHeight));
                   int tag = -1;
                   for (int i = 0; i < drawingFrame.getChildCount(); i++) {
                       View v = drawingFrame.getChildAt(i);
                       if ((v instanceof ScArc) && touchZone.intersect(((ScArc) v).oval)) {
                           tag = (int) v.getTag();
                           break;
                       }
                   }
      
               ...
               }
           }
       }