NXVoiceBubbleView.swift 5.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184
  1. //
  2. // NXVoiceBubbleView.swift
  3. // bubbleLayer_swift
  4. //
  5. // Created by liuming on 2020/8/23.
  6. // Copyright © 2020 liuming. All rights reserved.
  7. //
  8. import UIKit
  9. public class NXVoiceBubbleView: NXNormalBubbleView {
  10. /// 关闭按钮
  11. private let closeBtn = UIButton(type: .custom)
  12. /// 声音图片
  13. private let voiceImgView = UIImageView(frame: .zero)
  14. /// 语音时间文本
  15. public let durationLabel = UILabel(frame: .zero)
  16. /// 语音图片序列帧动画时间
  17. public var animationDuration: TimeInterval = 0.5 {
  18. didSet {
  19. self.initVoiceAnimation()
  20. }
  21. }
  22. // 加载圈
  23. lazy var activityIndicator: UIActivityIndicatorView = {
  24. let activityIndicator: UIActivityIndicatorView = UIActivityIndicatorView(style:
  25. .gray)
  26. return activityIndicator
  27. }()
  28. /// 语音图片帧图片
  29. public var animationImages: [UIImage] = Array() {
  30. didSet {
  31. initVoiceAnimation()
  32. }
  33. }
  34. /// 语音图片动画重复次数
  35. public var animationRepeatCount: Int = 1 {
  36. didSet {
  37. initVoiceAnimation()
  38. }
  39. }
  40. /// 音频显示的总时间
  41. public var duration: Float64 = 0 {
  42. didSet {
  43. showTime()
  44. activityIndicatorStop()
  45. }
  46. }
  47. public var closeBtnClickedHander: (() -> Void)?
  48. override public init(frame: CGRect) {
  49. super.init(frame: frame)
  50. initSubviews()
  51. }
  52. required init?(coder _: NSCoder) {
  53. fatalError("init(coder:) has not been implemented")
  54. }
  55. private func initSubviews() {
  56. containView.addSubview(voiceImgView)
  57. voiceImgView.image = UIImage(named: "icon_voice")
  58. containView.addSubview(durationLabel)
  59. closeBtn.setImage(UIImage(named: "videomk_serach_clear"), for: .normal)
  60. closeBtn.setImage(UIImage(named: "videomk_serach_clear"), for: .highlighted)
  61. closeBtn.addTarget(self, action: #selector(closeBtnClicked(sender:)), for: .touchUpInside)
  62. containView.addSubview(closeBtn)
  63. containView.addSubview(activityIndicator)
  64. // 布局
  65. voiceImgView.snp.makeConstraints { maker in
  66. maker.centerY.equalTo(self.containView)
  67. maker.left.equalTo(self.containView).offset(10)
  68. maker.width.height.equalTo(20)
  69. }
  70. durationLabel.snp.makeConstraints { maker in
  71. maker.right.equalTo(self.containView).offset(-10)
  72. maker.centerY.equalTo(self.containView)
  73. maker.height.equalTo(20)
  74. }
  75. closeBtn.snp.makeConstraints { maker in
  76. maker.right.equalTo(self.containView).offset(10)
  77. maker.top.equalTo(self.containView).offset(-8)
  78. maker.width.height.equalTo(20)
  79. }
  80. activityIndicator.snp.makeConstraints { maker in
  81. maker.right.equalTo(self.containView).offset(-10)
  82. maker.centerY.equalTo(self.containView)
  83. maker.height.equalTo(20)
  84. }
  85. }
  86. private func showTime() {
  87. durationLabel.text = duration < 1 ? "1'" : duration.formatDurationToMS()
  88. }
  89. private func initVoiceAnimation() {
  90. if animationImages.count > 0 {
  91. voiceImgView.animationImages = animationImages
  92. voiceImgView.animationDuration = animationDuration
  93. voiceImgView.animationRepeatCount = animationRepeatCount
  94. }
  95. }
  96. /// 加载圈开始动画
  97. public func activityIndicatorStart() {
  98. durationLabel.text = ""
  99. activityIndicator.startAnimating()
  100. }
  101. /// 加载圈结束动画
  102. public func activityIndicatorStop() {
  103. activityIndicator.stopAnimating()
  104. }
  105. /// 开始动画
  106. public func startAnimation() {
  107. voiceImgView.startAnimating()
  108. }
  109. /// 结束动画
  110. public func stopAnimation() {
  111. voiceImgView.stopAnimating()
  112. }
  113. /// 按照中心点抖动
  114. func animation() {
  115. let animati = CAKeyframeAnimation(keyPath: "transform.rotation")
  116. // rotation 旋转,需要添加弧度值
  117. // 角度转弧度
  118. animati.values = [angle2Radion(angle: -50), angle2Radion(angle: 50), angle2Radion(angle: -50)]
  119. animati.repeatCount = 4
  120. layer.add(animati, forKey: nil)
  121. }
  122. // MARK: - 重写交互层的长按和点击事件
  123. override public func tapGestureRecognizerHandler(sender: UITapGestureRecognizer) {
  124. super.tapGestureRecognizerHandler(sender: sender)
  125. startAnimation()
  126. print("点击了语音气泡")
  127. }
  128. override public func longGestureRecognizerHandler(sender: UILongPressGestureRecognizer) {
  129. super.longGestureRecognizerHandler(sender: sender)
  130. print("长按了 点击了语音气泡")
  131. animation()
  132. }
  133. func angle2Radion(angle: Float) -> Float {
  134. return angle / Float(180.0 * Double.pi)
  135. }
  136. // MARK: 关闭按钮点击事件
  137. @objc
  138. func closeBtnClicked(sender _: UIButton) {
  139. print("点击了关闭按钮")
  140. if let block = closeBtnClickedHander {
  141. block()
  142. }
  143. }
  144. override public func point(inside point: CGPoint, with _: UIEvent?) -> Bool {
  145. if bounds.contains(point) {
  146. return true
  147. }
  148. let p = convert(point, to: closeBtn)
  149. if closeBtn.bounds.contains(p) {
  150. return true
  151. }
  152. return false
  153. }
  154. }