18

I created a subclass of UIView that overrides drawRect: and uses AddArcToPoint() to draw rounded corners. (I don't want to use the layer's corner radius property because I need to define which corners have to be rounded.) The problem I cannot get over however: if I add a subview at (0|0), it hides my round corners. Any idea how I can fix this? I would like it to clip nicely.

Here's the code that draws the round cornered rectangle. It's Monotouch but should be readably by any developer.

(you can find the full code here: https://github.com/Krumelur/RoundedRectView)

public override void Draw (RectangleF rect)
        {
            using (var oContext = UIGraphics.GetCurrentContext())
            {
                oContext.SetLineWidth (this.StrokeWidth);
                oContext.SetStrokeColor (this.oStrokeColor.CGColor);
                oContext.SetFillColor (this.oRectColor.CGColor);

                RectangleF oRect = this.Bounds;

                float fRadius = this.CornerRadius;
                float fWidth = oRect.Width;
                float fHeight = oRect.Height;

                // Make sure corner radius isn't larger than half the shorter side.
                if (fRadius > fWidth / 2.0f)
                {
                    fRadius = fWidth / 2.0f;
                }
                if (fRadius > fHeight / 2.0f)
                {
                    fRadius = fHeight / 2.0f;    
                }

                float fMinX = oRect.GetMinX ();
                float fMidX = oRect.GetMidX ();
                float fMaxX = oRect.GetMaxX ();
                float fMinY = oRect.GetMinY ();
                float fMidY = oRect.GetMidY ();
                float fMaxY = oRect.GetMaxY ();

                // Move to left middle.
                oContext.MoveTo (fMinX, fMidY);

                // Arc to top middle.
                oContext.AddArcToPoint (fMinX, fMinY, fMidX, fMinY, (this.RoundCorners & ROUND_CORNERS.TopLeft) == ROUND_CORNERS.TopLeft ? fRadius : 0);
                // Arc to right middle.
                oContext.AddArcToPoint (fMaxX, fMinY, fMaxX, fMidY, (this.RoundCorners & ROUND_CORNERS.TopRight) == ROUND_CORNERS.TopRight ? fRadius : 0);
                // Arc to bottom middle.
                oContext.AddArcToPoint (fMaxX, fMaxY, fMidX, fMaxY, (this.RoundCorners & ROUND_CORNERS.BottomRight) == ROUND_CORNERS.BottomRight ? fRadius : 0);
                // Arc to left middle.
                oContext.AddArcToPoint (fMinX, fMaxY, fMinX, fMidY, (this.RoundCorners & ROUND_CORNERS.BottomLeft) == ROUND_CORNERS.BottomLeft ? fRadius : 0);

                // Draw the path.
                oContext.ClosePath ();
                oContext.DrawPath (CGPathDrawingMode.FillStroke);
            }
        }

EDIT:

Here's a piece of code that demonstrates how to solve it using CALayer.

private void UpdateMask()
        {
            UIBezierPath oMaskPath = UIBezierPath.FromRoundedRect (this.Bounds, this.eRoundedCorners, new SizeF (this.fCornerRadius, this.fCornerRadius));

            CAShapeLayer oMaskLayer = new CAShapeLayer ();
            oMaskLayer.Frame = this.Bounds;
            oMaskLayer.Path = oMaskPath.CGPath;
            this.Layer.Mask = oMaskLayer;
        }
Krumelur
  • 32,180
  • 27
  • 124
  • 263

2 Answers2

8

I haven't tried it, but I think you could use CALayer's mask property to do this. You'd have to draw your rounded rectangle into a layer that was set as the mask to your view layer.

joerick
  • 16,078
  • 4
  • 53
  • 57
  • That was a brilliant hint! I will update the code on https://github.com/Krumelur/RoundedRectView to use as CALayer mask. It is a one liner! – Krumelur Nov 07 '11 at 11:57
  • 3
    The code to do this in Objective-C is shown here: http://stackoverflow.com/a/10515546/197626 – Daniel Thorpe May 09 '12 at 11:53
2

It is possible (and, in fact, very easy) to specify particular rounded corners without resorting to drawRect:, or manually drawing a partially rounded rect into a layer. See my answer on a similar question.

Community
  • 1
  • 1
Stuart
  • 36,683
  • 19
  • 101
  • 139
  • Yeah, that's what I found and used after getting the CALayer hint. Thanks! My only issue with it is auto resizing. CALayer does not auto resize. So I override frame and bounds and update the mask but this cannot be animated and if you rotate the device, it looks a bit chunky. – Krumelur Nov 07 '11 at 19:47