Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
730 views
in Technique[技术] by (71.8m points)

core graphics - How to draw heart shape in UIView (iOS)?

I want to create different shapes. Below image is the one of example. Will you suggest me how to different shapes?

enter image description here

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

Came across this when I was trying to draw a UIBezier-based heart myself, but was looking for one that looked a bit more like the one on Instagram posts.

I ended up writing my own extension/class for it so I thought I'd share it on here in case it's of any use to anyone else who stumbles upon this in future.

(This is all in Swift 3)

First off, here's the UIBezier extension:

extension UIBezierPath {
    convenience init(heartIn rect: CGRect) {
        self.init()

        //Calculate Radius of Arcs using Pythagoras
        let sideOne = rect.width * 0.4
        let sideTwo = rect.height * 0.3
        let arcRadius = sqrt(sideOne*sideOne + sideTwo*sideTwo)/2

        //Left Hand Curve
        self.addArc(withCenter: CGPoint(x: rect.width * 0.3, y: rect.height * 0.35), radius: arcRadius, startAngle: 135.degreesToRadians, endAngle: 315.degreesToRadians, clockwise: true)

        //Top Centre Dip
        self.addLine(to: CGPoint(x: rect.width/2, y: rect.height * 0.2))

        //Right Hand Curve
        self.addArc(withCenter: CGPoint(x: rect.width * 0.7, y: rect.height * 0.35), radius: arcRadius, startAngle: 225.degreesToRadians, endAngle: 45.degreesToRadians, clockwise: true)

        //Right Bottom Line
        self.addLine(to: CGPoint(x: rect.width * 0.5, y: rect.height * 0.95))

        //Left Bottom Line
        self.close()
    }
}

You'll also need to add this somewhere in your project so that the degreesToRadians extension works:

extension Int {
    var degreesToRadians: CGFloat { return CGFloat(self) * .pi / 180 }
}

Using this is as simple as initialising a UIBezier in the same way you would an oval:

let bezierPath = UIBezierPath(heartIn: self.bounds)

In addition to this, I made a class to help easily display this and control certain features. It will render fully in IB, with overrides for the fill colour (using the tint colour property), whether or not you want a fill at all, the stroke colour, and the stroke width:

@IBDesignable class HeartButton: UIButton {

@IBInspectable var filled: Bool = true
@IBInspectable var strokeWidth: CGFloat = 2.0

@IBInspectable var strokeColor: UIColor?

override func draw(_ rect: CGRect) {
    let bezierPath = UIBezierPath(heartIn: self.bounds)

    if self.strokeColor != nil {
        self.strokeColor!.setStroke()
    } else {
        self.tintColor.setStroke()
    }

    bezierPath.lineWidth = self.strokeWidth
    bezierPath.stroke()

    if self.filled {
        self.tintColor.setFill()
        bezierPath.fill()
    }
}

}

It's a UIButton class, but it'd be pretty simple to alter this if you don't want it to be a button.

Here's what it actually looks like:

Heart Filled

And with just the stroke:

Heart Stroked


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...