简体   繁体   English

iPhone 旋转时 CALayer 的自动旋转

[英]Autorotation of CALayer on iPhone rotation

I have a UIViewController where I am adding a CALayer subclass to the view's layer:我有一个 UIViewController,我在其中向视图层添加了 CALayer 子类:

[self.view.layer addSublayer:myObject.backgroundLayer];

When I rotate the device, the view rotates, but the CALayer doesn't.当我旋转设备时,视图会旋转,但 CALayer 不会。 It sort of gets shunted off to the left, still in portrait view.它有点被分流到左边,仍然是纵向视图。

Is there a way to make sublayers rotate automatically or do I need to apply a transform?有没有办法让子图层自动旋转,或者我需要应用变换吗?

With Swift 4 / iOS 11, according to your needs, you may choose one of the 6 following examples in order to manage your CALayer / CAGradientLayer frame upon a device rotation.使用 Swift 4 / iOS 11,根据您的需要,您可以选择以下 6 个示例之一,以便在设备旋转时管理您的CALayer / CAGradientLayer框架。

The examples below use CAGradientLayer but can easily be mapped to CALayer or CAShapeLayer cases.下面的示例使用CAGradientLayer但可以轻松映射到CALayerCAShapeLayer案例。


#1. #1. Overriding UIViewController viewDidLayoutSubviews()覆盖UIViewController viewDidLayoutSubviews()

import UIKit

class ViewController: UIViewController {

    let gradientLayer: CAGradientLayer = {
        let layer = CAGradientLayer()
        layer.colors = [
            UIColor.blue.cgColor,
            UIColor.cyan.cgColor
        ]
        return layer
    }()

    override func viewDidLoad() {
        super.viewDidLoad()

        view.layer.addSublayer(gradientLayer)
        gradientLayer.frame = view.bounds
    }

    override func viewDidLayoutSubviews() {         
        gradientLayer.frame = view.bounds
    }

}

#2. #2. Overriding UIViewController loadView() , subclassing UIView and overriding UIView layoutSubviews()覆盖UIViewController loadView()UIView和覆盖UIView layoutSubviews()

LayerView.swift图层视图.swift

import UIKit

class LayerView: UIView {

    lazy var gradientLayer: CAGradientLayer = {
        let layer = CAGradientLayer()
        layer.colors = [
            UIColor.blue.cgColor,
            UIColor.cyan.cgColor
        ]
        self.layer.addSublayer(layer)
        return layer
    }()

    override func layoutSubviews() {
        gradientLayer.frame = bounds
    }

}

LayerView.swift (alternative) LayerView.swift(替代)

import UIKit

class LayerView: UIView {

    var gradientLayer: CAGradientLayer!

    override func layoutSubviews() {
        if gradientLayer == nil {
            let gradientLayer = CAGradientLayer()
            gradientLayer.colors = [
                UIColor.blue.cgColor,
                UIColor.cyan.cgColor
            ]
            self.gradientLayer = gradientLayer
            layer.addSublayer(gradientLayer)
        }

        gradientLayer.frame = bounds
    }

}

ViewController.swift视图控制器.swift

import UIKit

class ViewController: UIViewController {

    let layerView = LayerView()

    override func loadView() {
        view = layerView
    }

}

#3. #3. Using Key Value Observing (KVO)使用键值观察 (KVO)

import UIKit

class ViewController: UIViewController {

    var observation: NSKeyValueObservation?

    let gradientLayer: CAGradientLayer = {
        let layer = CAGradientLayer()
        layer.colors = [
            UIColor.blue.cgColor,
            UIColor.cyan.cgColor
        ]
        return layer
    }()

    override func viewDidLoad() {
        super.viewDidLoad()

        view.layer.addSublayer(gradientLayer)

        observation = view.observe(\.frame, options: [.new], changeHandler: { [unowned self] (object: UIView, change: NSKeyValueObservedChange<CGRect>) in
            guard let frame = change.newValue else { return }
            self.gradientLayer.frame = frame
        })

        // Also works
        /*
        observation = observe(\.view.frame, options: [.new], changeHandler: { [unowned self] (object: ViewController, change: NSKeyValueObservedChange<CGRect>) in
            guard let frame = change.newValue else { return }
            self.gradientLayer.frame = frame
        })
        */
    }

}

#4. #4. Overriding UIViewController loadView() , subclassing UIView and overriding UIView layerClass覆盖UIViewController loadView()layerClass UIView和覆盖UIView layerClass

LayerView.swift图层视图.swift

import UIKit

class LayerView: UIView {

    override public class var layerClass: AnyClass {
        return CAGradientLayer.self
    }

    required init() {
        super.init(frame: .zero)

        guard let gradientLayer = layer as? CAGradientLayer else { return }
        gradientLayer.colors = [
            UIColor.blue.cgColor,
            UIColor.cyan.cgColor
        ]
    }

    required init?(coder aDecoder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }

}

ViewController.swift视图控制器.swift

import UIKit

class ViewController: UIViewController {

    let layerView = LayerView()

    override func loadView() {
        view = layerView
    }

}

#5. #5. Overriding UIViewController loadView() , subclassing UIView and overriding CALayerDelegate layoutSublayers(of:)覆盖UIViewController loadView()CALayerDelegate UIView和覆盖CALayerDelegate layoutSublayers(of:)

LayerView.swift图层视图.swift

import UIKit

class LayerView: UIView {

    required init() {
        super.init(frame: .zero)

        let gradientLayer = CAGradientLayer()
        gradientLayer.colors = [
            UIColor.blue.cgColor,
            UIColor.cyan.cgColor
        ]

        layer.addSublayer(gradientLayer)
    }

    required init?(coder aDecoder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }

    override func layoutSublayers(of layer: CALayer) {
        layer.sublayers?.forEach {
            $0.frame = layer.bounds
        }
    }

}

ViewController.swift视图控制器.swift

import UIKit

class ViewController: UIViewController {

    let layerView = LayerView()

    override func loadView() {
        view = layerView
    }

}

#6. #6. Overriding UIViewController loadView() , subclassing UIView , overriding UIView layerClass , subclassing CALayer and overriding CALayer layoutSublayers()覆盖UIViewController loadView() ,子类化UIView ,覆盖UIView layerClass ,子类化CALayer和覆盖CALayer layoutSublayers()

Layer.swift层.swift

import UIKit

class Layer: CALayer {

    override init() {
        super.init()

        let gradientLayer = CAGradientLayer()
        gradientLayer.colors = [
            UIColor.blue.cgColor,
            UIColor.cyan.cgColor
        ]

        addSublayer(gradientLayer)
    }

    required init?(coder aDecoder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }

    override func layoutSublayers() {
        sublayers?.forEach {
            $0.frame = bounds
        }
    }

}

LayerView.swift图层视图.swift

import UIKit

class LayerView: UIView {

    override public class var layerClass: AnyClass {
        return Layer.self
    }

}

ViewController.swift视图控制器.swift

import UIKit

class ViewController: UIViewController {

    let layerView = LayerView()

    override func loadView() {
        view = layerView
    }

}

Sources:资料来源:

You need to manage the rotation of the CALayer yourself.您需要自己管理 CALayer 的旋转。 I believe that 0,0 stays at the same place and that the size is changed to match the new orientation, so if you wanted to do something yourself, you'd need to manage the addition of the rotation transformation yourself.我相信 0,0 保持在同一个位置,并且大小会改变以匹配新的方向,所以如果你想自己做一些事情,你需要自己管理旋转变换的添加。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM