|
@@ -17,22 +17,22 @@ class PQStuckPointCuttingView: UIView {
|
|
|
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 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
|
|
|
+ private var maxCutTime: CGFloat = cDefaultMargin * 400
|
|
|
// 最小时长 默认 10s
|
|
|
private var minCutTime: CGFloat = 10
|
|
|
/// 时间间隔
|
|
@@ -45,22 +45,37 @@ class PQStuckPointCuttingView: UIView {
|
|
|
private var timeLineMargin: CGFloat = 35
|
|
|
/// 时间线高
|
|
|
private var timeHeight: CGFloat = cDefaultMargin * 4
|
|
|
- /// 频率宽
|
|
|
- private var frequencyWidth: CGFloat = 1
|
|
|
+ /// 频率线宽
|
|
|
+ private var frequencyWidth: CGFloat = 1.5
|
|
|
/// 频率间隔
|
|
|
- private var frequencyMargin: CGFloat = 4
|
|
|
- /// 左右间隔
|
|
|
- private var margin: CGFloat = 2
|
|
|
- /// 每秒宽度
|
|
|
- private var perSecondWidth: CGFloat = 0
|
|
|
+ private var frequencyMargin: CGFloat = 3
|
|
|
+ /// 竖线和contentview 父视图的左右间隔
|
|
|
+ private var margin: CGFloat = (cScreenWidth - adapterWidth(width: 250)) / 2
|
|
|
+
|
|
|
/// 滑动区域大小
|
|
|
private var contentWidth: CGFloat = 0
|
|
|
+
|
|
|
+ //竖线一个间隔代表多少 S 是动态的
|
|
|
+ private var oneMarginTime:CGFloat = 0
|
|
|
+
|
|
|
+ private var isDrawLine:Bool = false
|
|
|
+
|
|
|
+ //保存已经绘制的竖线用于变色使用
|
|
|
+ var lineLayerArray:Array = Array<CAShapeLayer>.init()
|
|
|
+
|
|
|
+ //裁剪区的相素大小
|
|
|
+ var cropViewWidth: CGFloat = adapterWidth(width: 250)
|
|
|
/// 拖拽改变实时的回调
|
|
|
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)?
|
|
|
+
|
|
|
+ //选择区内的线个数
|
|
|
+ var wavSelectCount:Int = 0
|
|
|
+ //整首歌的线的个数
|
|
|
+ var wavTotalCount:Int = 0
|
|
|
/// 滚动视图
|
|
|
lazy var scrollView: UIScrollView = {
|
|
|
let scrollView = UIScrollView(frame: bounds)
|
|
@@ -77,6 +92,7 @@ class PQStuckPointCuttingView: UIView {
|
|
|
return scrollView
|
|
|
}()
|
|
|
|
|
|
+
|
|
|
//
|
|
|
lazy var rateView: UIView = {
|
|
|
let rateView = UIView(frame: CGRect(x: 0, y: 22, width: scrollView.contentSize.width, height: rateHeight))
|
|
@@ -96,7 +112,7 @@ class PQStuckPointCuttingView: UIView {
|
|
|
|
|
|
//显示选择框
|
|
|
lazy var videoCropView: UIView = {
|
|
|
- var cropViewWidth: CGFloat = perSecondWidth * (stuckPointEndTime - stuckPointStartTime) + margin
|
|
|
+
|
|
|
let videoCropView:UIView = UIView.init(frame: CGRect(x: (cScreenWidth - cropViewWidth) / 2 , y: 0, width: cropViewWidth, height: 80))
|
|
|
videoCropView.isUserInteractionEnabled = false
|
|
|
videoCropView.layer.borderColor = UIColor.hexColor(hexadecimal: PQBFConfig.shared.styleColor.rawValue).cgColor
|
|
@@ -120,62 +136,55 @@ class PQStuckPointCuttingView: UIView {
|
|
|
if videoDuration < maxCutTime {
|
|
|
maxCutTime = videoDuration
|
|
|
}
|
|
|
- backgroundColor = .red
|
|
|
+
|
|
|
// 更新卡点值
|
|
|
updateEndTime(startTime: startTime, endTime: endTime)
|
|
|
}
|
|
|
|
|
|
/// 更新卡点值
|
|
|
- /// - Parameter endTime: <#endTime description#>
|
|
|
+ /// - 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()
|
|
|
-
|
|
|
- //计算完第一秒相素宽度再添加裁剪view
|
|
|
+
|
|
|
addSubview(videoCropView)
|
|
|
videoCropView.addSubview(tatalTimeLabel)
|
|
|
-
|
|
|
+
|
|
|
+ addData()
|
|
|
+
|
|
|
tatalTimeLabel.snp.remakeConstraints { make in
|
|
|
make.width.equalTo(40)
|
|
|
make.height.equalTo(15)
|
|
|
make.top.equalTo(videoCropView.snp_top).offset(6)
|
|
|
make.right.equalTo(videoCropView.snp_right).offset(-6)
|
|
|
-
|
|
|
}
|
|
|
}
|
|
|
|
|
|
|
|
|
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
|
|
|
+
|
|
|
+ //1,选择区内的线个数
|
|
|
+ wavSelectCount = Int(cropViewWidth / (frequencyWidth + frequencyMargin))
|
|
|
+ //2,一共绘制的竖线个数
|
|
|
+ wavTotalCount = Int(videoDuration * CGFloat(wavSelectCount) / CGFloat(stuckPointEndTime - stuckPointStartTime))
|
|
|
+
|
|
|
+ //竖线一个间隔代表多少 S 是动态的
|
|
|
+ oneMarginTime = (stuckPointEndTime - stuckPointStartTime) / CGFloat(wavSelectCount)
|
|
|
+ timeRange = oneMarginTime * 10
|
|
|
+ //显示时间 label 的个数 , -1 不够整倍数就不显示时间了
|
|
|
+ let timeLabelCount = Int(videoDuration / timeRange) - 1
|
|
|
+
|
|
|
+ //
|
|
|
+ contentWidth = CGFloat(wavTotalCount) * (frequencyWidth + frequencyMargin) + margin * 2 + timeLineWidth / 2
|
|
|
if contentWidth < scrollView.frame.width {
|
|
|
contentWidth = scrollView.frame.width
|
|
|
}
|
|
|
scrollView.contentSize = CGSize(width: contentWidth, height: scrollView.frame.height)
|
|
|
- for index in 0 ... totalCount {
|
|
|
+ for index in 0 ... timeLabelCount {
|
|
|
let titleLab = UILabel(frame: CGRect(x: CGFloat(index) * (timeLineWidth + timeLineMargin) + margin, y: rateView.frame.maxY, width: timeLineWidth, height: 30))
|
|
|
titleLab.font = UIFont.systemFont(ofSize: 11)
|
|
|
titleLab.textAlignment = .center
|
|
@@ -184,13 +193,15 @@ class PQStuckPointCuttingView: UIView {
|
|
|
titleLab.textColor = UIColor.hexColor(hexadecimal: "#999999")
|
|
|
titleLab.text = "\((Float64(index) * Float64(timeRange)).formatDurationToHMS())"
|
|
|
scrollView.addSubview(titleLab)
|
|
|
+
|
|
|
}
|
|
|
- if perSecondWidth > 0, cutEndTime > 0, cutStartTime < cutEndTime {
|
|
|
- /// 处理音频频率
|
|
|
+ if oneMarginTime > 0{
|
|
|
+ // 1,处理音频频率
|
|
|
configVoiceFrequency()
|
|
|
- // 每秒占有宽度
|
|
|
+ // 2,滚动到推荐位置
|
|
|
if scrollView.frame.width < scrollView.contentSize.width {
|
|
|
- var offsetX = perSecondWidth * (stuckPointStartTime + (stuckPointEndTime - stuckPointStartTime) / 2) - scrollView.frame.width / 2 + timeLineWidth
|
|
|
+ var offsetX = (stuckPointStartTime / oneMarginTime) * (frequencyWidth + frequencyMargin) + timeLineWidth / 2
|
|
|
+
|
|
|
if offsetX < 0 {
|
|
|
offsetX = 0
|
|
|
}
|
|
@@ -207,20 +218,46 @@ class PQStuckPointCuttingView: UIView {
|
|
|
/// 处理音频频率
|
|
|
/// - Returns: <#description#>
|
|
|
func configVoiceFrequency() {
|
|
|
- let waveTotalCount = Int(videoDuration) / cFrequency.count
|
|
|
- var remainder = Int(ceil(videoDuration - CGFloat(waveTotalCount * cFrequency.count)))
|
|
|
+
|
|
|
+ //整倍数
|
|
|
+ let waveTotalCount = Int(wavTotalCount) / cFrequency.count
|
|
|
+ //余多少个未画的
|
|
|
+ var remainder = Int(ceil(CGFloat(wavTotalCount) - CGFloat(waveTotalCount * cFrequency.count)))
|
|
|
var totalWave: [CGFloat] = Array<CGFloat>.init()
|
|
|
+ //1,先画整倍数个竖线
|
|
|
for _ in 0 ..< waveTotalCount {
|
|
|
totalWave = totalWave + cFrequency
|
|
|
}
|
|
|
if remainder > cFrequency.count - 1 {
|
|
|
remainder = cFrequency.count - 1
|
|
|
}
|
|
|
+ //1,再画余数个竖线
|
|
|
if remainder > 0 {
|
|
|
totalWave = totalWave + cFrequency[0 ... remainder]
|
|
|
}
|
|
|
+
|
|
|
createWave(waveArr: totalWave)
|
|
|
}
|
|
|
+
|
|
|
+ /// 更新进度绘制不同色值
|
|
|
+ /// progress <#progress description#>
|
|
|
+ func updateProgress(progress: CGFloat) {
|
|
|
+
|
|
|
+ for (i,layer) in lineLayerArray.enumerated() {
|
|
|
+ if(CGFloat(i) * oneMarginTime <= stuckPointStartTime + progress * CGFloat(stuckPointEndTime - stuckPointStartTime) && CGFloat(i) * oneMarginTime >= stuckPointStartTime){
|
|
|
+ BFLog(message: "progress is \(progress) 命中的位置:\(CGFloat(i) * oneMarginTime)")
|
|
|
+ layer.strokeColor = UIColor.hexColor(hexadecimal: PQBFConfig.shared.styleColor.rawValue).cgColor
|
|
|
+ layer.setNeedsDisplay()
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ //竖线恢复到原有色值
|
|
|
+ func resetDefaultsColor() {
|
|
|
+ for layer in lineLayerArray {
|
|
|
+ layer.strokeColor = UIColor.hexColor(hexadecimal: "#999999").cgColor
|
|
|
+ layer.setNeedsDisplay()
|
|
|
+ }
|
|
|
+ }
|
|
|
|
|
|
/// 生成波纹
|
|
|
/// - Parameter waveArr: <#waveArr description#>
|
|
@@ -237,16 +274,34 @@ class PQStuckPointCuttingView: UIView {
|
|
|
if endY > CGFloat(hight) { endY = hight }
|
|
|
// 线的路径
|
|
|
let linePath = UIBezierPath()
|
|
|
- // 起点
|
|
|
- let originX: CGFloat = CGFloat(i * Int(frequencyWidth + frequencyMargin)) + margin + timeLineWidth / 2
|
|
|
+ // 起点 timeLineWidth / 2 处理显示时间的 label中心为时间点
|
|
|
+ let originX: CGFloat = CGFloat(Float(i) * Float(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
|
|
|
+
|
|
|
+ //推荐的开始起点是虚线
|
|
|
+ if(oneMarginTime * CGFloat(i) >= stuckPointStartTime && !isDrawLine){
|
|
|
+ isDrawLine = true
|
|
|
+ linePath.move(to: CGPoint(x: originX, y: -10))
|
|
|
+ // 终点
|
|
|
+ linePath.addLine(to: CGPoint(x: originX, y: 30))
|
|
|
+ lineLayer.path = linePath.cgPath
|
|
|
+ lineLayer.lineDashPhase = 0
|
|
|
+ lineLayer.lineDashPattern = [3, 3]
|
|
|
+
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ lineLayerArray.append(lineLayer)
|
|
|
rateView.layer.insertSublayer(lineLayer, at: 0)
|
|
|
}
|
|
|
}
|
|
@@ -261,21 +316,15 @@ class PQStuckPointCuttingView: UIView {
|
|
|
/// 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) {
|
|
|
+
|
|
|
+ func scrollViewDidEndDecelerating(_: UIScrollView) {
|
|
|
BFLog(message: "拖拽结束 - 回调")
|
|
|
-// videoProgress = 0
|
|
|
-// if videoDidEndDragging != nil {
|
|
|
-// videoDidEndDragging!(3, cutFinishedStartTime, cutFinishedEndTime, videoProgress)
|
|
|
-// }
|
|
|
+ resetDefaultsColor()
|
|
|
+ }
|
|
|
+ func scrollViewDidEndScrollingAnimation(_: UIScrollView) {
|
|
|
+ BFLog(message: "scrollViewDidEndScrollingAnimation")
|
|
|
+ resetDefaultsColor()
|
|
|
}
|
|
|
}
|