Disable autorotate on a single subview in iOS8

后端 未结 5 936
遇见更好的自我
遇见更好的自我 2020-12-10 07:33

I\'m writing a drawing app and I don\'t want the drawing view to rotate. At the same time, I want other controls to rotate nicely depending on the orientation of the device.

5条回答
  •  离开以前
    2020-12-10 08:31

    I managed to obtain this, check:

    rotation working as desired

    Note: The green and the red views are subviews of the controller's view. The blue view is subview of the red view.

    Idea According to https://developer.apple.com/library/archive/qa/qa1890/_index.html, we need to apply an inverse rotation to the view when it is transitioning to a new size. In addition to that, we need to adjust the constraints after rotation (landscape/portrait).

    Implementation

    class MyViewController: UIViewController {
    
        var viewThatShouldNotRotate = UIView()
    
        var view2 = UIView()
    
        var insiderView = UIView()
    
        var portraitConstraints: [NSLayoutConstraint]!
    
        var landscapeConstraints: [NSLayoutConstraint]!
    
        override func viewDidLoad() {
            super.viewDidLoad()
    
            viewThatShouldNotRotate.backgroundColor = .red
    
            view2.backgroundColor = .green
    
            insiderView.backgroundColor = .blue
    
            view.addSubview(viewThatShouldNotRotate)
            view.addSubview(view2)
    
    
            viewThatShouldNotRotate.addSubview(insiderView)
            portraitConstraints = createConstraintsForPortrait()
            landscapeConstraints = createConstraintsForLandscape()
        }
    
        func createConstraintsForLandscape() -> [NSLayoutConstraint] {
            return NSLayoutConstraint.autoCreateConstraintsWithoutInstalling {
                viewThatShouldNotRotate.autoMatch(.height, to: .width, of: view)
                viewThatShouldNotRotate.autoMatch(.width, to: .height, of: view)
                viewThatShouldNotRotate.autoCenterInSuperview()
    
                view2.autoPinEdgesToSuperviewEdges(with: UIEdgeInsets(), excludingEdge: .top)
                view2.autoSetDimension(.height, toSize: 100)
    
                insiderView.autoPinEdges(toSuperviewMarginsExcludingEdge: .bottom)
                insiderView.autoSetDimension(.height, toSize: 100)
            }
        }
    
        func createConstraintsForPortrait() -> [NSLayoutConstraint] {
            return NSLayoutConstraint.autoCreateConstraintsWithoutInstalling {
                viewThatShouldNotRotate.autoMatch(.height, to: .height, of: view)
                viewThatShouldNotRotate.autoMatch(.width, to: .width, of: view)
                viewThatShouldNotRotate.autoCenterInSuperview()
                view2.autoPinEdges(toSuperviewMarginsExcludingEdge: .top)
                view2.autoSetDimension(.height, toSize: 100)
                insiderView.autoPinEdges(toSuperviewMarginsExcludingEdge: .bottom)
                insiderView.autoSetDimension(.height, toSize: 100)
            }
        }
    
        override func viewDidLayoutSubviews() {
            super.viewDidLayoutSubviews()
            if view.bounds.size.width > view.bounds.size.height {
                // landscape
                portraitConstraints.forEach {$0.autoRemove()}
                landscapeConstraints.forEach { $0.autoInstall() }
            } else {
                landscapeConstraints.forEach {$0.autoRemove()}
                portraitConstraints.forEach { $0.autoInstall() }
            }
        }
    
        override func viewWillTransition(to size: CGSize, with coordinator: UIViewControllerTransitionCoordinator) {
            super.viewWillTransition(to: size, with: coordinator)
    
            let viewToRotate: UIView = viewThatShouldNotRotate
    
            coordinator.animate(alongsideTransition: { (UIViewControllerTransitionCoordinatorContext) -> Void in
                let deltaTransform = coordinator.targetTransform
                let deltaAngle = atan2f(Float(deltaTransform.b), Float(deltaTransform.a))
    
                var currentRotation = (viewToRotate.layer.value(forKeyPath: "transform.rotation.z") as! NSNumber).floatValue
    
                // Adding a small value to the rotation angle forces the animation to occur in a the desired direction, preventing an issue where the view would appear to rotate 2PI radians during a rotation from LandscapeRight -> LandscapeLeft.
                currentRotation = currentRotation + (-1 * Float(deltaAngle)) + 0.0001
                viewToRotate.layer.setValue(currentRotation, forKeyPath:"transform.rotation.z")
    
            }) { (UIViewControllerTransitionCoordinatorContext) -> Void in
    
                var currentTransform = viewToRotate.transform;
                currentTransform.a = round(currentTransform.a);
                currentTransform.b = round(currentTransform.b);
                currentTransform.c = round(currentTransform.c);
                currentTransform.d = round(currentTransform.d);
                viewToRotate.transform = currentTransform;
            }
        }
    }
    

提交回复
热议问题