BFIndirectionProgressView.swift 6.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166
  1. //
  2. // BFIndirectionProgressView.swift
  3. // BFRecordScreenKit
  4. //
  5. // Created by SanW on 2021/12/18.
  6. // Copyright © 2021 BytesFlow. All rights reserved.
  7. //
  8. import BFCommonKit
  9. import BFMediaKit
  10. import UIKit
  11. class BFIndirectionProgressView: UIView {
  12. var indirecColor: UIColor = UIColor.clear
  13. var themeColor: UIColor = UIColor.hexColor(hexadecimal: "#389AFF")
  14. var progressHeight: CGFloat = 6
  15. var tmpPercentW: CGFloat = 0
  16. var deletedView: UIView?
  17. var percenWidth: CGFloat {
  18. get {
  19. if tmpPercentW.isNaN || tmpPercentW.isInfinite || (tmpPercentW <= 0 && totalDuration > 0) {
  20. return frame.width / totalDuration
  21. } else {
  22. return tmpPercentW
  23. }
  24. }
  25. set {
  26. tmpPercentW = newValue
  27. }
  28. }
  29. var totalDuration: Float64 = 0
  30. var currentItem: UIView? // 当前的Item
  31. override private init(frame: CGRect) {
  32. super.init(frame: frame)
  33. }
  34. init(frame: CGRect, indirecColor: UIColor = UIColor.clear, themeColor: UIColor = UIColor.hexColor(hexadecimal: "#389AFF"), percenWidth: CGFloat = 0, progressHeight: CGFloat = 6, totalDuration: Float64 = 0) {
  35. super.init(frame: frame)
  36. self.indirecColor = indirecColor
  37. self.themeColor = themeColor
  38. self.totalDuration = totalDuration
  39. self.progressHeight = progressHeight
  40. self.percenWidth = percenWidth
  41. }
  42. required init?(coder _: NSCoder) {
  43. fatalError("init(coder:) has not been implemented")
  44. }
  45. /// 重绘view
  46. /// - Parameter items: <#items description#>
  47. /// - Parameter percenWidth: 图片为固定值要传入,视频的话可以计算,也可以传入
  48. func resetAllSubViews(items: [PQVoiceModel]?, percenWidth: CGFloat = 0, totalDuration: Float64) {
  49. frame.size.width = (superview as? UIScrollView)?.contentSize.width ?? 0
  50. self.totalDuration = totalDuration
  51. self.percenWidth = percenWidth
  52. deletedView = nil
  53. currentItem = nil
  54. subviews.forEach { vv in
  55. vv.removeFromSuperview()
  56. }
  57. items?.forEach { [weak self] model in
  58. _ = createItemView(minX: model.startCMTime.seconds * CGFloat(self?.percenWidth ?? 0), width: (model.endCMTime.seconds - model.startCMTime.seconds) * CGFloat(self?.percenWidth ?? 0))
  59. }
  60. }
  61. /// 设置进度
  62. /// - Parameters:
  63. /// - _: <#_ description#>
  64. /// - start: <#start description#>
  65. /// - progress: <#progress description#>
  66. func setProgress(start: CGFloat = 0, progress: Float64) {
  67. BFLog(message: "录音进度--指示器Indir:progress=\(progress),duration=\(totalDuration),w=\(frame.width),perW=\(percenWidth),totalW:\(progress * percenWidth)")
  68. if start * percenWidth >= frame.width {
  69. frame.size.width = (superview as? UIScrollView)?.contentSize.width ?? 0
  70. }
  71. detectionAndCreateItem(start: start, progress: progress)
  72. currentItem?.frame.size.width = progress < 0 ? 0 : progress * percenWidth
  73. BFLog(message: "当前view:\(String(describing: currentItem))")
  74. let vc = subviews.first { [weak self] sub in
  75. (self?.currentItem?.frame.minX ?? 0) < sub.frame.minX && sub.frame.minX < (self?.currentItem?.frame.maxX ?? 0)
  76. }
  77. if vc != nil {
  78. deletedView = vc
  79. vc?.removeFromSuperview()
  80. BFLog(message: "添加覆盖view-添加:deletedView = \(String(describing: deletedView))")
  81. }
  82. }
  83. /// 检测并创建item
  84. /// - Parameter start: <#start description#>
  85. func detectionAndCreateItem(start: CGFloat = 0, progress: Float64) {
  86. BFLog(message: "检测并创建item:\(start)")
  87. if currentItem == nil {
  88. deletedView = nil
  89. currentItem = detectionItem(start: start, progress: progress)
  90. }
  91. }
  92. /// 检测当前view
  93. /// - Parameters:
  94. /// - start: <#start description#>
  95. /// - progress: <#progress description#>
  96. /// - Returns: <#description#>
  97. func detectionItem(start: CGFloat = 0, progress: Float64) -> UIView {
  98. let newRange = CMTimeRange(start: CMTime(seconds: start, preferredTimescale: 1000), end: CMTime(seconds: start + progress, preferredTimescale: 1000))
  99. var currentIndex: Int?
  100. for (index, item) in subviews.enumerated() {
  101. let originRange = CMTimeRange(start: CMTime(seconds: item.frame.minX / percenWidth, preferredTimescale: 1000), end: CMTime(seconds: item.frame.width / percenWidth, preferredTimescale: 1000))
  102. if CMTimeRangeGetIntersection(originRange, otherRange: newRange).duration.seconds > 0 {
  103. currentIndex = index
  104. break
  105. }
  106. }
  107. if currentIndex != nil {
  108. BFLog(message: "检测存在重新创建")
  109. return subviews[currentIndex!]
  110. } else {
  111. BFLog(message: "检测不存在重新创建:\(start)")
  112. return createItemView(minX: start * percenWidth)
  113. }
  114. }
  115. /// 录制结束后重制当前item
  116. func resetCurrentItem(start: CGFloat, end: CGFloat) {
  117. currentItem?.frame.origin.x = start * percenWidth
  118. currentItem?.frame.size.width = (end - start) * percenWidth
  119. currentItem = nil
  120. BFLog(message: "重置currentItem:\(start)")
  121. }
  122. /// 删除某个view
  123. /// - Parameter index: <#index description#>
  124. func deleteItem(index: Int = 0, isCurrent: Bool = false, isImage _: Bool = false) {
  125. BFLog(message: "添加覆盖view-不足一秒:\(isCurrent),deletedView = \(String(describing: deletedView))")
  126. if isCurrent {
  127. currentItem?.removeFromSuperview()
  128. currentItem = nil
  129. if deletedView != nil {
  130. BFLog(message: "添加view")
  131. addSubview(deletedView!)
  132. }
  133. } else {
  134. if index >= 0, index < subviews.count {
  135. subviews[index].removeFromSuperview()
  136. }
  137. }
  138. deletedView = nil
  139. }
  140. /// 创建一个view
  141. /// - Parameters:
  142. /// - minX: <#minX description#>
  143. /// - width: <#width description#>
  144. /// - indirec: <#indirec description#>
  145. /// - Returns: <#description#>
  146. func createItemView(minX: CGFloat, width: CGFloat = 0, indirec: Bool = false) -> UIView {
  147. let lineV = UIView(frame: CGRect(x: minX < 0 ? 0 : minX, y: 0, width: width, height: progressHeight))
  148. lineV.backgroundColor = indirec ? indirecColor : themeColor
  149. addSubview(lineV)
  150. return lineV
  151. }
  152. }