123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296 |
- //
- // PQVideoCutingOprateView.swift
- // PQSpeed
- //
- // Created by SanW on 2021/5/9.
- // Copyright © 2021 BytesFlow. All rights reserved.
- //
- import UIKit
- class PQVideoCutingOprateView: UIView {
- // 距离左边间隔
- var leftMargin: CGFloat = 0
- // 距离右边间隔
- var rightMargin: CGFloat = 0
- // 距离上边间隔
- var topMargin: CGFloat = 14
- // 距离下边间隔
- var bottomMargin: CGFloat = 20
- /// 上下线条的高度
- var lineHeight: CGFloat = 3.0
- /// 进度宽度
- var progressWidth: CGFloat = 12.0
- // 左右裁剪操作宽度
- var cutingOprateWidth: CGFloat = 15
- // 开始时间 默认 0
- private var cutStartTime: CGFloat = 0
- // 结束时间
- private var cutEndTime: CGFloat = 0
- // 视频总时长
- private var totalDuration: CGFloat = 0
- // 最小裁剪大小 默认 10s
- private var cutMinDuration: CGFloat = 10
- // 最大裁剪大小 默认 40s
- private var cutMaxDuration: CGFloat = 40
- /// 每秒宽度
- private var perSecondWidth: CGFloat = 0
- /// 裁剪总时长
- private var cutTotalTime: CGFloat = 0
- /// 当前滑动的位置
- private var preOriginX: CGFloat = 0
- /// 当前滑动的view
- private var currentPanView: UIView?
- private var progress: CGFloat {
- if progressView.frame.minX >= (rightOprateView.frame.minX - (((progressView.frame.width - 3) / 2) + 3)) {
- return 1
- } else {
- return ((progressView.frame.minX - (leftOprateView.frame.maxX - ((progressView.frame.width - 3) / 2))) / perSecondWidth) / (cutEndTime - cutStartTime)
- }
- }
- /// 拖缀结束的回调 type - 1-拖动左边裁剪结束 2--拖动右边裁剪结束 3-进度条拖动结束 4-滑动结束
- var didEndDragging: ((_ type: Int, _ startTime: CGFloat, _ endTime: CGFloat, _ progress: CGFloat) -> Void)?
- /// 裁剪实时回调
- var cutRangeDidChanged: ((_ startTime: CGFloat, _ endTime: CGFloat, _ cutTotalTime: CGFloat) -> Void)?
- /// 进度回调
- var progressDidChanged: ((_ progress: CGFloat) -> Void)?
- lazy var durationLabel: UILabel = {
- let durationLabel = UILabel()
- durationLabel.font = UIFont.systemFont(ofSize: 11, weight: .medium)
- durationLabel.backgroundColor = UIColor(red: 238 / 255, green: 0, blue: 81 / 255, alpha: 0.3)
- durationLabel.textColor = UIColor.white
- durationLabel.textAlignment = .center
- return durationLabel
- }()
- lazy var leftOprateView: UIImageView = {
- let leftOprateView = UIImageView(image:UIImage.init().BF_Image(named: "videomk_crop_left"))
- leftOprateView.contentMode = .scaleAspectFill
- leftOprateView.isUserInteractionEnabled = true
- leftOprateView.backgroundColor = UIColor.white
- let panGes = UIPanGestureRecognizer(target: self, action: #selector(panGesture(gesture:)))
- panGes.maximumNumberOfTouches = 1
- panGes.minimumNumberOfTouches = 1
- leftOprateView.addGestureRecognizer(panGes)
- return leftOprateView
- }()
- lazy var rightOprateView: UIImageView = {
- let rightOprateView = UIImageView(image: UIImage.init().BF_Image(named: "videomk_crop_right"))
- rightOprateView.contentMode = .scaleAspectFill
- rightOprateView.isUserInteractionEnabled = true
- rightOprateView.backgroundColor = UIColor.white
- let panGes = UIPanGestureRecognizer(target: self, action: #selector(panGesture(gesture:)))
- panGes.maximumNumberOfTouches = 1
- panGes.minimumNumberOfTouches = 1
- rightOprateView.addGestureRecognizer(panGes)
- return rightOprateView
- }()
- lazy var topLineView: UIImageView = {
- let topLineView = UIImageView()
- topLineView.backgroundColor = UIColor.white
- return topLineView
- }()
- lazy var bottomLineView: UIImageView = {
- let bottomLineView = UIImageView()
- bottomLineView.backgroundColor = UIColor.white
- return bottomLineView
- }()
- lazy var progressView: PQCuttingPointView = {
- let progressView = PQCuttingPointView(frame: CGRect(x: 0, y: 0, width: progressWidth, height: frame.height))
- let panGes = UIPanGestureRecognizer(target: self, action: #selector(panGesture(gesture:)))
- panGes.maximumNumberOfTouches = 1
- panGes.minimumNumberOfTouches = 1
- progressView.addGestureRecognizer(panGes)
- return progressView
- }()
- 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, minDuration: CGFloat, maxDuration: CGFloat) {
- super.init(frame: frame)
- isUserInteractionEnabled = true
- clipsToBounds = true
- backgroundColor = UIColor.clear
- totalDuration = duration
- cutStartTime = startTime
- cutEndTime = endTime
- cutMinDuration = minDuration
- cutMaxDuration = maxDuration
- if cutMaxDuration <= 0 || cutMaxDuration > totalDuration {
- cutMaxDuration = totalDuration
- }
- if cutMinDuration <= 0 || (cutMinDuration > totalDuration) {
- cutMinDuration = 7
- }
- if cutEndTime <= 0 {
- cutEndTime = cutStartTime + cutMinDuration
- }
- perSecondWidth = 7
- cutTotalTime = cutEndTime - cutStartTime
- configSubview()
- BFLog(message: "======\(frame),perSecondWidth = \(perSecondWidth),cutMaxDuration = \(cutMaxDuration * perSecondWidth)")
- }
- /// 初始化视图
- /// - Returns: <#description#>
- func configSubview() {
- if leftOprateView.superview == nil {
- addSubview(leftOprateView)
- }
- if rightOprateView.superview == nil {
- addSubview(rightOprateView)
- }
- if topLineView.superview == nil {
- addSubview(topLineView)
- }
- if bottomLineView.superview == nil {
- addSubview(bottomLineView)
- }
- if durationLabel.superview == nil {
- addSubview(durationLabel)
- }
- if progressView.superview == nil {
- addSubview(progressView)
- }
- leftOprateView.frame = CGRect(x: leftMargin + perSecondWidth * cutStartTime, y: topMargin, width: cutingOprateWidth, height: frame.height - topMargin - bottomMargin)
- rightOprateView.frame = CGRect(x: leftOprateView.frame.maxX + perSecondWidth * (cutEndTime - cutStartTime), y: leftOprateView.frame.minY, width: cutingOprateWidth, height: frame.height - topMargin - bottomMargin)
- // 更新子视图布局
- updateSubViewFrame()
- }
- /// 更新子视图布局
- /// - Returns: <#description#>
- func updateSubViewFrame() {
- topLineView.frame = CGRect(x: leftOprateView.frame.maxX, y: leftOprateView.frame.minY, width: rightOprateView.frame.minX - leftOprateView.frame.maxX, height: lineHeight)
- bottomLineView.frame = CGRect(x: topLineView.frame.minX, y: leftOprateView.frame.maxY - lineHeight, width: topLineView.frame.width, height: lineHeight)
- progressView.frame = CGRect(x: leftOprateView.frame.maxX - ((progressView.frame.width - 3) / 2), y: 0, width: progressWidth, height: frame.height)
- durationLabel.frame = CGRect(x: topLineView.frame.minX, y: topLineView.frame.maxY, width: topLineView.frame.width, height: bottomLineView.frame.minY - topLineView.frame.maxY)
- durationLabel.text = "\(lround(Double(cutTotalTime)))s"
- }
- /// 更新进度
- /// progress <#progress description#>
- func updateProgress(progress: CGFloat) {
- if currentPanView != nil {
- return
- }
- let width = rightOprateView.frame.minX - leftOprateView.frame.maxX
- var newX = leftOprateView.frame.maxX - ((progressView.frame.width - 3) / 2) + progress * width
- BFLog(message: "progress = \(progress),newX = \(newX)")
- if newX.isNaN || newX <= (leftOprateView.frame.maxX - ((progressView.frame.width - 3) / 2)) {
- newX = (leftOprateView.frame.maxX - ((progressView.frame.width - 3) / 2))
- }
- if newX >= (rightOprateView.frame.minX - (((progressView.frame.width - 3) / 2) + 3)) {
- newX = (rightOprateView.frame.minX - (((progressView.frame.width - 3) / 2) + 3))
- }
- progressView.frame.origin.x = newX
- }
- deinit {
- BFLog(message: "卡点裁剪-裁剪时长视图销毁")
- }
- }
- extension PQVideoCutingOprateView {
- /// 操作手势
- /// - Parameter ges: <#ges description#>
- /// - Returns: <#description#>
- @objc func panGesture(gesture: UIPanGestureRecognizer) {
- switch gesture.state {
- case .began:
- preOriginX = 0
- currentPanView = gesture.view
- case .changed:
- if currentPanView == leftOprateView || currentPanView == rightOprateView || currentPanView == progressView {
- let point = gesture.translation(in: superview)
- var offsetX = point.x - preOriginX
- preOriginX = point.x
- if currentPanView == leftOprateView {
- var oprateFrame = leftOprateView.frame
- oprateFrame.origin.x = oprateFrame.origin.x + offsetX
- if oprateFrame.origin.x <= leftMargin {
- offsetX += leftMargin - oprateFrame.origin.x
- oprateFrame.origin.x = leftMargin
- }
- let minLength = rightOprateView.frame.minX - cutingOprateWidth - cutMinDuration * perSecondWidth
- if oprateFrame.origin.x >= minLength {
- offsetX -= oprateFrame.origin.x - minLength
- oprateFrame.origin.x = minLength
- }
- let maxLength = rightOprateView.frame.minX - cutingOprateWidth - cutMaxDuration * perSecondWidth
- if oprateFrame.origin.x <= maxLength {
- offsetX += maxLength - oprateFrame.origin.x
- oprateFrame.origin.x = maxLength
- }
- let time = offsetX / perSecondWidth
- cutStartTime = cutStartTime + time
- leftOprateView.frame = oprateFrame
- } else if currentPanView == rightOprateView {
- var oprateFrame = rightOprateView.frame
- oprateFrame.origin.x += offsetX
- var rightImageMaxX = leftOprateView.frame.maxX + cutMaxDuration * perSecondWidth
- if rightImageMaxX > frame.width - rightMargin - cutingOprateWidth {
- rightImageMaxX = frame.width - rightMargin - cutingOprateWidth
- }
- if oprateFrame.origin.x >= rightImageMaxX {
- offsetX -= oprateFrame.origin.x - rightImageMaxX
- oprateFrame.origin.x = rightImageMaxX
- }
- let rightImageMinX = leftOprateView.frame.maxX + cutMinDuration * perSecondWidth
- if oprateFrame.origin.x <= rightImageMinX {
- offsetX += rightImageMinX - oprateFrame.origin.x
- oprateFrame.origin.x = rightImageMinX
- }
- let time = offsetX / perSecondWidth
- cutEndTime = cutEndTime + time
- rightOprateView.frame = oprateFrame
- } else if currentPanView == progressView {
- var progressFrame = progressView.frame
- BFLog(message: "progressFrame = \(progressFrame),offsetX = \(offsetX)")
- progressFrame.origin.x += offsetX
- if progressFrame.origin.x <= (leftOprateView.frame.maxX - ((progressView.frame.width - 3) / 2)) {
- progressFrame.origin.x = (leftOprateView.frame.maxX - ((progressView.frame.width - 3) / 2))
- }
- if progressFrame.origin.x >= (rightOprateView.frame.minX - (((progressView.frame.width - 3) / 2) + 3)) {
- progressFrame.origin.x = (rightOprateView.frame.minX - (((progressView.frame.width - 3) / 2) + 3))
- }
- progressView.frame = progressFrame
- BFLog(message: "======\(progressView.frame.minX - (leftOprateView.frame.maxX - ((progressView.frame.width - 3) / 2)))")
- if progressDidChanged != nil {
- progressDidChanged!(progress)
- }
- }
- if currentPanView != progressView {
- cutTotalTime = cutEndTime - cutStartTime
- // 更新子视图布局
- updateSubViewFrame()
- if cutRangeDidChanged != nil {
- BFLog(message: "cutStartTime = \(cutStartTime),cutEndTime = \(cutEndTime)")
- cutRangeDidChanged!(cutStartTime, cutEndTime, cutTotalTime)
- }
- }
- }
- case .ended:
- if currentPanView == leftOprateView || currentPanView == rightOprateView || currentPanView == progressView {
- if didEndDragging != nil {
- didEndDragging!(currentPanView == leftOprateView ? 1 : (currentPanView == rightOprateView ? 2 : 3), cutStartTime, cutEndTime, progress)
- }
- }
- currentPanView = nil
- default:
- break
- }
- }
- }
|