1

So i have a circe with a certain pattern. I want to make transform this circle into a line. Any ideas how i could accomplish this?

I did have a look at making a UIBezierPath over the circle for then to transform this into a line without any help. I've also seen a link doing this in opencv (fast Cartesian to Polar to Cartesian in Python) but do prefer to do this in native swift.

enter image description here

6
  • Did you try something? Any code? Commented Jun 30, 2016 at 7:16
  • Ive looked at creating a UIBezierPath to cover the circle and then transforming this into a line but without luck. Commented Jun 30, 2016 at 7:17
  • Maybe add you best try to the question and somebody can help Commented Jun 30, 2016 at 7:19
  • Do you know the diameter or the radius? If you find one of this you can find the perimeter and create a UIView of 1px height (or the thickness you want for your line) and "Perimeter" width. For example (if radius = 3): Perimeter = 2*Pi*3 = 18.85. Commented Jun 30, 2016 at 7:42
  • I do know the radius. Once i've created the view, should i just set the image of the view to be the circle image? It will then transform the circle image into a line? Commented Jun 30, 2016 at 7:49

2 Answers 2

1

If you don't care about the nature of the transition, the easiest way is to do CABasicAnimation, animating the path of a CAShapeLayer from one path to another. And to achieve a patterned path with CAShapeLayer is actually to have two overlapping CAShapeLayer objects, one with a dash pattern on top of one without.

let fromPath = UIBezierPath(arcCenter: view.center, radius: 100, startAngle: 0, endAngle: CGFloat(M_PI) * 2.0, clockwise: true)
let toPath = UIBezierPath()
toPath.moveToPoint(CGPoint(x: view.frame.size.width / 2.0 - CGFloat(M_PI) * 100.0, y:view.center.y))
toPath.addLineToPoint(CGPoint(x: view.frame.size.width / 2.0 + CGFloat(M_PI) * 100.0, y: view.center.y))

let shapeLayer = CAShapeLayer()
shapeLayer.path = fromPath.CGPath
shapeLayer.lineWidth = 5
shapeLayer.strokeColor = UIColor.redColor().CGColor
shapeLayer.fillColor = UIColor.clearColor().CGColor

let shapeLayer2 = CAShapeLayer()
shapeLayer2.path = fromPath.CGPath
shapeLayer2.lineWidth = 5
shapeLayer2.strokeColor = UIColor.blackColor().CGColor
shapeLayer2.fillColor = UIColor.clearColor().CGColor
shapeLayer2.lineDashPattern = [100,50]

view.layer.addSublayer(shapeLayer)
view.layer.addSublayer(shapeLayer2)

And

shapeLayer.path = toPath.CGPath
shapeLayer2.path = toPath.CGPath

CATransaction.begin()
CATransaction.setAnimationDuration(5)

let animation = CABasicAnimation(keyPath: "path")
animation.fromValue = fromPath.CGPath
animation.toValue = toPath.CGPath
shapeLayer.addAnimation(animation, forKey: nil)

let animation2 = CABasicAnimation(keyPath: "path")
animation2.fromValue = fromPath.CGPath
animation2.toValue = toPath.CGPath
shapeLayer2.addAnimation(animation, forKey: nil)

CATransaction.commit()

Yielding:

enter image description here

If you want more control over the nature of the transition, then you have to resort to more manual techniques, e.g. a CADisplayLink in which you manually adjust the path. But that's more complicated.

Sign up to request clarification or add additional context in comments.

5 Comments

Hi! Thanks for such a informative and good answer! The only problem is was my formulation of the problem. The circle does not have a pre decided pattern, but is an Image, any future advice?
It is a non-trivial exercise to convert a random bitmap image into a shape and then proceed to that transform
I might be misunderstanding but is it? I could make a color with pattern image: var color = UIColor(patternImage: image!) and set the strokeColor. But it did not work as hoped. I cant add an image to a CAShapeLayer and a CALayer does not have a path property. All i found was: stackoverflow.com/questions/5578801/…
@Rob great answer! +1 for sharing your experience.
@LarsErik - Yes, patternImage doesn't work as expected here, which is why I did what I did. And, no, you can just add image and expect it to transform like a UIBezierPath/CGPath can. They're completely different things.
0

try this code, The animation is not perfect, but you will be able to convert an image to a line this way. I have to say that Rob's solution above is far more superior and if I were give a choice, i would do it his way.

The below code is very self-explanatory, but if in case of any doubt, feel free to ask.

To make the animation happen, tap the yellow button.

  class ViewController: UIViewController{

    var imageView : UIImageView = {
        let image = UIImageView()
        image.translatesAutoresizingMaskIntoConstraints = false
        image.layer.cornerRadius = 120
        image.backgroundColor = UIColor.clearColor()
        image.layer.borderWidth = 3.0
        image.layer.borderColor = UIColor.blackColor().CGColor
        return image
    }()

    var animatorButton : UIButton = {
        let button = UIButton()
        button.translatesAutoresizingMaskIntoConstraints = false
        button.tintColor = UIColor.blueColor()
        button.layer.borderWidth = 3.0
        button.layer.borderColor = UIColor.blackColor().CGColor
        button.backgroundColor = UIColor.yellowColor()
        return button
    }()

    var constraintHeight = [NSLayoutConstraint]()
    override func viewDidLoad() {

        view.addSubview(imageView)
        view.addSubview(animatorButton)

        view.addConstraint(view.centerXAnchor.constraintEqualToAnchor(imageView.centerXAnchor))
        view.addConstraints(NSLayoutConstraint.constraintsWithVisualFormat("H:[imageView(240)]", options: NSLayoutFormatOptions(), metrics: nil, views: ["imageView": imageView]))

        self.constraintHeight = NSLayoutConstraint.constraintsWithVisualFormat("V:|-100-[imageView(240)]", options: NSLayoutFormatOptions(), metrics: nil, views: ["imageView": imageView])
        view.addConstraints(constraintHeight)


        view.addConstraint(animatorButton.centerXAnchor.constraintEqualToAnchor(view.centerXAnchor))
        view.addConstraints(NSLayoutConstraint.constraintsWithVisualFormat("V:|-450-[Button(40)]", options: NSLayoutFormatOptions(), metrics: nil, views: ["Button": animatorButton]))
        view.addConstraints(NSLayoutConstraint.constraintsWithVisualFormat("H:|[Button]|", options: NSLayoutFormatOptions(), metrics: nil, views: ["Button": animatorButton]))


        animatorButton.addTarget(self, action: #selector(ViewController.animateImageToLine), forControlEvents: .TouchUpInside)
    }

    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
        // Dispose of any resources that can be recreated.
    }

    func animateImageToLine() {

        view.removeConstraints(constraintHeight)
        constraintHeight = NSLayoutConstraint.constraintsWithVisualFormat("V:|-100-[imageView(3)]", options: NSLayoutFormatOptions(), metrics: nil, views: ["imageView": imageView])
        view.addConstraints(constraintHeight)
        UIView.animateWithDuration(0.3, animations: {
            self.imageView.layer.cornerRadius = 0
               self.view.layoutIfNeeded()


            }, completion: { success in
                self.imageView.backgroundColor = UIColor.blackColor()
                self.imageView.layer.borderWidth = 3.0
        })

    }
    }

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.