[英]CABasicAnimation CALayer Path Animation Direction
我正在嘗試使用CABasicAnimation
鍵路徑設置圖層路徑屬性但是。 沒有得到准確的結果
我正在尋找的路徑 animation 的變化如下
預期 Animation
注意:-請忽略開關.. 我的重點只是從circular
到moon
animation 的路徑變化
我試過的
這是我試圖獲得此路徑轉換的代碼 animation
@IBDesignable class CustomView: UIView {
private lazy var shapeLayer = CAShapeLayer()
override init(frame: CGRect) {
super.init(frame: frame)
commonInit()
}
required init?(coder: NSCoder) {
super.init(coder: coder)
commonInit()
}
private func commonInit() {
shapeLayer.frame = bounds
shapeLayer.fillColor = UIColor.black.cgColor
shapeLayer.strokeColor = UIColor.red.cgColor
shapeLayer.lineWidth = 3
layer.addSublayer(shapeLayer)
}
override func layoutSubviews() {
shapeLayer.path = drawSunShape(bounds)
}
private func drawSunShape(_ group:CGRect) -> CGPath {
let bezierPath = UIBezierPath()
let radius = group.maxX/2
let center = CGPoint(x: group.midX, y: group.midY)
bezierPath.addArc(withCenter:center, radius: radius, startAngle: -.pi/2, endAngle: 3 * .pi * 0.5 , clockwise: true)
return bezierPath.cgPath
}
private func drawMoonShape(_ group:CGRect) -> CGPath {
let rad : CGFloat = group.maxX/2
let center = CGPoint(x: group.midX, y: group.midY)
let big = UIBezierPath()
big.addArc(withCenter: center, radius: rad, startAngle:-.pi/2.0, endAngle: .pi/2.0, clockwise: true)
big.addArc(withCenter: CGPoint(x: rad * cos(.pi/2.0), y: center.y), radius: rad * sin(.pi/2.0), startAngle: .pi/2.0, endAngle: -.pi/2.0, clockwise: false)
big.close()
return big.cgPath
}
private func animateToOffShape() {
let anim = CABasicAnimation(keyPath: "path")
anim.toValue = drawMoonShape(bounds)
anim.duration = 5.0
shapeLayer.add(anim, forKey: nil)
}
}
我從這段代碼中得到了什么
更新
我能夠在@sweeper 和@max 的幫助下實現這一目標
但我想要它從中間右邊
任何指針我如何能達到預期的結果。 謝謝
正如 Max 所說,當兩條路徑具有相同數量的點時,貝塞爾路徑插值效果最佳。
這可能會讓你接近你的目標......
這個想法是將圓分成兩條弧 - 保持一條弧不變,並修改另一條弧:
為了計算弧線,我們從一個完整的圓和我們想要的新月開始:
要獲得新月點,我們可以取原始的完整圓並將其中心向上和向左移動(半徑的 1/3 給出了不錯的結果):
所以,我們想把圓分成兩條弧......
我們的第一個弧將從 301° 和 go 順時針到 149° 開始:
這意味着我們的第二個弧將從 149° 開始,go 順時針到 301°:
下一步是獲得“修改后的”第二個弧:
這里我們的第二個圓弧將從 121° 開始,go逆時針到 329°:
結果:
這是一些示例代碼,帶有硬編碼的角度。 我將由您自己進行數學運算,以獲得不同新月形狀的精確角度。 每次點擊都會在“太陽”和“月亮”形狀之間來回動畫:
// little degrees-to-radians helper
extension BinaryInteger {
var degreesToRadians: CGFloat { CGFloat(self) * .pi / 180 }
}
class MoonView: UIView {
private lazy var shapeLayer = CAShapeLayer()
override init(frame: CGRect) {
super.init(frame: frame)
commonInit()
}
required init?(coder: NSCoder) {
super.init(coder: coder)
commonInit()
}
private func commonInit() {
shapeLayer.fillColor = UIColor.cyan.cgColor
// to see outline only
//shapeLayer.fillColor = UIColor.clear.cgColor
shapeLayer.strokeColor = UIColor.red.cgColor
shapeLayer.lineWidth = 3
shapeLayer.lineJoin = .round
layer.addSublayer(shapeLayer)
}
private var isOn: Bool = true
override func layoutSubviews() {
super.layoutSubviews()
shapeLayer.frame = bounds
if isOn {
shapeLayer.path = drawSunShape(bounds)
} else {
shapeLayer.path = drawMoonShape(bounds)
}
}
private func drawSunShape(_ group:CGRect) -> CGPath {
let radius = group.maxX/2
let center = CGPoint(x: group.midX, y: group.midY)
let bezierPath = UIBezierPath()
bezierPath.addArc(withCenter: center, radius: radius, startAngle: 301.degreesToRadians, endAngle: 149.degreesToRadians, clockwise: true)
bezierPath.addArc(withCenter: center, radius: radius, startAngle: 149.degreesToRadians, endAngle: 301.degreesToRadians, clockwise: true)
bezierPath.close()
return bezierPath.cgPath
}
private func drawMoonShape(_ group:CGRect) -> CGPath {
let radius: CGFloat = group.maxX/2
let centerA = CGPoint(x: group.midX, y: group.midY)
let offset = radius * 1.0 / 3.0
let centerB = CGPoint(x: centerA.x - offset, y: centerA.y - offset)
let bezierPath = UIBezierPath()
bezierPath.addArc(withCenter: centerA, radius: radius, startAngle: 301.degreesToRadians, endAngle: 149.degreesToRadians, clockwise: true)
bezierPath.addArc(withCenter: centerB, radius: radius, startAngle: 121.degreesToRadians, endAngle: 329.degreesToRadians, clockwise: false)
bezierPath.close()
return bezierPath.cgPath
}
func animateShape() {
let anim = CABasicAnimation(keyPath: "path")
if isOn {
anim.toValue = drawMoonShape(bounds)
} else {
anim.toValue = drawSunShape(bounds)
}
anim.duration = 0.5
anim.fillMode = .forwards
anim.isRemovedOnCompletion = false
shapeLayer.add(anim, forKey: nil)
isOn.toggle()
}
}
class MoonViewController: UIViewController {
let mView = MoonView()
override func viewDidLoad() {
super.viewDidLoad()
view.backgroundColor = .yellow
view.addSubview(mView)
mView.translatesAutoresizingMaskIntoConstraints = false
view.addSubview(mView)
NSLayoutConstraint.activate([
mView.centerXAnchor.constraint(equalTo: view.centerXAnchor),
mView.centerYAnchor.constraint(equalTo: view.centerYAnchor),
mView.widthAnchor.constraint(equalToConstant: 200.0),
mView.heightAnchor.constraint(equalTo: mView.widthAnchor)
])
mView.backgroundColor = .white
let t = UITapGestureRecognizer(target: self, action: #selector(self.didTap(_:)))
view.addGestureRecognizer(t)
}
@objc func didTap(_ g: UITapGestureRecognizer) -> Void {
mView.animateShape()
}
}
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.