123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272 |
- //
- // PQStuckPointCuttingView.swift
- // PQSpeed
- //
- // Created by SanW on 2021/5/8.
- // Copyright © 2021 BytesFlow. All rights reserved.
- //
- import UIKit
- import BFCommonKit
- class PQStuckPointCuttingView: UIView {
- // 视频时长
- private var videoDuration: CGFloat = 0
- // 卡点开始时间 默认 0
- private var stuckPointStartTime: CGFloat = 0
- // 卡点结束时间
- private var stuckPointEndTime: CGFloat = 0
- // 裁剪开始时间 默认 0
- private var cutStartTime: CGFloat = 0
- // 裁剪结束时间
- private var cutEndTime: CGFloat = 0
- /// 裁剪结束最终的开始时间
- private var cutFinishedStartTime: CGFloat {
- (scrollView.contentOffset.x / perSecondWidth) + (((scrollView.frame.width - videoCropView.frame.width) / 2 + 15) / perSecondWidth) + cutStartTime
- }
- /// 裁剪结束最终的结束时间
- private var cutFinishedEndTime: CGFloat {
- cutFinishedStartTime + (cutEndTime - cutStartTime)
- }
- // 播放进度
- private var videoProgress: CGFloat = 0
- // 最大时长 默认 40s
- private var maxCutTime: CGFloat = cDefaultMargin * 4
- // 最小时长 默认 10s
- private var minCutTime: CGFloat = 10
- /// 时间间隔
- private var timeRange: CGFloat = cDefaultMargin
- /// 刻度高
- private var rateHeight: CGFloat = cDefaultMargin * 5
- /// 时间线宽
- private var timeLineWidth: CGFloat = 35
- /// 时间线间隔
- private var timeLineMargin: CGFloat = 35
- /// 时间线高
- private var timeHeight: CGFloat = cDefaultMargin * 4
- /// 频率宽
- private var frequencyWidth: CGFloat = 1
- /// 频率间隔
- private var frequencyMargin: CGFloat = 4
- /// 左右间隔
- private var margin: CGFloat = cDefaultMargin * 3
- /// 每秒宽度
- private var perSecondWidth: CGFloat = 0
- /// 滑动区域大小
- private var contentWidth: CGFloat = 0
- /// 拖拽改变实时的回调
- var videoRangeDidChanged: ((_ startTime: CGFloat, _ endTime: CGFloat) -> Void)?
- /// 进度改变实时的回调
- var videoProgressDidChanged: ((_ progress: CGFloat) -> Void)?
- /// 拖缀结束的回调 type - 1-拖动左边裁剪结束 2--拖动右边裁剪结束 3-进度条拖动结束 4-滑动结束
- var videoDidEndDragging: ((_ type: Int, _ startTime: CGFloat, _ endTime: CGFloat, _ progress: CGFloat) -> Void)?
- /// 滚动视图
- lazy var scrollView: UIScrollView = {
- let scrollView = UIScrollView(frame: bounds)
- scrollView.showsVerticalScrollIndicator = false
- scrollView.showsHorizontalScrollIndicator = false
- scrollView.bounces = false
- scrollView.delegate = self
- if #available(iOS 11.0, *) {
- scrollView.contentInsetAdjustmentBehavior = .never
- } else {
- // automaticallyAdjustsScrollViewInsets = false
- }
- return scrollView
- }()
- lazy var rateView: UIView = {
- let rateView = UIView(frame: CGRect(x: 0, y: videoCropView.frame.minY + 16.5, width: scrollView.contentSize.width, height: rateHeight))
- rateView.backgroundColor = PQBFConfig.shared.otherTintColor
- return rateView
- }()
- lazy var videoCropView: PQVideoCutingOprateView = {
- var originX: CGFloat = perSecondWidth * (stuckPointStartTime + cutStartTime) + margin
- if contentWidth > scrollView.frame.width {
- originX = perSecondWidth * (stuckPointStartTime - cutStartTime) + margin
- }
- let videoCropView: PQVideoCutingOprateView = PQVideoCutingOprateView(frame: CGRect(x: margin, y: frame.height - 90, width: contentWidth - margin * 2, height: 90), duration: videoDuration, startTime: cutStartTime, endTime: cutEndTime, minDuration: minCutTime, maxDuration: maxCutTime)
- videoCropView.cutRangeDidChanged = { [weak self] cutStartTime, cutEndTime, _ in
- self?.cutStartTime = cutStartTime
- self?.cutEndTime = cutEndTime
- self?.videoProgress = 0
- // 计算当前时间
- if self?.videoRangeDidChanged != nil {
- self?.videoRangeDidChanged!(cutStartTime, cutEndTime)
- }
- }
- videoCropView.progressDidChanged = { [weak self] progress in
- self?.videoProgress = progress
- if self?.videoProgressDidChanged != nil {
- self?.videoProgressDidChanged!(progress)
- }
- }
- videoCropView.didEndDragging = { [weak self] type, startTime, endTime, progress in
- self?.videoProgress = 0
- if self?.videoDidEndDragging != nil {
- self?.videoDidEndDragging!(type, startTime, endTime, progress)
- }
- }
- return videoCropView
- }()
- override private init(frame: CGRect) {
- super.init(frame: frame)
- }
- required init?(coder _: NSCoder) {
- fatalError("init(coder:) has not been implemented")
- }
- init(frame: CGRect, duration: CGFloat, startTime: CGFloat, endTime: CGFloat) {
- super.init(frame: frame)
- videoDuration = duration
- if videoDuration < maxCutTime {
- maxCutTime = videoDuration
- }
- // 更新卡点值
- updateEndTime(startTime: startTime, endTime: endTime)
- }
- /// 更新卡点值
- /// - Parameter endTime: <#endTime description#>
- /// - Returns: <#description#>
- func updateEndTime(startTime: CGFloat, endTime: CGFloat) {
- stuckPointStartTime = startTime
- stuckPointEndTime = endTime
- if (stuckPointEndTime - stuckPointStartTime) > maxCutTime {
- stuckPointEndTime = stuckPointStartTime + maxCutTime
- }
- cutStartTime = startTime
- cutEndTime = endTime
- if cutEndTime > videoDuration {
- cutEndTime = videoDuration
- }
- backgroundColor = PQBFConfig.shared.styleBackGroundColor
- addSubview(scrollView)
- addData()
- }
- func addData() {
- perSecondWidth = (timeLineWidth + timeLineMargin) / timeRange
- frequencyMargin = perSecondWidth - frequencyWidth
- let tempWidth = videoDuration * perSecondWidth + timeLineWidth
- let totalCount = Int(videoDuration / timeRange)
- // let remainder = videoDuration - (CGFloat(totalCount) * timeRange)
- // if remainder != 0 {
- // totalCount = totalCount + 1
- // }
- if (tempWidth + margin * 2) < scrollView.frame.width {
- margin = (scrollView.frame.width - tempWidth) / 2
- }
- contentWidth = tempWidth + margin * 2
- if contentWidth < scrollView.frame.width {
- contentWidth = scrollView.frame.width
- }
- scrollView.contentSize = CGSize(width: contentWidth, height: scrollView.frame.height)
- for index in 0 ... totalCount {
- let titleLab = UILabel(frame: CGRect(x: CGFloat(index) * (timeLineWidth + timeLineMargin) + margin, y: 0, width: timeLineWidth, height: timeHeight))
- titleLab.font = UIFont.systemFont(ofSize: 12)
- titleLab.textAlignment = .center
- titleLab.numberOfLines = 2
- titleLab.textColor = UIColor.hexColor(hexadecimal: "#999999")
- titleLab.text = "\((Float64(index) * Float64(timeRange)).formatDurationToHMS())\n·"
- scrollView.addSubview(titleLab)
- }
- if perSecondWidth > 0, cutEndTime > 0, cutStartTime < cutEndTime {
- /// 处理音频频率
- configVoiceFrequency()
- // 每秒占有宽度
- if scrollView.frame.width < scrollView.contentSize.width {
- var offsetX = perSecondWidth * (stuckPointStartTime + (stuckPointEndTime - stuckPointStartTime) / 2) - scrollView.frame.width / 2 + timeLineWidth
- if offsetX < 0 {
- offsetX = 0
- }
- if offsetX > (scrollView.contentSize.width - scrollView.frame.width) {
- offsetX = (scrollView.contentSize.width - scrollView.frame.width)
- }
- scrollView.contentOffset = CGPoint(x: offsetX, y: 0)
- }
- scrollView.addSubview(rateView)
- scrollView.addSubview(videoCropView)
- }
- }
- /// 处理音频频率
- /// - Returns: <#description#>
- func configVoiceFrequency() {
- let waveTotalCount = Int(videoDuration) / cFrequency.count
- var remainder = Int(ceil(videoDuration - CGFloat(waveTotalCount * cFrequency.count)))
- var totalWave: [CGFloat] = Array<CGFloat>.init()
- for _ in 0 ..< waveTotalCount {
- totalWave = totalWave + cFrequency
- }
- if remainder > cFrequency.count - 1 {
- remainder = cFrequency.count - 1
- }
- if remainder > 0 {
- totalWave = totalWave + cFrequency[0 ... remainder]
- }
- createWave(waveArr: totalWave)
- }
- /// 生成波纹
- /// - Parameter waveArr: <#waveArr description#>
- /// - Returns: <#description#>
- func createWave(waveArr: [CGFloat]) {
- for (i, power) in waveArr.enumerated() {
- // 画布高度
- let hight: CGFloat = rateView.frame.height
- // 开始 Y 值
- var startY: CGFloat = (hight - power) / 2.0
- if startY < 0 { startY = 0 }
- // 结束 Y 值
- var endY: CGFloat = startY + power
- if endY > CGFloat(hight) { endY = hight }
- // 线的路径
- let linePath = UIBezierPath()
- // 起点
- let originX: CGFloat = CGFloat(i * Int(frequencyWidth + frequencyMargin)) + margin + timeLineWidth / 2
- linePath.move(to: CGPoint(x: originX, y: startY))
- // 终点
- linePath.addLine(to: CGPoint(x: originX, y: endY))
- let lineLayer = CAShapeLayer()
- lineLayer.lineWidth = frequencyWidth
- lineLayer.strokeColor = UIColor.hexColor(hexadecimal: "#999999").cgColor
- lineLayer.path = linePath.cgPath
- lineLayer.fillColor = UIColor.black.cgColor
- rateView.layer.insertSublayer(lineLayer, at: 0)
- }
- }
- deinit {
- BFLog(message: "卡点裁剪-裁剪视图销毁")
- }
- }
- // MARK: - scrollView滑动代理
- /// scrollView滑动代理
- extension PQStuckPointCuttingView: UIScrollViewDelegate {
- func scrollViewDidScroll(_: UIScrollView) {
- // 计算当前开始时间
- // if scrollView.contentOffset.x > margin {
- // if videoRangeDidChanged != nil {
- // videoRangeDidChanged!(cutFinishedStartTime, cutFinishedEndTime)
- // }
- // NSObject.cancelPreviousPerformRequests(withTarget: self)
- // perform(#selector(scrollViewDidEndScrollingAnimation(scrollView:)), with: nil, afterDelay: 0.1)
- // }
- }
- @objc func scrollViewDidEndScrollingAnimation(scrollView _: UIScrollView) {
- BFLog(message: "拖拽结束 - 回调")
- // videoProgress = 0
- // if videoDidEndDragging != nil {
- // videoDidEndDragging!(3, cutFinishedStartTime, cutFinishedEndTime, videoProgress)
- // }
- }
- }
|