Draw iOS 7-style squircle programmatically

后端 未结 7 2093
深忆病人
深忆病人 2020-12-07 19:15

I\'m trying to find a way to draw a iOS 7-style icon \'squircle\' shape programmatically, using core graphics. I\'m not asking how to draw a rounded rectangle

7条回答
  •  执笔经年
    2020-12-07 19:41

    Quote from Wikipedia: Superellipse

    For n = 1/2, in particular, each of the four arcs is a Quadratic Bézier curve defined by the two axes; as a result, each arc is a segment of a parabola.

    So why not try to approximate Squircle using Bezier curves? Both curves (Bezier and Squircle) are defined by the parametric equations.

    UIBezierPath Class have method: addCurveToPoint:controlPoint1:controlPoint2:

    Appends a cubic Bézier curve to the receiver’s path.

    NOTE: Use of the addQuadCurveToPoint:controlPoint: method gives worse results - tested.

    I used this method and that's what happened as a result:

    red line - rounded rectangle, blue line - rectangle from fours Bezier curves

    Rounded rectangle vs cubic Bezier curve

    If this result is interested - drawing code below.

    NOTE: To achieve a more exact match Bezier curve can be required to change the coordinates of the four corner points (now they correspond to the angles of the rectangle in which is inscribed the figure).

    CGContextRef context = UIGraphicsGetCurrentContext();
    CGContextSaveGState(context);
    
    //set rect size for draw
    float rectSize = 275.;
    CGRect rectangle = CGRectMake(CGRectGetMidX(rect) - rectSize/2, CGRectGetMidY(rect) - rectSize/2, rectSize, rectSize);
    
    //Rounded rectangle
    CGContextSetStrokeColorWithColor(context, [UIColor redColor].CGColor);
    UIBezierPath* roundedPath = [UIBezierPath bezierPathWithRoundedRect:rectangle cornerRadius:rectSize/4.7];
    [roundedPath stroke];
    
    //Rectangle from Fours Bezier Curves
    CGContextSetStrokeColorWithColor(context, [UIColor blueColor].CGColor);
    UIBezierPath *bezierCurvePath = [UIBezierPath bezierPath];
    
    //set coner points
    CGPoint topLPoint = CGPointMake(CGRectGetMinX(rectangle), CGRectGetMinY(rectangle));
    CGPoint topRPoint = CGPointMake(CGRectGetMaxX(rectangle), CGRectGetMinY(rectangle));
    CGPoint botLPoint = CGPointMake(CGRectGetMinX(rectangle), CGRectGetMaxY(rectangle));
    CGPoint botRPoint = CGPointMake(CGRectGetMaxX(rectangle), CGRectGetMaxY(rectangle));
    
    //set start-end points
    CGPoint midRPoint = CGPointMake(CGRectGetMaxX(rectangle), CGRectGetMidY(rectangle));
    CGPoint botMPoint = CGPointMake(CGRectGetMidX(rectangle), CGRectGetMaxY(rectangle));
    CGPoint topMPoint = CGPointMake(CGRectGetMidX(rectangle), CGRectGetMinY(rectangle));
    CGPoint midLPoint = CGPointMake(CGRectGetMinX(rectangle), CGRectGetMidY(rectangle));
    
    //Four Bezier Curve
    [bezierCurvePath moveToPoint:midLPoint];
    [bezierCurvePath addCurveToPoint:topMPoint controlPoint1:topLPoint controlPoint2:topLPoint];
    [bezierCurvePath moveToPoint:midLPoint];
    [bezierCurvePath addCurveToPoint:botMPoint controlPoint1:botLPoint controlPoint2:botLPoint];
    [bezierCurvePath moveToPoint:midRPoint];
    [bezierCurvePath addCurveToPoint:topMPoint controlPoint1:topRPoint controlPoint2:topRPoint];
    [bezierCurvePath moveToPoint:midRPoint];
    [bezierCurvePath addCurveToPoint:botMPoint controlPoint1:botRPoint controlPoint2:botRPoint];
    
    [bezierCurvePath stroke];
    
    CGContextRestoreGState(context);
    

提交回复
热议问题