美文网首页
iOS 类似于水波的控件及变化 Swift版

iOS 类似于水波的控件及变化 Swift版

作者: 一根聪 | 来源:发表于2017-03-30 15:46 被阅读58次
    运行效果如下(带动画的,图片非gif):
    // MARK: 由中心向外围扩散的波纹控件
    class AKRippleView: UIView {
        
        @IBInspectable public var fillColor: UIColor = UIColor.orange {
            didSet {
                self.shapeLayer.fillColor = fillColor.cgColor
                self.animShapeLayer.fillColor = fillColor.withAlphaComponent(0.8).cgColor
            }
        }
        
        public var duration: TimeInterval = 6.0 {
            didSet {
                self.animationGroup.duration = duration
            }
        }
        
        public var instanceCount: Int = 3 {
            didSet {
                self.replicatorLayer.instanceCount = instanceCount
            }
        }
        
        public var instanceDelay: Double = 2.0 {
            didSet {
                self.replicatorLayer.instanceDelay = instanceDelay
            }
        }
        
        public var path: UIBezierPath? {
            didSet {
                self.shapeLayer.path = path?.cgPath
                self.animShapeLayer.path = path?.cgPath
            }
        }
        
        public var scaleFromValue = 0.8 {
            didSet {
                let scaleAnim: CABasicAnimation = self.animationGroup.animations![1] as! CABasicAnimation
                scaleAnim.fromValue = scaleFromValue
                self.shapeLayer.transform = CATransform3DMakeScale(CGFloat(scaleFromValue), CGFloat(scaleFromValue), 0)
            }
        }
        
        public var scaleToValue = 1.3 {
            didSet {
                let scaleAnim: CABasicAnimation = self.animationGroup.animations![1] as! CABasicAnimation
                scaleAnim.toValue = scaleToValue
            }
        }
        
        // 动画
        private let animationGroup: CAAnimationGroup = {
            let opacityAnim = CAKeyframeAnimation(keyPath: "opacity")
            opacityAnim.values = [0.0, 0.7, 0.5, 0.3, 0.0]
            opacityAnim.keyTimes = [0.0, 0.1, 0.25, 0.5, 1.0]
            
            let scaleAnim = CABasicAnimation(keyPath: "transform.scale")
            scaleAnim.fromValue = 0.8
            scaleAnim.toValue = 1.3
            
            let group = CAAnimationGroup()
            group.animations = [opacityAnim, scaleAnim]
            group.fillMode = kCAFillModeBoth
            group.beginTime = CACurrentMediaTime()
            group.duration = 6
            group.autoreverses = false
            group.repeatCount = MAXFLOAT
            group.timingFunction = CAMediaTimingFunction(name: kCAMediaTimingFunctionLinear)
            return group
        }()
        
        private let shapeLayer: CAShapeLayer = {
            let shape = CAShapeLayer()
            shape.fillColor = UIColor.orange.cgColor
            shape.transform = CATransform3DMakeScale(0.8, 0.8, 0.0)
            shape.allowsEdgeAntialiasing = true
            return shape
        }()
        
        private let animShapeLayer: CAShapeLayer = {
            let animShape = CAShapeLayer()
            animShape.fillColor = UIColor.orange.withAlphaComponent(0.8).cgColor
            animShape.allowsEdgeAntialiasing = true
            return animShape
        }()
        
        private let replicatorLayer: CAReplicatorLayer = {
            let replicator = CAReplicatorLayer()
            replicator.allowsEdgeAntialiasing = true
            replicator.instanceCount = 3
            replicator.instanceDelay = 2
            return replicator
        }()
        
        private var isAnimating = true
        
        convenience init() {
            self.init(frame: CGRect.zero)
        }
        
        override init(frame: CGRect) {
            super.init(frame: frame)
            
            let rect = CGRect(origin: CGPoint.zero, size: frame.size)
            
            shapeLayer.frame = rect
            self.layer.addSublayer(shapeLayer)
            
            animShapeLayer.frame = rect
            replicatorLayer.frame = rect
            replicatorLayer.addSublayer(animShapeLayer)
            self.layer.insertSublayer(replicatorLayer, at: 0)
            
            NotificationCenter.default.addObserver(self, selector: #selector(startAnimation), name: NSNotification.Name.UIApplicationDidBecomeActive, object: nil)
        }
        
        override func layoutSubviews() {
            super.layoutSubviews()
            
            let rect = CGRect(origin: CGPoint.zero, size: frame.size)
            if path == nil {
                path = UIBezierPath(ovalIn: rect)
            }
            shapeLayer.frame = rect
            animShapeLayer.frame = rect
            replicatorLayer.frame = rect
        }
        
        required init?(coder aDecoder: NSCoder) {
            super.init(coder: aDecoder)
        }
        
        deinit {
            animShapeLayer.removeAllAnimations()
        }
        
        private func resumeAnimation() {
            if isAnimating {
                startAnimation()
            }
        }
        
        public func startAnimation() {
            animShapeLayer.add(animationGroup, forKey: "anim")
            isAnimating = true
        }
        
        public func stopAnimation() {
            animShapeLayer.removeAllAnimations()
            isAnimating = false
        }
    }
    

    ** 使用方法 **

    // 默认是oval
    let rippleView = AKRippleView(frame: CGRect(x: 100, y: 100, width: 120, height: 120))
            rippleView.startAnimation()
            self.view.addSubview(rippleView)
            
            // 椭圆
            let rippleView1 = AKRippleView(frame: CGRect(x: 250, y: 100, width: 120, height: 80))
            rippleView1.path = UIBezierPath(ovalIn: CGRect(x: 0, y: 0, width: 120, height: 80))
            rippleView1.startAnimation()
            self.view.addSubview(rippleView1)
            
            
            // 弧线
            let rippleView2 = AKRippleView(frame: CGRect(x: 100, y: 300, width: 120, height: 120))
            rippleView2.path = UIBezierPath(arcCenter: CGPoint.zero, radius: 60, startAngle: CGFloat(Double.pi / 4.0), endAngle: CGFloat(Double.pi), clockwise: true)
            rippleView2.startAnimation()
            self.view.addSubview(rippleView2)
    
            // 带圆角的举行
            let rippleView3 = AKRippleView(frame: CGRect(x: 250, y: 300, width: 120, height: 100))
            rippleView3.path = UIBezierPath(roundedRect: CGRect(x: 0, y: 0, width: 120, height: 120), byRoundingCorners: UIRectCorner.allCorners, cornerRadii: CGSize(width: 30, height: 30))
            rippleView3.startAnimation()
            self.view.addSubview(rippleView3)
    

    更多用法可以自己参考UIBezierPath

    也可以结合SnpaKit使用

    let rippleView = AKRippleView(frame: CGRect(x: 100, y: 100, width: 120, height: 120))
    rippleView.startAnimation()
    self.view.addSubview(rippleView)
    rippleView.snp.makeConstraints() {
               $0.centerX.equalTo(self.view)
                $0.bottom.equalTo(self.view).offset(UIDevice.iphone_568_or_less ? -60 : -75)
                $0.size.equalTo(CGSize(width: UIDevice.iphone_568_or_less ? 100 : 110, height: UIDevice.iphone_568_or_less ? 100 : 110))
            }
    

    相关文章

      网友评论

          本文标题:iOS 类似于水波的控件及变化 Swift版

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