具有CAShapeLayer根层的自定义UIView,希望在设备旋转动画期间更新图形边界

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

我想要的确切结果是,在设备旋转动画期间,将由faceView的边界驱动的faceView的绘图内容更新为faceView的边界。

旋转设备时,我希望椭圆的大小在动画过程中完全填满视图的边界。

相反,背景颜色可以正确设置动画,但是在旋转动画开始之前形状会突然更改为其新的大小和颜色。

我尝试过的似乎无济于事的是,在关键帧动画中使用以下内容实现viewWillTransition

self.setColors()
self.faceView.updatePath()

我看不出如何使形状的路径和填充颜色包含在动画中。

ViewController

class ViewController: UIViewController {

    lazy var faceView = FaceView()
    var colorSwitch = true

    var faceViewConstraints = [NSLayoutConstraint]()

    override func loadView() {
        super.loadView()

        self.view.addSubview(faceView)
        self.faceView.viewFrame = self.faceView.bounds
        setupConstraints()
        activateConstraints()
    }

    override func viewDidLoad() { 
        super.viewDidLoad()
        self.setColors()
    }

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

        coordinator.animate(alongsideTransition: {_ in

            UIView.animateKeyframes(withDuration: coordinator.transitionDuration, delay: 0, animations: {
                UIView.addKeyframe(withRelativeStartTime: 0, relativeDuration: 1) {

                    self.setColors()
                    self.faceView.updatePath()
                }
            })
        })
    }

    private func setColors() {
        if (colorSwitch) {
            self.faceView.backgroundColor = .red
            self.faceView.shapeFillColor = .blue
        } else {
            self.faceView.backgroundColor = .blue
            self.faceView.shapeFillColor = .red
        }
        self.colorSwitch = !self.colorSwitch
    }

    private func setupConstraints() {

        let safeArea = view.safeAreaLayoutGuide

        let aspectConstraint = faceView.widthAnchor.constraint(equalTo: faceView.heightAnchor, multiplier: 9/16)
        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 Class

class FaceView: UIView {

    // use custom root layer
    override class var layerClass: AnyClass {
        return CAShapeLayer.self
    }

    var viewFrame = CGRect.zero {
        didSet { 
            self.circleBounds = viewFrame.insetBy(dx: lineW/2, dy: lineW/2)
        }
    }

    var circleBounds = CGRect.zero
    var lineW: CGFloat = 3
    var myLayer: CAShapeLayer!
    var shapeFillColor = UIColor.blue

    override init(frame: CGRect) {
        super.init(frame: frame)
        self.translatesAutoresizingMaskIntoConstraints = false
        myLayer = self.layer as? CAShapeLayer
        updatePath()
    }

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

    override func layoutSubviews() {
        super.layoutSubviews()
        myLayer.contentsScale = UIScreen.main.scale
        myLayer.lineWidth = lineW
        myLayer.fillColor = shapeFillColor.cgColor
        myLayer.strokeColor = UIColor.black.cgColor
        viewFrame = self.bounds
        updatePath()
    }

    func updatePath() {
        myLayer.fillColor = shapeFillColor.cgColor
        viewFrame = self.bounds
        let p = CGMutablePath()
        p.addEllipse(in: circleBounds)
        myLayer.path = p
    }
}
ios xcode uiview calayer
1个回答
0
投票

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

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

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