通过设备旋转调整CALayer的平滑动画大小

问题描述 投票:1回答:1

这里,我有一个自定义UIView,它由一个自定义CALayer支持,该CALayer只是画一个圆。我已经设置了约束,以使视图保持正方形和居中,并且在旋转设备时始终适合屏幕。

我希望在视图层中绘制的所有内容与在设备旋转时创建的动画过程中所绘制的层一起平滑缩放。

我想了解如何将其用于具有多个图层和/或子视图以及大量自定义工程图的视图。首先,我将问题简化为一层,从而绘制了一个与视图边界链接的简单形状。

照原样,在旋转动画发生之前,圆会调整为最终边界大小。

我想做的事情我想要的确切结果是,对circleBounds的更改将与faceView的大小一起进行动画处理,而不是在圆圈刚改变之前将其突然更改为其新的大小。旋转动画开始。

另外,在此示例中,旋转在iPhone模拟器中看起来很平滑,因为圆实际上并没有改变大小。在iPad上,问题变得很明显。

我尝试过的似乎没有帮助的是this answer

您需要通过视图来管理[CALayer]。您可以通过创建一个使用[CALayer]作为其图层的UIView子类来做到这一点。

我还根据.insertSubview(faceView, at: 0),在同一问题上尝试使用loadView()中的another answer,但这也无济于事。

//      self.view.addSubview(faceView)
        self.view.insertSubview(faceView, at: 0)

[我也尝试将this answerinsertSubView方法结合使用,但未成功。

    override func viewWillLayoutSubviews() {
        view.layer.sublayers![0].frame = view.bounds
    }

View Controller

class ViewController: UIViewController {

    lazy var faceView = FaceView2(frame: self.view.bounds)

    var faceViewConstraints = [NSLayoutConstraint]()

    override func loadView() {
        super.loadView()
        self.view.addSubview(faceView)
        setupConstraints()
        activateConstraints()
    }

    override func viewDidLoad() {
        super.viewDidLoad()
        faceView.backgroundColor = .cyan
    }

    private func setupConstraints() {

        let safeArea = view.safeAreaLayoutGuide

        let aspectConstraint = faceView.widthAnchor.constraint(equalTo: faceView.heightAnchor, multiplier: 1/1)
        let centerXConstraint = faceView.centerXAnchor.constraint(equalTo: faceView.superview!.centerXAnchor)
        let centerYConstraint = faceView.centerYAnchor.constraint(equalTo: faceView.superview!.centerYAnchor)

        // medium high priority constraints
        let leadingConstraintMedHigh = faceView.leadingAnchor.constraint(equalTo: safeArea.leadingAnchor, constant: 10)
        leadingConstraintMedHigh.priority = UILayoutPriority(750)

        let trailingConstraintMedHigh = faceView.trailingAnchor.constraint(equalTo: safeArea.trailingAnchor, constant: 10)
        trailingConstraintMedHigh.priority = UILayoutPriority(750)

        let topConstraintMedHigh = faceView.topAnchor.constraint(equalTo: safeArea.topAnchor, constant: 10)
        topConstraintMedHigh.priority = UILayoutPriority(750)

        let bottomConstraintMedHigh = faceView.bottomAnchor.constraint(equalTo: safeArea.bottomAnchor, constant: -10)
        bottomConstraintMedHigh.priority = UILayoutPriority(750)

        // required constraints
        let leadingConstraintHigh = faceView.leadingAnchor.constraint(greaterThanOrEqualTo: safeArea.leadingAnchor, constant: 10)
        leadingConstraintHigh.priority = UILayoutPriority(1000)

        let trailingConstraintHigh = faceView.trailingAnchor.constraint(lessThanOrEqualTo: safeArea.trailingAnchor, constant: 10)
        trailingConstraintHigh.priority = UILayoutPriority(1000)

        let topConstraintHigh = faceView.topAnchor.constraint(greaterThanOrEqualTo: safeArea.topAnchor, constant: 10)
        topConstraintHigh.priority = UILayoutPriority(1000)

        let bottomConstraintHigh = faceView.bottomAnchor.constraint(lessThanOrEqualTo: safeArea.bottomAnchor, constant: -10)
        bottomConstraintHigh.priority = UILayoutPriority(1000)

        faceViewConstraints = [aspectConstraint, centerXConstraint, centerYConstraint, leadingConstraintMedHigh, trailingConstraintMedHigh, topConstraintMedHigh, bottomConstraintMedHigh, leadingConstraintHigh, trailingConstraintHigh, topConstraintHigh, bottomConstraintHigh]
    }

    private func activateConstraints() {
        NSLayoutConstraint.activate(faceViewConstraints)
    }
}

View&Layer Class

class FaceView2: UIView {

    override init(frame: CGRect) {
        super.init(frame: frame)
        self.translatesAutoresizingMaskIntoConstraints = false
    }

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

    override class var layerClass: AnyClass {
        return FaceLayer.self
    }
}

class FaceLayer: CAShapeLayer {

    private var circleBounds: CGRect!
    private var viewCenter: CGPoint!
    private var lineW: CGFloat = 15

    override init() {
        super.init()
        contentsScale = UIScreen.main.scale
        circleBounds = self.bounds.insetBy(dx: lineW / 2, dy: lineW / 2)
    }

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

    override func layoutSublayers() {

        self.contentsScale = UIScreen.main.scale
        self.lineWidth = lineW
        self.fillColor = UIColor.lightGray.cgColor
        self.strokeColor = UIColor.black.cgColor

        circleBounds = self.bounds.insetBy(dx: lineW / 2, dy: lineW / 2)

        let p = CGMutablePath()
        p.addEllipse(in: circleBounds)
        self.path = p
    }
}
ios xcode uiview calayer
1个回答
0
投票

我不清楚您要达到的确切结果,但是通常要知道的关键是:如果实现viewWillLayoutSubviews,并且在该实现中是否更改了视图的约束或框架(取决于视图是否受自动布局影响),这些更改将与内置的旋转动画一起进行动画处理。

或者(并且不相关),您可以实现viewWillTransitionwillTransition,获取过渡协调器,并调用其animate(alongsideTransition:completion:)。同样,您在此处执行的任何动画都将成为旋转动画的一部分。

© www.soinside.com 2019 - 2024. All rights reserved.