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;
}
Add subview with the same color which will be centered on the parent and will be with several pixels smaller. Like this you will have space from each side of the parent. On the parent turn on clipping subviews and add shadow to the inner view. Like this, you can have an inner shadow.
Select the view that you want to round and open its Identity Inspector. In the User Defined Runtime Attributes section, add the following two entries: Key Path: layer. cornerRadius , Type: Number, Value: (whatever radius you want)
If you start with a regular UIView it has square corners. You can give it round corners by changing the cornerRadius property of the view's layer . and smaller values give less rounded corners. Both clipsToBounds and masksToBounds are equivalent.
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.
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With