用CoreAnimation制作填充矩形动画

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

我正试图使用CoreAnimation来制作一个填充矩形的动画。当把动画添加到 CAShapeLayer但是,这个动画看起来很奇怪。

我已经附上了gif。

Example Animation

我做了一个小例子

import Foundation
import UIKit

class TestView : UIView
{
    private var progressLayer = CAShapeLayer()

    override init(frame: CGRect)
    {
        super.init(frame: frame)

        self.commonInit()
    }

    required init?(coder: NSCoder)
    {
        super.init(coder: coder)

        self.commonInit()
    }

    override func layoutSubviews()
    {
        super.layoutSubviews()

        self.commonInit()
    }

    fileprivate func commonInit()
    {
        self.progressLayer.removeFromSuperlayer()

        let barWidth: CGFloat = self.frame.width * 0.33

        let path = UIBezierPath(roundedRect: CGRect(x: self.bounds.width / 2 - barWidth / 2.0, y: self.bounds.height - 1.0, width: barWidth, height: 1.0), byRoundingCorners: [.topLeft, .topRight], cornerRadii: CGSize(width: 6.0, height: 6.0))
        self.progressLayer.path = path.cgPath
        self.progressLayer.fillColor = UIColor.systemBlue.cgColor
        self.progressLayer.strokeColor = UIColor.clear.cgColor

        Swift.print(self.progressLayer.position)
        self.progressLayer.position = CGPoint(x: -barWidth / 2.0, y: 0.0)

        self.layer.addSublayer(self.progressLayer)
    }

    func animate()
    {
        let barWidth: CGFloat = self.frame.width * 0.33

        let from = UIBezierPath(roundedRect: CGRect(x: self.bounds.width / 2 - barWidth / 2.0, y: self.bounds.height - 1.0, width: barWidth, height: 1.0), byRoundingCorners: [.topLeft, .topRight], cornerRadii: CGSize(width: 6.0, height: 6.0))
        let to = UIBezierPath(roundedRect: CGRect(x: self.bounds.width / 2 - barWidth / 2.0, y: 0.0, width: barWidth, height: self.bounds.height), byRoundingCorners: [.topLeft, .topRight], cornerRadii: CGSize(width: 6.0, height: 6.0))

        // This works fine.
//        let from = UIBezierPath(rect: CGRect(x: self.bounds.width / 2 - barWidth / 2.0, y: self.bounds.height - 1.0, width: barWidth, height: 1.0))
//        let to = UIBezierPath(rect: CGRect(x: self.bounds.width / 2 - barWidth / 2.0, y: 0.0, width: barWidth, height: self.bounds.height))

        let animation = CABasicAnimation(keyPath: "path")
        animation.fromValue = from.cgPath
        animation.toValue = to.cgPath
        animation.duration = 0.8
        animation.timingFunction = CAMediaTimingFunction(name: .easeInEaseOut)
        animation.fillMode = .forwards
        animation.isRemovedOnCompletion = false

        self.progressLayer.add(animation, forKey: "path")
    }
}

去掉圆角后,一切都很好。我怎样才能修复动画,使它只在一个维度上(从下到上)产生动画?

swift core-animation
1个回答
0
投票

你可以使用自动布局来实现:在控制器类下声明你的UIViews和你的按钮。

let grayView = UIView()
let blueView = UIView()
let button = UIButton(type: .system)

在viewDidLoad中设置属性和cal函数的约束。

button.backgroundColor = .red
    button.setTitle("Up", for: .normal)
    button.setTitleColor(.white, for: .normal)
    button.titleLabel?.font = .systemFont(ofSize: 16, weight: .semibold)
    button.addTarget(self, action: #selector(handleUp), for: .touchUpInside)
    button.translatesAutoresizingMaskIntoConstraints = false

    grayView.backgroundColor = .gray
    grayView.translatesAutoresizingMaskIntoConstraints = false

    blueView.backgroundColor = .blue
    blueView.translatesAutoresizingMaskIntoConstraints = false

    setupConstraints()

现在在viewDidLoad下面设置动画的变量:

var normalHeight: NSLayoutConstraint?
var newHeight: NSLayoutConstraint?

然后写函数来设置约束条件,最后一步写函数来调用动画

fileprivate func setupConstraints() {

    view.addSubview(grayView)
    grayView.topAnchor.constraint(equalTo: view.safeAreaLayoutGuide.topAnchor, constant: 50).isActive = true
    grayView.leadingAnchor.constraint(equalTo: view.safeAreaLayoutGuide.leadingAnchor, constant: 50).isActive = true
    grayView.trailingAnchor.constraint(equalTo: view.safeAreaLayoutGuide.trailingAnchor, constant: -50).isActive = true
    grayView.bottomAnchor.constraint(equalTo: view.safeAreaLayoutGuide.bottomAnchor, constant: -50).isActive = true

    grayView.addSubview(blueView)
    blueView.bottomAnchor.constraint(equalTo: grayView.bottomAnchor, constant: 0).isActive = true
    blueView.trailingAnchor.constraint(equalTo: grayView.trailingAnchor, constant: -40).isActive = true
    blueView.leadingAnchor.constraint(equalTo: grayView.leadingAnchor, constant: 40).isActive = true
    normalHeight = blueView.heightAnchor.constraint(equalToConstant: 10)
    normalHeight?.isActive = true

    newHeight = blueView.topAnchor.constraint(equalTo: grayView.topAnchor)

    view.addSubview(button)
    button.topAnchor.constraint(equalTo: grayView.bottomAnchor, constant: 10).isActive = true
    button.leadingAnchor.constraint(equalTo: grayView.leadingAnchor).isActive = true
    button.trailingAnchor.constraint(equalTo: grayView.trailingAnchor).isActive = true
    button.bottomAnchor.constraint(equalTo: view.safeAreaLayoutGuide.bottomAnchor).isActive = true
}

最后一步写函数来调用动画并设置角半径。

@objc fileprivate func handleUp() {
    UIView.animate(withDuration: 0.5, delay: 0, options: .curveEaseOut, animations: {
        self.normalHeight?.isActive = false
        self.newHeight?.isActive = true
        self.blueView.layer.cornerRadius = 14
        self.blueView.layer.maskedCorners = [.layerMaxXMinYCorner, .layerMinXMinYCorner]
        self.view.layoutIfNeeded()
    }, completion: nil)
}

这就是结果。

enter image description here

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