如何制作类似于ig story的划线动画?我尝试制作动态划线,但失败了;
( CABasicAnimation *rotateAnimation = [CABasicAnimation animationWithKeyPath:@"transform.rotation"];
rotateAnimation.fromValue = @0;
rotateAnimation.toValue = @(M_PI_2*3);
CABasicAnimation * strokeStartAnimation = [CABasicAnimation animationWithKeyPath:@"strokeStart"];
strokeStartAnimation.fromValue = @(0);
strokeStartAnimation.toValue = @0.6;
CAAnimationGroup *animationGroup = [CAAnimationGroup animation];
animationGroup.animations = @[rotateAnimation,strokeStartAnimation];
animationGroup.duration = 1.5;
animationGroup.fillMode = kCAFillModeForwards;
animationGroup.removedOnCompletion = NO;
animationGroup.delegate = self;
animationGroup.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut];
[self.circlarShapeLayer addAnimation:animationGroup forKey:@"animationGroup"];
答案 0 :(得分:1)
我可能会研究CAReplicatorLayer。您可以使用它来做一些有趣的事情。我快速进入了Playgrounds。您可以按时间和实例延迟进行播放,以查看是否可以按自己的喜好进行操作。我也没有对实例颜色的变化考虑很多。您还可以将渐变图像设置为图层,并使用CAShapeLayer对其进行遮罩并将其添加到复制器。唯一的其他方法是手动添加图层,您可以使用下面的代码中CAReplicatorLayer使用的相同代码来进行添加,然后您将拥有更多控制权。您将只有一个for循环,并继续围绕图层旋转或使用笔划的不同部分旋转图层。然后保留并排列它们,并在需要时进行动画处理。
import Foundation
import UIKit
import PlaygroundSupport
class InstagramProfileSpinner : UIView{
var circlePiece : CAShapeLayer = CAShapeLayer()
var replicator : CAReplicatorLayer = CAReplicatorLayer()
lazy var imageView : UIImageView = {
let img = UIImageView(frame: self.bounds)
img.layer.cornerRadius = self.bounds.width/2
img.layer.masksToBounds = true
img.contentMode = .scaleAspectFill
return img
}()
var avatarURL : URL?{
didSet{
configureAvatar()
}
}
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
setUpShapeLayer()
self.addSubview(imageView)
}
override init(frame: CGRect) {
super.init(frame: frame)
setUpShapeLayer()
self.addSubview(imageView)
}
func setUpShapeLayer(){
if let sublayers = self.layer.sublayers,sublayers.contains(replicator){} else{
circlePiece = CAShapeLayer()
circlePiece.frame = self.bounds
circlePiece.path = self.pathForCircle()
circlePiece.strokeColor = UIColor(red: 254/255, green: 136/255, blue: 7/255, alpha: 1).cgColor
circlePiece.lineWidth = 2.5
circlePiece.lineJoin = .round
circlePiece.lineCap = .round
circlePiece.fillColor = UIColor.clear.cgColor
circlePiece.strokeEnd = 0.025
let count = 1/circlePiece.strokeEnd
//set up replicator
replicator.instanceCount = Int(count)
let angle = (2.0*Double.pi)/Double(count)
replicator.instanceTransform = CATransform3DMakeRotation(CGFloat(angle), 0.0, 0.0, 1.0)
replicator.instanceRedOffset = -0.002
replicator.instanceGreenOffset = -0.04
replicator.instanceBlueOffset = -0.02
replicator.addSublayer(circlePiece)
self.layer.addSublayer(replicator)
}
}
func pathForCircle()->CGPath{
let path = UIBezierPath(ovalIn: self.bounds.insetBy(dx: 5, dy: 5))
return path.cgPath
}
func animateSpinner(){
let basic = CABasicAnimation(keyPath: "strokeEnd")
basic.fromValue = circlePiece.strokeEnd
basic.toValue = circlePiece.strokeEnd/5
basic.duration = 1
basic.autoreverses = true
basic.repeatCount = .infinity
replicator.instanceDelay = 0.25
circlePiece.add(basic, forKey: "littleStrokes")
}
func removeAnimation(){
if let animation = circlePiece.presentation(),
let stroke = animation.value(forKeyPath: "strokeEnd") as? CGFloat{
let final = CABasicAnimation(keyPath: "strokeEnd")
final.toValue = circlePiece.strokeEnd
final.duration = 1
replicator.instanceDelay = 0
circlePiece.add(final, forKey: "littleStrokes")
}
}
func configureAvatar(){
guard let url = self.avatarURL else{return}
self.imageView.image = nil
URLSession.shared.dataTask(with: url) { (data, response, error) in
if let dt = data{
DispatchQueue.main.async {
self.imageView.image = UIImage(data: dt)
}
}
}.resume()
}
override func layoutSubviews() {
super.layoutSubviews()
replicator.frame = self.bounds
let inset = self.bounds.width * 0.08
imageView.frame = self.bounds.insetBy(dx: inset, dy:inset)
imageView.layer.cornerRadius = imageView.frame.width/2
}
}
class ViewController:UIViewController{
var check = true
var circle = InstagramProfileSpinner(frame: CGRect(x: 30, y: 30, width: 100, height: 100))
override func viewDidLoad() {
super.viewDidLoad()
view.backgroundColor = .white
view.addSubview(circle)
let url = URL(string: "https://images.pexels.com/photos/450271/pexels-photo-450271.jpeg?auto=compress&cs=tinysrgb&h=750&w=1260")
circle.avatarURL = url
circle.animateSpinner()
DispatchQueue.main.asyncAfter(deadline: DispatchTime.now() + 10) {
self.circle.removeAnimation()
}
}
}
let viewController = ViewController()
PlaygroundPage.current.liveView = viewController
PlaygroundPage.current.needsIndefiniteExecution