// // AV_WaveView.swift // anniversary_Project // // Created by 忆海16 on 2024/7/8. // import UIKit class AV_WaveView: UIView { private var waveLayers: [CAShapeLayer] = [] private var waveHeight: CGFloat = 10.0 private var waveLength: CGFloat = 200.0 private var waveSpeed: CGFloat = 0.05 private var waveOffset: CGFloat = 0.0 private var wavePositionY: CGFloat = 0.0 private var totalCapacity: CGFloat = 0.0 private var currentVolume: CGFloat = 0.0 private var timer: Timer? override init(frame: CGRect) { super.init(frame: frame) setupWaveLayers() setupMaskLayer() startWaveAnimation() } required init?(coder: NSCoder) { super.init(coder: coder) setupWaveLayers() setupMaskLayer() startWaveAnimation() } private func setupWaveLayers() { let colors = [UIColor.hexSting(color: "#96D3FF", alpha: 1).cgColor, UIColor.hexSting(color: "#62BFFF", alpha: 1).cgColor] for color in colors { let waveLayer = CAShapeLayer() waveLayer.fillColor = color layer.addSublayer(waveLayer) waveLayers.append(waveLayer) } } private func setupMaskLayer() { let maskLayer = CAShapeLayer() let path = UIBezierPath(rect: bounds) maskLayer.path = path.cgPath layer.mask = maskLayer } private func startWaveAnimation() { timer = Timer.scheduledTimer(timeInterval: 1.0 / 30.0, target: self, selector: #selector(updateWave), userInfo: nil, repeats: true) } @objc private func updateWave() { waveOffset += waveSpeed for (index, waveLayer) in waveLayers.enumerated() { let amplitude = waveHeight * (1.2 - 0.2 * CGFloat(index)) let path = createWavePath(offset: waveOffset + CGFloat(index) * 0.3, amplitude: amplitude) waveLayer.path = path.cgPath } } private func createWavePath(offset: CGFloat, amplitude: CGFloat) -> UIBezierPath { let path = UIBezierPath() let width = bounds.width let height = bounds.height let midY = height * wavePositionY path.move(to: CGPoint(x: 0, y: midY)) for x in stride(from: 0.0, to: Double(width), by: 1.0) { let relativeX = CGFloat(x) / waveLength * .pi * 2 let y = sin(relativeX + offset) * amplitude + midY path.addLine(to: CGPoint(x: CGFloat(x), y: y)) } path.addLine(to: CGPoint(x: width, y: height)) path.addLine(to: CGPoint(x: 0, y: height)) path.close() return path } func setTotalCapacity(_ capacity: CGFloat) { totalCapacity = capacity currentVolume = 0 wavePositionY = 1.0 updateWavePosition(animated: false) } func drinkWater(_ volume: CGFloat) { currentVolume += volume if currentVolume > totalCapacity { currentVolume = totalCapacity } let newPositionY = 1.0 - (currentVolume / totalCapacity) updateWavePosition(animated: true, targetPositionY: newPositionY) } func setCurrentVolume(_ volume: CGFloat) { currentVolume = volume if currentVolume > totalCapacity { currentVolume = totalCapacity } else if currentVolume < 0 { currentVolume = 0 } let newPositionY = 1.0 - (currentVolume / totalCapacity) updateWavePosition(animated: true, targetPositionY: newPositionY) } private func updateWavePosition(animated: Bool, targetPositionY: CGFloat? = nil) { let newPositionY = targetPositionY ?? (1.0 - (currentVolume / totalCapacity)) if animated { UIView.animate(withDuration: 3.0, delay: 0, options: [.curveEaseInOut], animations: { self.wavePositionY = newPositionY self.layer.setNeedsDisplay() }, completion: { finished in if finished { print("Animation completed.") } }) } else { wavePositionY = newPositionY layer.setNeedsDisplay() } } deinit { timer?.invalidate() } }