如何在ios中制作类似于ig故事加载样式的动画?

时间:2018-12-13 02:29:55

标签: ios animation

如何制作类似于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"];

1 个答案:

答案 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