swift4.0

仿的一个水波纹view(swift)

2018-12-11  本文已影响40人  279cb620c509

仿的一个水波纹view(swift)

外框的形状path可以自己任意修改

image image
//  ZZWWaveView.swift
//  CoreAnimationDemo
//
//  Created by ma c on 2018/12/5.
//  Copyright © 2018年 jcgf. All rights reserved.
//

import UIKit

class ZZWWaveView: UIView {

    enum ZZWWaveViewType {
        case OvalType
        case SectorType
    }
               // 百分比      默认:0
    var percent : CGFloat = 0.0{
        didSet{
            
            currentWavePointY = self.frame.height * self.percent
            if (percent>0 && percent<1) {
                kExtraHeight = 10
            }
            
            initial()
        }
    }
    
    var colors : [CGColor] = [hexColor(hex: "ff9548").cgColor,hexColor(hex: "f76ae0").cgColor]
    var sColors : [CGColor] = [hexColor(hex: "ffa548").cgColor,hexColor(hex: "f78ae0").cgColor]
    
    var waveAmplitude : CGFloat = 0.0     // 波纹振幅     默认:0
    var waveCycle : CGFloat = 0.0// 波纹周期     默认:1.29 * M_PI /
    var waveSpeed : CGFloat = 0.2/CGFloat.pi// 波纹速度     默认:0.2/M_PI
    var waveGrowth : CGFloat = 1.00// 波纹上升速度  默认:1.00
 
    var waveDisplaylink : CADisplayLink?
    var firstWaveLayer : CAShapeLayer?//里层
    var secondWaveLayer : CAShapeLayer?//外层
    var gradientLayer : CAGradientLayer?// 绘制渐变1
    var sGradientLayer : CAGradientLayer?// 绘制渐变2
    var textLayer : CATextLayer?
   
    var waterWaveWidth : CGFloat = 160.0// 宽度
    var offsetX : CGFloat = 0.0// 波浪x位移
    var currentWavePointY : CGFloat = 0.0// 当前波浪上升高度Y
    var kExtraHeight : CGFloat = 0.0     // 保证水波波峰不被裁剪,增加部分额外的高度
    var variable : CGFloat = 0.2/CGFloat.pi// 可变参数 更加真实 模拟波纹
    var increase : Bool = false// 增减变化
    
    var waveViewType :ZZWWaveViewType = .OvalType
    
    override init(frame: CGRect) {
        super.init(frame: frame)
        self.backgroundColor = .clear
        self.layer.masksToBounds = true
       
        
    }
    
    func initial()   {
 
        waterWaveWidth  = self.frame.width
        if (waterWaveWidth > 0) {
            self.waveCycle =  1.29 * CGFloat.pi / waterWaveWidth
        }
 
        resetProperty()
    }
    
    func resetProperty() {
        currentWavePointY =  self.frame.height * self.percent
        
        offsetX = 0
        variable = 1.6
        increase = false
        
        kExtraHeight = 0
        if (percent>0 && percent<1) {
            kExtraHeight = 10
        }
 
    }
    
    func startWave()  {

        if (firstWaveLayer == nil) {
            // 创建第一个波浪Layer
            firstWaveLayer = CAShapeLayer.init()
            
        }
        
        if (secondWaveLayer == nil) {
            // 创建第二个波浪Layer
            secondWaveLayer = CAShapeLayer.init()
        }
 
        // 添加渐变layer``````
        if ((self.gradientLayer) != nil) {
            self.gradientLayer?.removeFromSuperlayer()
            self.gradientLayer = nil
        }
        self.gradientLayer = CAGradientLayer.init()
        self.gradientLayer?.frame = gradientLayerFrame()
        self.gradientLayer?.mask = firstWaveLayer
        self.layer.addSublayer(self.gradientLayer!)
        
        if (self.sGradientLayer) != nil {
            self.sGradientLayer?.removeFromSuperlayer()
            self.sGradientLayer = nil
        }
        self.sGradientLayer = CAGradientLayer.init()
        self.sGradientLayer?.frame = gradientLayerFrame()
        self.sGradientLayer?.mask = secondWaveLayer
        self.layer.addSublayer(self.sGradientLayer!)
        
        //设置渐变layer相关属性
        setupGradientColor()
        
        if ((self.textLayer) != nil) {
            self.textLayer?.removeFromSuperlayer()
            self.textLayer = nil
        }
        textLayer = CATextLayer.init()
        textLayer?.frame = CGRectMake((self.width - 18.0)/2.0, (self.height - 35.0)/2.0, 18.0, 35.0)
        textLayer?.contentsScale = kViewScake
        textLayer?.fontSize = 16.0
        textLayer?.foregroundColor = color_141414.cgColor
        textLayer?.alignmentMode = kCAAlignmentCenter
        self.layer.addSublayer(textLayer!)
        
        if ((waveDisplaylink) != nil) {
            stopWave()
        }
        
        // 启动定时调用
        waveDisplaylink = CADisplayLink.init(target: self, selector: #selector(getCurrentWave(displayLink:)))
        waveDisplaylink?.add(to: RunLoop.main, forMode: RunLoopMode.commonModes)
      
    }
    
    func gradientLayerFrame() -> CGRect{
      
    // gradientLayer在上升完成之后的frame值,如果gradientLayer在上升过程中不断变化frame值会导致一开始绘制卡顿,所以只进行一次赋值
    
        var gradientLayerHeight : CGFloat = self.frame.height * self.percent + kExtraHeight
        
        if (gradientLayerHeight > self.frame.height)
        {
            gradientLayerHeight = self.frame.height
        }
        
        let frame = CGRectMake(0, self.frame.height - gradientLayerHeight, self.frame.width, gradientLayerHeight)
        return frame
    }
    
    func setupGradientColor() {
     
    // gradientLayer设置渐变色
        if ((self.colors.count) < 1){
            self.colors = defaultColors()
        }
        if ((self.sColors.count) < 1){
            self.sColors = defaultColors()
        }

        self.gradientLayer?.colors = self.colors
        self.sGradientLayer?.colors = self.sColors

        //设定颜色分割点
        let count  = self.colors.count
        let d : CGFloat = 1.0 / CGFloat(count)

        let locations = NSMutableArray.init(capacity: 0)
        for i in 0..<count {

            let num = NSNumber.init(value: Float(d + d * CGFloat(i)))
            locations.add(num)

        }
        let lastNum = NSNumber.init(value: Float(1.0))
        locations.add(lastNum)

        self.gradientLayer?.locations = locations as! [NSNumber]
        self.sGradientLayer?.locations = locations as! [NSNumber]

        // 设置渐变方向,从上往下
        self.gradientLayer?.startPoint = CGPointMake(0, 0)
        self.gradientLayer?.endPoint = CGPointMake(0, 1)

        self.sGradientLayer?.startPoint = CGPointMake(0, 0)
        self.sGradientLayer?.endPoint = CGPointMake(0, 1)
 
    }
    
    func defaultColors() -> [CGColor] {
    
        // 默认的渐变色
        let color0 = UIColor.init(red: 166.0 / 255.0, green: 240.0 / 255.0, blue: 255.0 / 255.0, alpha: 1.0)
        let color1 = UIColor.init(red: 240.0 / 255.0, green: 250.0 / 255.0, blue: 255.0 / 255.0, alpha: 1.0)
        
        let colors = [color0.cgColor,color1.cgColor]
        return colors
    }
    
    @objc func getCurrentWave(displayLink:CADisplayLink)  {
    
        animateWave()

        if (!waveFinished()) {
            currentWavePointY -= self.waveGrowth
        }

    // 波浪位移
        offsetX += self.waveSpeed
        
        textLayer?.string = String(format: "%d", Int(self.frame.height * self.percent - currentWavePointY)) + "\n%"

        setCurrentFirstWaveLayerPath()

        setCurrentSecondWaveLayerPath()
    }
    
    func setCurrentFirstWaveLayerPath()  {
  
        UIGraphicsBeginImageContext(CGSize(width: bounds.width, height: bounds.width))
        let path = UIBezierPath()
        var y : CGFloat = currentWavePointY
  
        path.move(to: CGPoint(x: 0, y: currentWavePointY + self.waveAmplitude))
        for x in 0..<Int(waterWaveWidth) {

        // 正弦波浪公式
            y = currentWavePointY + self.waveAmplitude * (sin(self.waveCycle * CGFloat(x) + offsetX) + 1.0)
            path.addLine(to: CGPoint(x: CGFloat(x), y: y))

        }
        path.addLine(to: CGPoint(x: waterWaveWidth, y: self.frame.height))
        path.addLine(to: CGPoint(x: 0, y: self.frame.height))
        path.close()

        firstWaveLayer?.path = path.cgPath
        self.gradientLayer?.mask = firstWaveLayer
        UIGraphicsEndImageContext()
    }
    
    func setCurrentSecondWaveLayerPath() {
        UIGraphicsBeginImageContext(CGSize(width: bounds.width, height: bounds.height))
        let path = UIBezierPath()
        var y : CGFloat = currentWavePointY
        path.move(to: CGPoint(x: 0, y: currentWavePointY + self.waveAmplitude))
        for x in 0..<Int(waterWaveWidth) {
            
            // 正弦波浪公式
            y = currentWavePointY +  self.waveAmplitude * (cos(self.waveCycle * CGFloat(x) + offsetX) + 1.0)
            path.addLine(to: CGPoint(x: CGFloat(x), y: y))
            
        }
        path.addLine(to: CGPoint(x: waterWaveWidth, y: self.frame.height))
        path.addLine(to: CGPoint(x: 0, y: self.frame.height))
        path.close()
        
        secondWaveLayer?.path = path.cgPath
        self.sGradientLayer?.mask = secondWaveLayer
        UIGraphicsEndImageContext()
    }
    
    func animateWave()  {
        if (increase) {
            variable += 0.01
        }else{
            variable -= 0.01
        }
        if (variable<=1) {
            increase = true
        }
        if (variable>=1.6) {
            increase = false
        }
        // 可变振幅
        self.waveAmplitude = variable*3
    }
    
    func waveFinished() -> Bool{
    // 波浪上升动画是否完成
        let d : CGFloat = self.frame.height - self.gradientLayer!.frame.height
        let extraH : CGFloat = min(d, kExtraHeight)
        let bFinished : Bool = currentWavePointY <= 0.0
        return bFinished
    }
    
    func stopWave()  {
        waveDisplaylink?.invalidate()
        waveDisplaylink = nil;
    }
    
    func goOnWave()  {
        if ((waveDisplaylink) != nil) {
            stopWave()
        }
        // 启动定时调用
        waveDisplaylink = CADisplayLink.init(target: self, selector: #selector(getCurrentWave(displayLink:)))
        waveDisplaylink?.add(to: RunLoop.main, forMode: RunLoopMode.commonModes)
    }
    
    func reset()  {
        stopWave()
        resetProperty()
        
        firstWaveLayer?.removeFromSuperlayer()
        firstWaveLayer = nil;
        secondWaveLayer?.removeFromSuperlayer()
        secondWaveLayer = nil
        
        gradientLayer?.removeFromSuperlayer()
        gradientLayer = nil
        sGradientLayer?.removeFromSuperlayer()
        sGradientLayer = nil
    }
    
    required init?(coder aDecoder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }
    
    override func draw(_ rect: CGRect) {
        super.draw(rect)
        switch waveViewType {
        case .OvalType:
            let path = UIBezierPath.init(ovalIn: CGRect(x: 0, y: 1.0, width: self.width, height: self.height - 1.0*2.0))
            hexColor(hex: "979797").setStroke()
            path.lineWidth = 1.0
            path.stroke()
            let layerTest = CAShapeLayer.init()
            layerTest.path = path.cgPath
            self.layer.mask = layerTest

        case .SectorType:
            let path = UIBezierPath.init()
            path.move(to: CGPoint(x: self.width/2.0, y: 0))
            path.addArc(withCenter: CGPoint(x: self.width/2.0, y: self.height - self.width/2.0), radius: self.width/2.0, startAngle: -1.0/6.0*CGFloat.pi, endAngle: -5.0/6.0*CGFloat.pi, clockwise: true)

            path.close()
            hexColor(hex: "979797").setStroke()
            path.lineWidth = 1.0
            path.stroke()
            
            let layerTest = CAShapeLayer.init()
            layerTest.path = path.cgPath
            self.layer.mask = layerTest
        }
    }
    
   
    
}

使用:

override func viewDidLoad() {
        super.viewDidLoad()
        self.view.backgroundColor = color_ffffff

        ZZWWaveViewFunc()
    }
func ZZWWaveViewFunc()  {
        let colors = [hexColor(hex: "86d0f8", alpha: 0.75).cgColor,hexColor(hex: "ffffff").cgColor]
        let sColors = [hexColor(hex: "a6f0ff", alpha: 0.5).cgColor,hexColor(hex: "f0faff", alpha: 0.5).cgColor]
       
        let waveView = ZZWWaveView.init(frame: CGRectMake(100.0, 100.0, 65.0, 99.0))
        self.view.addSubview(waveView)
        waveView.waveViewType = .OvalType
        waveView.colors = colors
        waveView.sColors = sColors
        waveView.percent = 0.3
        waveView.startWave()
        
    }
上一篇下一篇

猜你喜欢

热点阅读