// // NXVoiceBubbleView.swift // bubbleLayer_swift // // Created by liuming on 2020/8/23. // Copyright © 2020 liuming. All rights reserved. // import UIKit public class NXVoiceBubbleView: NXNormalBubbleView { /// 关闭按钮 private let closeBtn = UIButton(type: .custom) /// 声音图片 private let voiceImgView = UIImageView(frame: .zero) /// 语音时间文本 public let durationLabel = UILabel(frame: .zero) /// 语音图片序列帧动画时间 public var animationDuration: TimeInterval = 0.5 { didSet { self.initVoiceAnimation() } } // 加载圈 lazy var activityIndicator: UIActivityIndicatorView = { let activityIndicator: UIActivityIndicatorView = UIActivityIndicatorView(style: .gray) return activityIndicator }() /// 语音图片帧图片 public var animationImages: [UIImage] = Array() { didSet { initVoiceAnimation() } } /// 语音图片动画重复次数 public var animationRepeatCount: Int = 1 { didSet { initVoiceAnimation() } } /// 音频显示的总时间 public var duration: Float64 = 0 { didSet { showTime() activityIndicatorStop() } } public var closeBtnClickedHander: (() -> Void)? override public init(frame: CGRect) { super.init(frame: frame) initSubviews() } required init?(coder _: NSCoder) { fatalError("init(coder:) has not been implemented") } private func initSubviews() { containView.addSubview(voiceImgView) voiceImgView.image = UIImage(named: "icon_voice") containView.addSubview(durationLabel) closeBtn.setImage(UIImage(named: "videomk_serach_clear"), for: .normal) closeBtn.setImage(UIImage(named: "videomk_serach_clear"), for: .highlighted) closeBtn.addTarget(self, action: #selector(closeBtnClicked(sender:)), for: .touchUpInside) containView.addSubview(closeBtn) containView.addSubview(activityIndicator) // 布局 voiceImgView.snp.makeConstraints { maker in maker.centerY.equalTo(self.containView) maker.left.equalTo(self.containView).offset(10) maker.width.height.equalTo(20) } durationLabel.snp.makeConstraints { maker in maker.right.equalTo(self.containView).offset(-10) maker.centerY.equalTo(self.containView) maker.height.equalTo(20) } closeBtn.snp.makeConstraints { maker in maker.right.equalTo(self.containView).offset(10) maker.top.equalTo(self.containView).offset(-8) maker.width.height.equalTo(20) } activityIndicator.snp.makeConstraints { maker in maker.right.equalTo(self.containView).offset(-10) maker.centerY.equalTo(self.containView) maker.height.equalTo(20) } } private func showTime() { durationLabel.text = duration < 1 ? "1'" : duration.formatDurationToMS() } private func initVoiceAnimation() { if animationImages.count > 0 { voiceImgView.animationImages = animationImages voiceImgView.animationDuration = animationDuration voiceImgView.animationRepeatCount = animationRepeatCount } } /// 加载圈开始动画 public func activityIndicatorStart() { durationLabel.text = "" activityIndicator.startAnimating() } /// 加载圈结束动画 public func activityIndicatorStop() { activityIndicator.stopAnimating() } /// 开始动画 public func startAnimation() { voiceImgView.startAnimating() } /// 结束动画 public func stopAnimation() { voiceImgView.stopAnimating() } /// 按照中心点抖动 func animation() { let animati = CAKeyframeAnimation(keyPath: "transform.rotation") // rotation 旋转,需要添加弧度值 // 角度转弧度 animati.values = [angle2Radion(angle: -50), angle2Radion(angle: 50), angle2Radion(angle: -50)] animati.repeatCount = 4 layer.add(animati, forKey: nil) } // MARK: - 重写交互层的长按和点击事件 override public func tapGestureRecognizerHandler(sender: UITapGestureRecognizer) { super.tapGestureRecognizerHandler(sender: sender) startAnimation() print("点击了语音气泡") } override public func longGestureRecognizerHandler(sender: UILongPressGestureRecognizer) { super.longGestureRecognizerHandler(sender: sender) print("长按了 点击了语音气泡") animation() } func angle2Radion(angle: Float) -> Float { return angle / Float(180.0 * Double.pi) } // MARK: 关闭按钮点击事件 @objc func closeBtnClicked(sender _: UIButton) { print("点击了关闭按钮") if let block = closeBtnClickedHander { block() } } override public func point(inside point: CGPoint, with _: UIEvent?) -> Bool { if bounds.contains(point) { return true } let p = convert(point, to: closeBtn) if closeBtn.bounds.contains(p) { return true } return false } }