Draw iOS 7-style squircle programmatically

后端 未结 7 2111
深忆病人
深忆病人 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条回答
  •  猫巷女王i
    2020-12-07 19:49

    Building on top of Ruslan's and Sunkas' answers above, I created a path that joins superelliptic "corners" with straight line segments; i.e. a superelliptic analog of the regular, rounded rectangle (like the mask seen around the edges of the iPhone X Simulator):

    extension UIBezierPath {
    
        static func superellipse(in rect: CGRect, cornerRadius: CGFloat) -> UIBezierPath {
    
            // (Corner radius can't exceed half of the shorter side; correct if
            // necessary:)
            let minSide = min(rect.width, rect.height)
            let radius = min(cornerRadius, minSide/2)
    
            let topLeft = CGPoint(x: rect.minX, y: rect.minY)
            let topRight = CGPoint(x: rect.maxX, y: rect.minY)
            let bottomLeft = CGPoint(x: rect.minX, y: rect.maxY)
            let bottomRight = CGPoint(x: rect.maxX, y: rect.maxY)
    
            // The two points of the segment along the top side (clockwise):
            let p0 = CGPoint(x: rect.minX + radius, y: rect.minY)
            let p1 = CGPoint(x: rect.maxX - radius, y: rect.minY)
    
            // The two points of the segment along the right side (clockwise):
            let p2 = CGPoint(x: rect.maxX, y: rect.minY + radius)
            let p3 = CGPoint(x: rect.maxX, y: rect.maxY - radius)
    
            // The two points of the segment along the bottom side (clockwise):
            let p4 = CGPoint(x: rect.maxX - radius, y: rect.maxY)
            let p5 = CGPoint(x: rect.minX + radius, y: rect.maxY)
    
            // The two points of the segment along the left side (clockwise):
            let p6 = CGPoint(x: rect.minX, y: rect.maxY - radius)
            let p7 = CGPoint(x: rect.minX, y: rect.minY + radius)
    
            let path = UIBezierPath()
            path.move(to: p0)
            path.addLine(to: p1)
            path.addCurve(to: p2, controlPoint1: topRight, controlPoint2: topRight)
            path.addLine(to: p3)
            path.addCurve(to: p4, controlPoint1: bottomRight, controlPoint2: bottomRight)
            path.addLine(to: p5)
            path.addCurve(to: p6, controlPoint1: bottomLeft, controlPoint2: bottomLeft)
            path.addLine(to: p7)
            path.addCurve(to: p0, controlPoint1: topLeft, controlPoint2: topLeft)
    
            return path
        }
    }
    

    The points p0 through p7 in the code can be visualized in the following diagram:

    If you pass a rectangle that is actually a square, and the corner radius is equal to or greater than half the side length, the straight line segments collapse (p0 "merges" with p1, p2 with p3, etc.) and you get the standard superellipse.

提交回复
热议问题