Animating shape layer type custom UIViews, during a UIView.animate?

The behavior you describe has to do with the way that iOS animations work. Specifically when you set the frame of a view in a UIAnimation block (that's what layoutIfNeeded does -- it forces a synchronous recalculation of the frame according to the autolayout rules) the view's frame immediately changes to the new value which is the apparent value at the end of the animation (add a print statement after layoutIfNeeded and you can see this is true). Incidentally changing the constraints doesn't do anything until layoutIfNeeded is called so you don't even need to put the constraint change in the animation block.

However during the animation, the system shows the presentation layer instead of the backing layer and it interpolates the value of the frame from the presentation layer from the initial value to the final value over the duration of the animation. This makes it look like the view is moving even though inspecting the value will reveal the view has already assumed its final position.

Therefore if you want the actual coordinates of the on screen layer while an animation is in flight, you have to use view.layer.presentationLayer to get them. See: https://developer.apple.com/reference/quartzcore/calayer/1410744-presentationlayer

This doesn't entirely solve your problem through because I assume that what you are trying to do is to spawn more layers as time goes on. If you cannot do with simple interpolation then you may be better off spawning all of the layers at the beginning and then using a keyframe animation to turn them on at certain intervals as the animation progresses. You can base your layer positions on view.layer.presentationLayer.bounds (your sublayers are in their super layers coordinates so don't use frame). It's difficult to provide an exact solution without knowing what you are trying to accomplish.

Another possible solution is to use drawRect with CADisplayLink which lets you redraw each frame however you want, so it's much more suited to things that cannot be easily interpolated from frame to frame (i.e. games or in your case adding/removing and animating geometry as a function of time).

Edit: Here is an example Playground showing how to animate the layer in parallel with the view.

    //: Playground - noun: a place where people can play

    import UIKit
    import PlaygroundSupport

    class V: UIViewController {
        var a = UIView()
        var b = CAShapeLayer()
        var constraints: [NSLayoutConstraint] = []
        override func viewDidLoad() {
            view.addSubview(a)
            a.translatesAutoresizingMaskIntoConstraints = false
            constraints = [
                a.topAnchor.constraint(equalTo: view.topAnchor, constant: 100),
                a.leadingAnchor.constraint(equalTo: view.leadingAnchor, constant: 100),
                a.widthAnchor.constraint(equalToConstant: 200),
                a.heightAnchor.constraint(equalToConstant: 200)

            ]
            constraints.forEach {$0.isActive = true}
            a.backgroundColor = .blue
        }

        override func viewDidAppear(_ animated: Bool) {
            b.path = UIBezierPath(ovalIn: a.bounds).cgPath
            b.fillColor = UIColor.red.cgColor
            a.layer.addSublayer(b)
            constraints[3].constant = 400
            constraints[2].constant = 400
            let oldBounds = a.bounds
            UIView.animate(withDuration: 3, delay: 0, options: .curveLinear, animations: {
                self.view.layoutIfNeeded()
            }, completion: nil)
            let scale = a.bounds.size.width / oldBounds.size.width
            let animation = CABasicAnimation(keyPath: "transform.scale")
            animation.fromValue = 1
            animation.toValue = scale
            animation.duration = 3
            b.add(animation, forKey: "scale")
            b.transform = CATransform3DMakeScale(scale, scale, 1)

        }
    }

    let v = V()
    PlaygroundPage.current.liveView = v