Deepak Sharma
Deepak Sharma

Reputation: 6477

UIView autorotation issue

I am getting issues in autorotation of a UIView which is nothing but a red line of width 4 and height half of superview's height in landscape mode, and in portrait mode the height is 4 points and width is half of superview width. You can see the issue in the gif. As I rotate from landscape to portrait, the effect of autorotation is not smooth and with distortions.

enter image description here

Here is the code. What am I doing wrong?

private var myView:UIView!

override func viewDidLoad() {
    super.viewDidLoad()
    // Do any additional setup after loading the view, typically from a nib.

    myView = UIView(frame: CGRect(x: 0, y: 0, width: self.view.bounds.width/2, height: 4))
    myView.backgroundColor = UIColor.red
    view.addSubview(myView)

    myView.center = CGPoint(x: view.bounds.width/2, y: view.bounds.height/2)


}

private func layoutMyView() {

    let orientation = UIApplication.shared.statusBarOrientation

    if orientation == .landscapeLeft || orientation == .landscapeRight {
        myView.frame = CGRect(x: 0, y: 0, width: view.bounds.width/2, height: 4)
    } else {
        myView.frame = CGRect(x: 0, y: 0, width: 4, height: view.bounds.height/2)
    }

    myView.center = CGPoint(x: view.bounds.width/2, y: view.bounds.height/2)
}


override func viewWillTransition(to size: CGSize, with coordinator: UIViewControllerTransitionCoordinator) {

    let orientation = UIApplication.shared.statusBarOrientation

    NSLog("View will transition to \(size), \(orientation.rawValue)")

    if size.width < size.height {
        NSLog("Portrait mode")
    } else {
        NSLog("Landscape mode")
    }

    super.viewWillTransition(to: size, with: coordinator)

    coordinator.animate(alongsideTransition: { [unowned self] (_) in

        let orient = UIApplication.shared.statusBarOrientation

         self.layoutMyView()

        }, completion: { [unowned self] (UIViewControllerTransitionCoordinatorContext) -> Void in

            let orient = UIApplication.shared.statusBarOrientation
            self.layoutMyView()
            NSLog("rotation completed to \(orient.rawValue), \(self.myView.frame)")
    })
}

Upvotes: 0

Views: 284

Answers (1)

Rob
Rob

Reputation: 437392

There are a few potential options:

  1. In animate(alongsideTransition:completion:), do a keyframe animation to set mid animation point so you don’t end up with that curious boxy feel mid animation. E.g. this shrink it down to a 4x4 box

    override func viewWillTransition(to size: CGSize, with coordinator: UIViewControllerTransitionCoordinator) {
        super.viewWillTransition(to: size, with: coordinator)
    
        let origin = CGPoint(x: (view.bounds.midX + view.bounds.midY) / 2 - 2,
                             y: (view.bounds.midX + view.bounds.midY) / 2 - 2)
    
        coordinator.animate(alongsideTransition: { _ in
            UIView.animateKeyframes(withDuration: coordinator.transitionDuration, delay: 0, animations: {
                UIView.addKeyframe(withRelativeStartTime: 0, relativeDuration: 0.5) {
                    self.myView.frame = CGRect(origin: origin, size: CGSize(width: 4, height: 4))
                }
    
                UIView.addKeyframe(withRelativeStartTime: 0.5, relativeDuration: 0.5) {
                    self.layoutMyView()
                }
            })
        })
    }
    

    There are many possible variations on this theme. This still animates the view, but gives it a more “deliberate” sort of vibe and doesn’t lose the “line” feel of it.

    enter image description here

  2. Rather than rendering a “line” with UIView, use CAShapeLayer and update its path.

  3. You could run a CADisplayLink while transition is in progress, and then update the frame to whatever you want as the animation progresses.

  4. Instead of animating the frame, you could animate the transform of this view, possibly rotating it in the opposite direction that the view is rotating.

Upvotes: 2

Related Questions