Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Animate a circle from the center in Swift

I have a circle that I'm animating. It works except that the drawing is from the top left.. Can I animate it from the center? If so, any help would be appreciated..

My code for drawing the circle is:

class CircleView: UIView {

    override func draw(_ rect: CGRect)
        {
            let prefs: UserDefaults = UserDefaults.standard
            lineWidthFloat = prefs.value(forKey: "lineWidth") as! Float
            let circleSize = Double(lineWidthFloat * 100)
            let context = UIGraphicsGetCurrentContext()
            context!.setLineWidth(10.0)
            context!.setFillColor(UIColor.black.cgColor)
            let rect = CGRect(x: 20, y: 20, width: circleSize, height: circleSize)
            context!.addEllipse(inRect: rect)
            context!.fillPath()
        }

    }

Thanks!

like image 885
ICL1901 Avatar asked Aug 17 '16 15:08

ICL1901


People also ask

How do you animate a circle in Swift?

The easiest way to do this is to use the power of core animation to do most of the work for you. To do that, we'll have to move your circle drawing code from your drawRect function to a CAShapeLayer . Then, we can use a CABasicAnimation to animate CAShapeLayer 's strokeEnd property from 0.0 to 1.0 .

How do you animate in Swift?

swift , turn on animation for the button's rotation by adding an animation modifier that begins on changes of the showDetail value. Add another animatable change by making the button larger when the graph is visible. The animation modifier applies to all animatable changes within the views it wraps.


1 Answers

Details

  • Xcode 10.2.1 (10E1001), Swift 5

Full Sample

CircleView

class CircleView: UIView {

    weak var circleView: UIView?
    lazy var isAnimating = false

    override init(frame: CGRect) {
        super.init(frame: frame)
        setup()
    }

    required init?(coder aDecoder: NSCoder) {
        super.init(coder: aDecoder)
    }

    private func setup() {
        let rectSide = (frame.size.width > frame.size.height) ? frame.size.height : frame.size.width
        let circleRect = CGRect(x: (frame.size.width-rectSide)/2, y: (frame.size.height-rectSide)/2, width: rectSide, height: rectSide)
        let circleView = UIView(frame: circleRect)
        circleView.backgroundColor = UIColor.yellow
        circleView.layer.cornerRadius = rectSide/2
        circleView.layer.borderWidth = 2.0
        circleView.layer.borderColor = UIColor.red.cgColor
        addSubview(circleView)
        self.circleView = circleView
    }

    func resizeCircle (summand: CGFloat) {

        guard let circleView = circleView else { return }
        frame.origin.x -= summand/2
        frame.origin.y -= summand/2
        frame.size.height += summand
        frame.size.width += summand

        circleView.frame.size.height += summand
        circleView.frame.size.width += summand
    }

    private func animateChangingCornerRadius (toValue: Any?, duration: TimeInterval) {
        guard let circleView = circleView else { return }
        let animation = CABasicAnimation(keyPath:"cornerRadius")
        animation.timingFunction = CAMediaTimingFunction(name: CAMediaTimingFunctionName.easeInEaseOut)
        animation.fromValue = circleView.layer.cornerRadius
        animation.toValue =  toValue
        animation.duration = duration
        circleView.layer.cornerRadius = circleView.frame.size.width/2
        circleView.layer.add(animation, forKey:"cornerRadius")
    }


    private func circlePulseAinmation(_ summand: CGFloat, duration: TimeInterval, completionBlock:@escaping ()->()) {

        guard let circleView = circleView else { return }
        UIView.animate(withDuration: duration, delay: 0,  options: .curveEaseInOut, animations: { [weak self] in
            self?.resizeCircle(summand: summand)
        }) { _ in completionBlock() }

        animateChangingCornerRadius(toValue: circleView.frame.size.width/2, duration: duration)
    }

    func resizeCircleWithPulseAinmation(_ summand: CGFloat,  duration: TimeInterval) {
        if (!isAnimating) {
            isAnimating = true
            circlePulseAinmation(summand, duration:duration) { [weak self] in
                guard let self = self else { return }
                self.circlePulseAinmation((-1)*summand, duration:duration) {self.isAnimating = false}
            }
        }
    }
}

ViewController

import UIKit

class ViewController: UIViewController {

    weak var circleView: CircleView?
    weak var button: UIButton?

    override func viewDidLoad() {
        super.viewDidLoad()
        // Do any additional setup after loading the view, typically from a nib.
        let circleView = CircleView(frame: CGRect(x: 40, y: 50, width: 40, height: 60))
        circleView.backgroundColor = UIColor.clear
        view.addSubview(circleView)
        self.circleView = circleView

        let button = UIButton(frame: CGRect(x: 20, y: 150, width: 80, height: 40))
        button.setTitle("Animate", for: UIControl.State())
        button.setTitleColor(UIColor.blue, for: UIControl.State())
        button.setTitleColor(UIColor.blue.withAlphaComponent(0.3), for: .highlighted)
        button.addTarget(self, action: #selector(ViewController.animateCircle), for: .touchUpInside)
        view.addSubview(button)
        self.button = button
    }

    @objc func animateCircle() {
        circleView?.resizeCircleWithPulseAinmation(30, duration: 1.5)
    }
}

Result

enter image description here

like image 180
Vasily Bodnarchuk Avatar answered Nov 13 '22 16:11

Vasily Bodnarchuk