美文网首页iOS DeveloperiosiOS精品文章
iOS 动画十三:Stroke and Path Animati

iOS 动画十三:Stroke and Path Animati

作者: _浅墨_ | 来源:发表于2018-07-25 22:58 被阅读187次

    这里我们实现一个 stroke and path animations 下拉刷新动画。最后效果如下:

    pull-to-refresh animation
    1. 创建虚线圆
    ovalShapeLayer.strokeColor = UIColor.white.cgColor
        ovalShapeLayer.fillColor = UIColor.clear.cgColor
        ovalShapeLayer.lineWidth = 4.0
        // 虚线组成为2单位实线3单位虚线
        ovalShapeLayer.lineDashPattern = [2, 3] // alternates between a 2-user-space-unit-long painted segment and a 3-user-space-unit-long unpainted segment
        
        let refreshRadius = frame.size.height/2 * 0.8
        
        ovalShapeLayer.path = UIBezierPath(ovalIn: CGRect(
            x: frame.size.width/2 - refreshRadius,
            y: frame.size.height/2 - refreshRadius,
            width: 2 * refreshRadius,
            height: 2 * refreshRadius)).cgPath
        
        layer.addSublayer(ovalShapeLayer)
        
        let airplaneImage = UIImage(named: "airplane.png")!
        airplaneLayer.contents = airplaneImage.cgImage
        airplaneLayer.bounds = CGRect(x: 0.0, y: 0.0,width: airplaneImage.size.width, height: airplaneImage.size.height)
        
        airplaneLayer.position = CGPoint(
            x: frame.size.width/2 + frame.size.height/2 * 0.8, y: frame.size.height/2)
        layer.addSublayer(airplaneLayer)
        
        airplaneLayer.opacity = 0.0
    
    2. 实现 Path Animations
    func beginRefreshing() {
        isRefreshing = true
        
        UIView.animate(withDuration: 0.3) {
          var newInsets = self.scrollView.contentInset
          newInsets.top += self.frame.size.height
          self.scrollView.contentInset = newInsets
        }
        
        let strokeStartAnimation = CABasicAnimation(keyPath: "strokeStart")
        strokeStartAnimation.fromValue = -0.5
        strokeStartAnimation.toValue = 1.0
        
        let strokeEndAnimation = CABasicAnimation(keyPath: "strokeEnd")
        strokeEndAnimation.fromValue = 0.0
        strokeEndAnimation.toValue = 1.0
        
        let strokeAnimationGroup = CAAnimationGroup()
        strokeAnimationGroup.duration = 1.5
        strokeAnimationGroup.repeatDuration = 5.0
        strokeAnimationGroup.animations = [strokeStartAnimation, strokeEndAnimation]
        ovalShapeLayer.add(strokeAnimationGroup, forKey: nil)
        
        let flightAnimation = CAKeyframeAnimation(keyPath: "position")
        flightAnimation.path = ovalShapeLayer.path
        flightAnimation.calculationMode = kCAAnimationPaced
        
        let airplaneOrientationAnimation = CABasicAnimation(keyPath: "transform.rotation")
        airplaneOrientationAnimation.fromValue = 0
        airplaneOrientationAnimation.toValue = 2.0 * .pi
        
        let flightAnimationGroup = CAAnimationGroup()
        flightAnimationGroup.duration = 1.5
        flightAnimationGroup.repeatDuration = 5.0
        flightAnimationGroup.animations = [flightAnimation,airplaneOrientationAnimation]
        airplaneLayer.add(flightAnimationGroup, forKey: nil)
      }
    
    func endRefreshing() {
        
        isRefreshing = false
        
        UIView.animate(withDuration: 0.3, delay:0.0, options: .curveEaseOut,
          animations: {
            var newInsets = self.scrollView.contentInset
            newInsets.top -= self.frame.size.height
            self.scrollView.contentInset = newInsets
          },
          completion: {_ in
            //finished
          }
        )
      }
      
      func redrawFromProgress(_ progress: CGFloat) {
         ovalShapeLayer.strokeEnd = progress
         airplaneLayer.opacity = Float(progress)
      }
    
    
    
    3. strokeStart和strokeEnd 注释

    可以把strokeStart理解成一个橡皮擦,如果我们让strokeStart从0到1的话 那么这个线就会被从(0,0)一直檫除到(100,0)

    可以把strokeEnd理解为一个画笔,strokeEnd从0 动画到 1 那么动画表现为线越来越长。

    eg. 对勾动画

    先把路径用贝赛尔曲线画出来,然后用strokeEnd做动画:

    #pragma mark -- 成功的路径
    -(CGPathRef)getSuccessPath{
        
        // 圆
        UIBezierPath *ciclePath = [UIBezierPath bezierPathWithArcCenter:CGPointMake(self.frame.size.width/2,self.frame.size.height/2) radius:0.8*self.currentSize.width/2 startAngle:M_PI * 3 / 2 endAngle:M_PI * 7 / 2 clockwise:YES];
        // 对勾
        CGFloat W = self.frame.size.width *0.9;
        CGFloat H = self.frame.size.height*0.9;
        UIBezierPath *subPath  = [UIBezierPath bezierPath];
        [subPath moveToPoint:CGPointMake(W/4,H/2)];
        [subPath addLineToPoint:CGPointMake(W/2,(H/2)+ H/4)];
        [subPath addLineToPoint:CGPointMake(W-(W/8),H/4)];
        
        // 添加到路径上 由于CAShapeLayer只能添加一条路径  幸好贝赛尔曲线有个appendPath: 方法 可以让我们画多条路径
        [ciclePath appendPath:subPath];
        return ciclePath.CGPath;
    }
    
    #pragma mark -- 成功的动画
    - (CABasicAnimation*)successAnimtion{
        
        // 第一个满圆旋转
        CABasicAnimation *aniamtion1 = [CABasicAnimation animation];
        aniamtion1.keyPath = @"strokeEnd";
        aniamtion1.fromValue = @0;
        aniamtion1.toValue = @1;
        aniamtion1.duration = 1.5;
        
        // 这个是缓冲函数
        // 可以自定义
        //
    //    aniamtion1.timingFunction = [CAMediaTimingFunction functionWithControlPoints:1 :1 :1 :1];
        
        aniamtion1.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut];
        aniamtion1.fillMode = kCAFillModeBackwards;
        return aniamtion1;
       }
    
    

    demo下载

    参考:

    1. strokeStart和strokeEnd

    感谢 @谢微一直都得踢足球

    相关文章

      网友评论

        本文标题:iOS 动画十三:Stroke and Path Animati

        本文链接:https://www.haomeiwen.com/subject/zcapmftx.html