美文网首页
iOS 利用加速计实现多个波浪线

iOS 利用加速计实现多个波浪线

作者: 达摩君 | 来源:发表于2018-08-31 10:55 被阅读196次

    需求

    要求根据手机摇晃程度(加速计),来实现多个波浪线动画,要求两端低,中间高。
    实现效果:


    1.gif

    工作原理

    正弦曲线公式:y=Asin(ωx+φ)+k
    A :振幅,曲线最高位和最低位的距离
    ω :角速度,用于控制周期大小,单位x中起伏的个数
    K :偏距,曲线上下偏移量
    φ :初相,曲线左右偏移量
    曲线图如下:


    曲线图.png

    现在有一根正弦曲线出来了,要产生动画只要实时改变φ,就会有左右滚动的效果,多个曲线就是原始φ不同,多个曲线峰值高低则改变A ,波浪线要中间高两边低其实也简单,只要再乘以半个周期的标准正弦曲线。


    image.png

    看了图片相信恍然大悟了吧

    代码实现

    import UIKit
    import CoreMotion
    
    class SportWaveLineView: UIView {
    
        var lastAccelera: Double = 0.0
        let path1 = UIBezierPath()
        let path2 = UIBezierPath()
        let path3 = UIBezierPath()
        let path4 = UIBezierPath()
        let layer1 = CAShapeLayer()
        let layer2 = CAShapeLayer()
        let layer3 = CAShapeLayer()
        let layer4 = CAShapeLayer()
        var offset: Double = 0.0
        
        lazy var noMotionlabel: UILabel = {
           
            let noMotionlabel = UILabel(frame: .zero)
            noMotionlabel.text = """
            鹰和鹰将利用手机传感器来记录你的跑步
            请确认手机可以感受到迈步或者摆臂,以减少误差
            """
            noMotionlabel.numberOfLines = 2
            noMotionlabel.textAlignment = NSTextAlignment.center
            noMotionlabel.font = UIFont.systemFont(ofSize: 12)
            noMotionlabel.textColor = UIColor(white: 1.0, alpha: 0.3)
            noMotionlabel.backgroundColor = UIColor(hexString: "#393E4C")
            addSubview(noMotionlabel)
            noMotionlabel.snp.makeConstraints({ (make) in
                make.center.equalToSuperview()
                make.left.equalToSuperview().offset(30)
                make.right.equalToSuperview().offset(-30)
            })
            return noMotionlabel
        }()
        
        override init(frame: CGRect) {
            super.init(frame: frame)
            
            layer1.strokeColor = UIColor(white: 1.0, alpha: 0.3).cgColor
            layer1.fillColor = UIColor.clear.cgColor
            layer1.lineWidth = 0.5
            layer.addSublayer(layer1)
            
            layer2.strokeColor = UIColor(white: 1.0, alpha: 0.3).cgColor
            layer2.fillColor = UIColor.clear.cgColor
            layer2.lineWidth = 0.5
            layer.addSublayer(layer2)
            
            layer3.strokeColor = UIColor(white: 1.0, alpha: 0.3).cgColor
            layer3.fillColor = UIColor.clear.cgColor
            layer3.lineWidth = 0.5
            layer.addSublayer(layer3)
            
            layer4.strokeColor = UIColor(white: 1.0, alpha: 0.3).cgColor
            layer4.fillColor = UIColor.clear.cgColor
            layer4.lineWidth = 0.5
            layer.addSublayer(layer4)
            
            //判断加速计是否可用,不能就一根直线
            if !SportTrackingManager.shareInstance.accelerometerManager.isAccelerometerAvailable {
                path1.move(to: CGPoint(x: 0, y: self.bounds.height / 2))
                path1.addLine(to: CGPoint(x: bounds.width, y: bounds.height / 2))
                layer1.path = path1.cgPath
                return
            }
            SportTrackingManager.shareInstance.accelerometerManager.accelerometerUpdateInterval = 1 / 15
            SportTrackingManager.shareInstance.accelerometerManager.startAccelerometerUpdates(to: OperationQueue.main) { (accelerometerData, error) in
                let acceleration = accelerometerData?.acceleration
                //            print(acceleration?.x, acceleration?.y, acceleration?.z)
                let accelera = sqrt(pow(acceleration!.x, 2) + pow(acceleration!.y, 2) + pow(acceleration!.z, 2))
                if accelera < 1.05 && accelera > 0.9 {
                    return
                }
                if accelera > self.lastAccelera {
                    self.lastAccelera = accelera
                    self.lastAccelera *= 1.4
                }
                if accelera <= 0.9 {
                    let lowTemp = 0.9 - accelera
                    let highTemp = self.lastAccelera - 1.05
                    if lowTemp > highTemp {
                        self.lastAccelera = 1.05 + lowTemp
                        self.lastAccelera *= 1.4
                    }
                }
                if self.lastAccelera > 6 {
                    self.lastAccelera = 6
                }
            }
            //根据手机刷新频率刷新曲线
            let display = CADisplayLink(target: self, selector: #selector(drawWaveLine))
            display.add(to: RunLoop.current, forMode: .commonModes)
        }
        
        required init?(coder aDecoder: NSCoder) {
            fatalError("init(coder:) has not been implemented")
        }
        @objc func drawWaveLine() {
            
            path1.removeAllPoints()
            path2.removeAllPoints()
            path3.removeAllPoints()
            path4.removeAllPoints()
            path1.move(to: CGPoint(x: 0, y: self.bounds.height / 2))
            
            path2.move(to: CGPoint(x: 0, y: self.bounds.height / 2))
            path2.addLine(to: CGPoint(x: 5, y: self.bounds.height / 2))
            
            path3.move(to: CGPoint(x: 0, y: self.bounds.height / 2))
            path3.addLine(to: CGPoint(x: 10, y: self.bounds.height / 2))
            path4.move(to: CGPoint(x: 0, y: self.bounds.height / 2))
            path4.addLine(to: CGPoint(x: 15, y: self.bounds.height / 2))
            for x in 0...Int(bounds.width) {
                
                let y =  9 * self.lastAccelera * sin(Double.pi / Double(UIScreen.main.bounds.width / 6) * Double(x) + offset) * (sin(Double(x) * Double.pi / Double(UIScreen.main.bounds.width)))
                path1.addLine(to: CGPoint(x: Double(x), y: y + Double(bounds.height / 2)))
                
                if CGFloat(x) < bounds.width - 5 {
                    
                    let y1 =  8 * self.lastAccelera * sin(Double.pi / Double(UIScreen.main.bounds.width / 6) * Double(x) + offset - 0.2) * (sin(Double(x) * Double.pi / Double(UIScreen.main.bounds.width - 5)))
                    path2.addLine(to: CGPoint(x: Double(x) + 5, y: y1 + Double(bounds.height / 2)))
                }
                
                if CGFloat(x) < bounds.width - 10 {
                    
                    let y2 =  7 * self.lastAccelera * sin(Double.pi / Double(UIScreen.main.bounds.width / 6) * Double(x) + offset - 0.4) * (sin(Double(x) * Double.pi / Double(UIScreen.main.bounds.width - 10)))
                    path3.addLine(to: CGPoint(x: Double(x) + 10, y: y2 + Double(bounds.height / 2)))
                }
                
                if CGFloat(x) < bounds.width - 15 {
                    
                    let y3 =  6 * self.lastAccelera * sin(Double.pi / Double(UIScreen.main.bounds.width / 6) * Double(x) + offset - 0.6) * (sin(Double(x) * Double.pi / Double(UIScreen.main.bounds.width - 15)))
                    path4.addLine(to: CGPoint(x: Double(x) + 15, y: y3 + Double(bounds.height / 2)))
                    
                }
            }
            
            path1.addLine(to: CGPoint(x: bounds.width, y: bounds.height / 2))
            path2.addLine(to: CGPoint(x: bounds.width, y: bounds.height / 2))
            path3.addLine(to: CGPoint(x: bounds.width, y: bounds.height / 2))
            path4.addLine(to: CGPoint(x: bounds.width, y: bounds.height / 2))
            
            
            layer1.path = path1.cgPath
            layer2.path = path2.cgPath
            layer3.path = path3.cgPath
            layer4.path = path4.cgPath
            
            //没有加速就显示文案,波浪线归0
            if self.lastAccelera <= 0.1 {
                self.lastAccelera = 0.0
                self.noMotionlabel.isHidden = false
            } else {
                self.noMotionlabel.isHidden = true
                self.lastAccelera -= 0.08
            }
            //波浪线移动
            offset -= 0.18
            if offset < -60 * Double.pi {
                offset = 0
            }
            
        }
    
    }
    
    

    相关文章

      网友评论

          本文标题:iOS 利用加速计实现多个波浪线

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