Search code examples
androidpathandroid-canvasdrawandroid-drawable

How to draw a partial round rect on a android canvas?


I want to draw on a canvas a round rectangle fill with color (or bitmap) and with a stroke but without some selected corners and also without the border on some selected sides. any ideas how i can achieve this ?


Solution

  • you can split the drawing process into two parts.

    1. draw the fill area

      when trying to draw a shape that is not support by the standard sdk APIs, Canvas.drawPath method will be a good way to do it.you can just define four variables to represent radiuses of four corners.

      Path path = new Path();
      Rect drawingRect = {the rect area you want to draw}
      RectF topLeftArcBound = new RectF();
      RectF topRightArcBound = new RectF();
      RectF bottomLeftArcBound = new RectF();
      RectF bottomRightArcBound = new RectF();
      
      topRightArcBound.set(drawingRect.right - topRightRadius * 2, drawingRect.top, drawingRect.right, drawingRect.top + topRightRadius * 2);
      bottomRightArcBound.set(drawingRect.right - bottomRightRadius * 2, drawingRect.bottom - bottomRightRadius * 2, drawingRect.right, drawingRect.bottom);
      bottomLeftArcBound.set(drawingRect.left, drawingRect.bottom - bottomLeftRadius * 2, drawingRect.left + bottomLeftRadius * 2, drawingRect.bottom);
      topLeftArcBound.set(drawingRect.left, drawingRect.top, drawingRect.left + topLeftRadius * 2, drawingRect.top + topLeftRadius * 2);
      
      path.reset();
      
      path.moveTo(drawingRect.left + topLeftRadius, drawingRect.top);
      
      //draw top horizontal line
      path.lineTo(drawingRect.right - topRightRadius, drawingRect.top);
      
      //draw top-right corner
      path.arcTo(topRightArcBound, -90, 90);
      
      //draw right vertical line
      path.lineTo(drawingRect.right, drawingRect.bottom - bottomRightRadius);
      
      //draw bottom-right corner
      path.arcTo(bottomRightArcBound, 0, 90);
      
      //draw bottom horizontal line
      path.lineTo(drawingRect.left - bottomLeftRadius, drawingRect.bottom);
      
      //draw bottom-left corner
      path.arcTo(bottomLeftArcBound, 90, 90);
      
      //draw left vertical line
      path.lineTo(drawingRect.left, drawingRect.top + topLeftRadius);
      
      //draw top-left corner
      path.arcTo(topLeftArcBound, 180, 90);
      
      path.close();
      
      paint.setStyle(Paint.Style.FILL);
      canvas.drawPath(path, paint);
      

      and you can just set radius to zero for selected corners

    2. draw border

      border contains eight parts:

      • top-left corner
      • top line
      • top-right corner
      • right line
      • bottom-right corner
      • bottom line
      • bottom-left corner
      • left line

      use a int value to contains selected parts will be a good idea

      private static final int TOP_LEFT_CORNER = 0x1;
      private static final int TOP_LINE = 0x2;
      private static final int TOP_RIGHT_CORNER = 0x4;
      private static final int RIGHT_LINE = 0x8;
      private static final int BOTTOM_RIGHT_CORNER = 0x10;
      private static final int BOTTOM_LINE = 0x20;
      private static final int BOTTOM_LEFT_CORNER = 0x40;
      private static final int LEFT_LINE = 0x80;
      
      private int selectedParts = TOP_LEFT_CORNER | TOP_LINE | TOP_RIGHT_CORNER;
      

      and now we can draw border based on selectedParts:

      paint.setStyle(Paint.Style.STROKE);
      if((selectedParts & TOP_LINE) > 0){
          canvas.drawLine(drawingRect.left + topLeftRadius, drawingRect.top, drawingRect.right - topRightRadius, drawingRect.top);
      }
      
      if((selectedParts & TOP_RIGHT_CORNER) > 0){
          canvas.drawArc(topRightArcBound, -90, 90, false, paint);
      }
      
      if((selectedParts & RIGHT_LINE) > 0){
          canvas.drawLine(drawingRect.right, drawingRect.top + topRightRadius, drawingRect.right, drawingRect.bottom - bottomRightRadius, paint);
      }
      
      if((selectedParts & BOTTOM_RIGHT_CORNER) > 0){
          canvas.drawArc(bottomRightArcBound, 0, 90, false, paint);
      }
      
      if((selectedParts & BOTTOM_LINE) > 0){
          canvas.drawLine(drawingRect.right - bottomRightRadius, drawingRect.bottom. drawingRect.left + bottomLeftRadius, drawingRect.bottom, paint);
      }
      
      if((selectedParts & BOTTOM_LEFT_CORNER) > 0){
          canvas.drawArc(bottomLeftArcBound, 90, 90, false, paint);
      }
      
      if((selectedParts & LEFT_LINE) > 0){
          canvas.drawLine(drawingRect.left, drawingRect.bottom - bottomLeftRadius, drawingRect.left, drawingRect.top + topLeftRadius, paint);
      }
      
      if((selectedParts & TOP_LEFT_CORNER) > 0){
          canvas.drawArc(topLeftArcBound, 180, 90, false, paint);
      }