我正试图使用CoreAnimation来制作一个填充矩形的动画。当把动画添加到 CAShapeLayer
但是,这个动画看起来很奇怪。
我已经附上了gif。
我做了一个小例子
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")
}
}
去掉圆角后,一切都很好。我怎样才能修复动画,使它只在一个维度上(从下到上)产生动画?
你可以使用自动布局来实现:在控制器类下声明你的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)
}
这就是结果。