Parcourir la source

音乐选择界面

jsonwang il y a 3 ans
Parent
commit
181a2f7f8c

+ 71 - 3
BFFramework/Classes/Stuckpoint/Controller/PQStuckPointEditerController.swift

@@ -69,6 +69,9 @@ class PQStuckPointEditerController: PQBaseViewController {
         playerView.backgroundColor = PQBFConfig.shared.styleBackGroundColor
         playerView.isShowLine = false
         playerView.showGaussianBlur = true
+        playerView.renderViewOnClickHandle = {[weak self] in
+            self?.musicEditBGView.pausePlayer()
+        }
         playerView.playerEmptyView.isHidden = true
         return playerView
     }()
@@ -92,7 +95,8 @@ class PQStuckPointEditerController: PQBaseViewController {
 
     /// 裁剪视图
     lazy var stuckPointCuttingView: PQStuckPointCuttingView = {
-        let stuckPointCuttingView = PQStuckPointCuttingView(frame: CGRect(x: 0, y: sustomSwitchView.frame.minY - cDefaultMargin * 14 - cDefaultMargin * 2, width: view.frame.width, height: cDefaultMargin * 14), duration: CGFloat(Float(stuckPointMusicData?.duration ?? "0") ?? 0), startTime: CGFloat(stuckPointMusicData?.startTime ?? 0), endTime: CGFloat(stuckPointMusicData?.endTime ?? 0))
+         
+        let stuckPointCuttingView = PQStuckPointCuttingView(frame: CGRect(x: 0, y: optionlineView.frame.minY - 85 - 28, width: view.frame.width, height: 85), duration: CGFloat(Float(stuckPointMusicData?.duration ?? "0") ?? 0), startTime: CGFloat(stuckPointMusicData?.startTime ?? 0), endTime: CGFloat(stuckPointMusicData?.endTime ?? 0))
         /// 裁剪进度回调
         stuckPointCuttingView.videoRangeDidChanged = { [weak self] startTime, endTime in
             BFLog(message: "裁剪返回--startTime = \(startTime),endTime = \(endTime)")
@@ -182,6 +186,41 @@ class PQStuckPointEditerController: PQBaseViewController {
         pointEditBGView.backgroundColor = .clear
         return pointEditBGView
     }()
+    
+    /// 下方音乐编辑操作区背景
+    lazy var musicEditBGView: PQSelecteMusicView = {
+        let musicEditBGView = PQSelecteMusicView.init()
+        musicEditBGView.backgroundColor = .clear
+        musicEditBGView.isUserInteractionEnabled = true
+        musicEditBGView.isHidden = true
+        musicEditBGView.musicSearchBtn.addTarget(self, action: #selector(musicSearchBtnClick(sender:)), for: .touchUpInside)
+        
+        musicEditBGView.didSelectItemHandle = { [weak self] isplaying in
+            self?.playerView.pause()
+        }
+        musicEditBGView.btnClickHandle = { [weak self] _, bgmData in
+            
+            //音乐面板点击了使用
+            self?.stuckPointMusicData = bgmData as? PQVoiceModel
+            //同步最新音乐数据
+            self?.synchroMusicInfoData()
+            
+            //更新音乐标题UI
+            let nameWidth: CGFloat = sizeWithText(text: "\(self?.stuckPointMusicData?.musicName ?? "")", font: UIFont.systemFont(ofSize: 13), size: CGSize(width: (self?.view.frame.width ?? 0) - ((cDefaultMargin * 6 + 16 * 2) * 2) - (25 + cDefaultMargin * 3), height: cDefaultMargin * 3)).width
+            
+            if nameWidth < cDefaultMargin * 4 {
+                self?.musicNameLab.text = " \(self?.stuckPointMusicData?.musicName ?? "") "
+            } else {
+                self?.musicNameLab.text = " \(self?.stuckPointMusicData?.musicName ?? "") "
+            }
+      
+        }
+        
+        return musicEditBGView
+    }()
+ 
+    
+
 
     // 卡点编辑 btn
     lazy var pointEditerBtn: UIButton = {
@@ -344,12 +383,18 @@ class PQStuckPointEditerController: PQBaseViewController {
         // 点击上报:返回按钮
         PQEventTrackViewModel.baseReportUpload(businessType: .bt_buttonClick, objectType: .ot_click_back, pageSource: .sp_stuck_previewSyncedUp, extParams: nil, remindmsg: "卡点视频数据上报-(点击上报:返回按钮)")
     }
-
+    //点击搜索音乐
+    @objc func musicSearchBtnClick(sender: UIButton) {
+        
+    }
+    
     // 卡点编辑
     @objc func pointEditerBtnClick(sender: UIButton) {
         if sender.isSelected { return }
         sender.isSelected = !sender.isSelected
         musicEditerBtn.isSelected = false
+        pointEditBGView.isHidden = false
+        musicEditBGView.isHidden = true
     }
 
     // 音乐编辑
@@ -357,6 +402,8 @@ class PQStuckPointEditerController: PQBaseViewController {
         if sender.isSelected { return }
         sender.isSelected = !sender.isSelected
         pointEditerBtn.isSelected = false
+        pointEditBGView.isHidden = true
+        musicEditBGView.isHidden = false
     }
 
     // 三种模式修改
@@ -429,12 +476,14 @@ class PQStuckPointEditerController: PQBaseViewController {
         }
         view.addSubview(playerView)
         view.addSubview(pointEditBGView)
+        view.addSubview(musicEditBGView)
         view.addSubview(optionlineView)
 
         view.addSubview(pointEditerBtn)
         view.addSubview(musicEditerBtn)
         view.addSubview(customSpeedSettingView)
 
+        //卡点
         pointEditBGView.addSubview(pointEditRemindLab)
         pointEditBGView.addSubview(speedTitleLab)
         pointEditBGView.addSubview(speedStuckBtn)
@@ -443,7 +492,10 @@ class PQStuckPointEditerController: PQBaseViewController {
         pointEditBGView.addSubview(editModelLineView)
         pointEditBGView.addSubview(speedSettingView)
         pointEditBGView.addSubview(sustomSwitchView)
-//        view.addSubview(stuckPointCuttingView)
+        
+        //音乐
+        musicEditBGView.addSubview(stuckPointCuttingView)
+
 
         pointEditerBtn.snp.makeConstraints { make in
             make.left.equalToSuperview().offset(100)
@@ -463,11 +515,27 @@ class PQStuckPointEditerController: PQBaseViewController {
             make.bottom.equalTo(pointEditerBtn.snp_top).offset(-7)
             make.height.equalTo(290)
         }
+        musicEditBGView.snp.makeConstraints { make in
+            make.left.right.equalTo(view)
+            make.bottom.equalTo(pointEditerBtn.snp_top).offset(-7)
+            make.height.equalTo(290)
+        }
+        stuckPointCuttingView.snp.makeConstraints { make in
+            make.left.right.equalTo(view)
+            make.bottom.equalTo(pointEditerBtn.snp_top).offset(-7)
+            make.height.equalTo(290)
+        }
         optionlineView.snp.makeConstraints { make in
             make.left.right.equalToSuperview()
             make.bottom.equalTo(pointEditBGView.snp_bottom).offset(-1)
             make.height.equalTo(1)
         }
+        
+        stuckPointCuttingView.snp.makeConstraints { make in
+            make.left.right.equalToSuperview()
+            make.bottom.equalTo(musicEditBGView.snp_bottom).offset(-1)
+            make.height.equalTo(85)
+        }
         pointEditRemindLab.snp.makeConstraints { make in
             make.left.equalToSuperview().offset(16)
             make.top.equalToSuperview().offset(16)

+ 522 - 0
BFFramework/Classes/Stuckpoint/View/PQSelecteMusicView.swift

@@ -0,0 +1,522 @@
+//
+//  PQSelecteMusic.swift
+//  BFFramework
+//
+//  Created by ak on 2021/8/4.
+//  功能:显示编辑界面里的音乐选择界面
+
+import Foundation
+
+class PQSelecteMusicView: UIView {
+    // 所有分类数据
+    var catageryDatas: [PQStuckPointMusicTagsModel] = Array<PQStuckPointMusicTagsModel>.init()
+
+    // 歌单数据
+    var musicDatas: [PQVoiceModel] = Array<PQVoiceModel>.init()
+    // 当前页码
+    var pageNum: Int = 0
+    
+    // 当前播放的音乐
+    var currentPlayData: PQVoiceModel?
+    // 当前播放的视频
+    var playerItem: AVPlayerItem?
+    
+    // 按钮点击的回调
+    var btnClickHandle: ((_ sender: UIButton, _ bgmData: Any?) -> Void)?
+    
+    // 点击播放一个歌,回调
+    var didSelectItemHandle:((_ isPlaying:Bool) -> Void)?
+ 
+    lazy var avPlayer: AVPlayer = {
+        let avPlayer = AVPlayer()
+        PQNotification.addObserver(forName: .AVPlayerItemDidPlayToEndTime, object: avPlayer.currentItem, queue: .main) { [weak self] notify in
+            BFLog(message: "AVPlayerItemDidPlayToEndTime = \(notify)")
+            avPlayer.seek(to: CMTime(value: CMTimeValue((self?.currentPlayData?.startTime ?? 0) * 1000), timescale: CMTimeScale(playerTimescale)))
+//            avPlayer.play()
+//            self?.playStuckPointMusic(itemData: nil)
+        }
+        PQNotification.addObserver(forName: .AVPlayerItemNewErrorLogEntry, object: avPlayer.currentItem, queue: .main) { notify in
+            BFLog(message: "AVPlayerItemNewErrorLogEntry = \(notify)")
+        }
+        PQNotification.addObserver(forName: .AVPlayerItemFailedToPlayToEndTime, object: avPlayer.currentItem, queue: .main) { notify in
+            BFLog(message: "AVPlayerItemFailedToPlayToEndTime = \(notify)")
+        }
+        PQNotification.addObserver(forName: .AVPlayerItemPlaybackStalled, object: avPlayer.currentItem, queue: .main) { notify in
+            BFLog(message: "AVPlayerItemPlaybackStalled = \(notify)")
+        }
+        avPlayer.addPeriodicTimeObserver(forInterval: CMTime(value: 1, timescale: CMTimeScale(playerTimescale)), queue: .main) { [weak self] cmTime in
+            BFLog(message: "addPeriodicTimeObserver = \(cmTime)")
+        }
+        return avPlayer
+    }()
+    
+    // 音乐分类的
+    lazy var categoryCollection: UICollectionView = {
+        let flowLayout = UICollectionViewFlowLayout()
+        flowLayout.sectionInset = UIEdgeInsets.zero
+        flowLayout.minimumLineSpacing = 0
+        flowLayout.minimumInteritemSpacing = 0
+        flowLayout.scrollDirection = .horizontal
+
+        let categoryCollection = UICollectionView(frame: .zero, collectionViewLayout: flowLayout)
+        categoryCollection.showsVerticalScrollIndicator = false
+        categoryCollection.showsHorizontalScrollIndicator = false
+        categoryCollection.delegate = self
+        categoryCollection.dataSource = self
+        categoryCollection.backgroundColor = .clear
+        categoryCollection.register(PQSelectMusicTagsCell.self, forCellWithReuseIdentifier: String(describing: PQSelectMusicTagsCell.self))
+        categoryCollection.delaysContentTouches = false
+
+        return categoryCollection
+    }()
+
+    // 每一个分类下所有歌曲
+    lazy var selectMusicCollection: UICollectionView = {
+        let flowLayout = UICollectionViewFlowLayout()
+        flowLayout.sectionInset = UIEdgeInsets.zero
+        flowLayout.minimumLineSpacing = 0
+        flowLayout.minimumInteritemSpacing = 0
+        flowLayout.scrollDirection = .horizontal
+
+        let selectMusicCollection = UICollectionView(frame: .zero, collectionViewLayout: flowLayout)
+        selectMusicCollection.showsVerticalScrollIndicator = false
+        selectMusicCollection.showsHorizontalScrollIndicator = false
+        selectMusicCollection.delegate = self
+        selectMusicCollection.dataSource = self
+        selectMusicCollection.backgroundColor = .clear
+        selectMusicCollection.register(PQSelectMusicCell.self, forCellWithReuseIdentifier: String(describing: PQSelectMusicCell.self))
+        selectMusicCollection.delaysContentTouches = false
+        return selectMusicCollection
+    }()
+
+    // 搜索音乐btn
+    lazy var musicSearchBtn: UIButton = {
+        let musicSearchBtn = UIButton(type: .custom)
+        musicSearchBtn.setTitle("搜索", for: .normal)
+        musicSearchBtn.setImage(UIImage().BF_Image(named: "musicSearch"), for: .normal)
+        musicSearchBtn.setTitleColor(UIColor.hexColor(hexadecimal: "#959595"), for: .normal)
+        musicSearchBtn.titleLabel?.font = UIFont.boldSystemFont(ofSize: 14)
+
+        return musicSearchBtn
+    }()
+
+    override init(frame: CGRect) {
+        super.init(frame: frame)
+        addSubview(categoryCollection)
+        addSubview(selectMusicCollection)
+        addSubview(musicSearchBtn)
+
+        autolayout()
+
+        loadRequestTagsList()
+    }
+
+    required init?(coder _: NSCoder) {
+        fatalError("init(coder:) has not been implemented")
+    }
+
+    func autolayout() {
+        categoryCollection.snp.makeConstraints { make in
+            make.height.equalTo(20)
+            make.left.equalToSuperview().offset(91)
+            make.right.equalToSuperview()
+            make.top.equalToSuperview().offset(14)
+        }
+        selectMusicCollection.snp.makeConstraints { make in
+            make.height.equalTo(131)
+            make.left.equalToSuperview().offset(17)
+            make.right.equalToSuperview()
+            make.top.equalToSuperview().offset(54)
+        }
+
+        musicSearchBtn.snp.makeConstraints { make in
+            make.left.equalToSuperview().offset(12)
+            make.top.equalToSuperview().offset(14)
+            make.height.equalTo(20)
+            make.width.equalTo(60)
+        }
+        musicSearchBtn.imagePosition(at: .left, space: 8)
+    }
+
+    /// 请求标签数据
+    /// - Returns: <#description#>
+    func loadRequestTagsList() {
+        PQStuckPointViewModel.stuckPointMusicCategoryList { [weak self] tags, _, _ in
+
+            if tags.count > 0 {
+                // 请求列表数据
+                self?.requestPageListData(isRefresh: true, tagId: tags.first?.tagId ?? 0)
+
+                self?.catageryDatas = tags
+
+                self?.categoryCollection.reloadData()
+            }
+        }
+    }
+
+    /// 请求指定分类的歌列表数据
+    /// - Returns:
+    func requestPageListData(isRefresh: Bool = true, isHotPage _: Bool = false, tagId: Int64) {
+        if isRefresh {
+            pageNum = 1
+        }
+        PQStuckPointViewModel.stuckPointMusicPageList(tagId: tagId, pageNum: pageNum, videoCount: 0, imageCount: 0, totalDuration: 0) { [weak self] musicInfo, _ in
+
+            if musicInfo.count > 0 {
+                self?.pageNum = (self?.pageNum ?? 0) + 1
+            }
+
+            self?.musicDatas = musicInfo
+            self?.selectMusicCollection.reloadData()
+        }
+    }
+    
+    /// 播放音乐
+    /// - Parameter itemData: <#itemData description#>
+    func playStuckPointMusic(itemData: PQVoiceModel?, isClearCurrentMusic: Bool = false) {
+        if itemData != nil, currentPlayData != itemData {
+            if !isValidURL(url: itemData?.musicPath ?? "") {
+                cShowHUB(superView: nil, msg: "本歌曲暂无伴奏版本哦~")
+                return
+            }
+            avPlayer.pause()
+            playerItem?.removeObserver(self, forKeyPath: "status")
+            playerItem?.removeObserver(self, forKeyPath: "error")
+            playerItem = AVPlayerItem(url: URL(string: itemData?.musicPath ?? "")!)
+            if (itemData?.endTime ?? 0) > 0, (itemData?.endTime ?? 0) > (itemData?.startTime ?? 0) {
+                playerItem?.forwardPlaybackEndTime = CMTime(value: CMTimeValue((itemData?.endTime ?? 0) * playerTimescale), timescale: CMTimeScale(playerTimescale))
+            }
+            avPlayer.replaceCurrentItem(with: playerItem)
+            playerItem?.addObserver(self, forKeyPath: "status", options: .new, context: nil)
+            playerItem?.addObserver(self, forKeyPath: "error", options: .new, context: nil)
+            avPlayer.seek(to: CMTime(value: CMTimeValue((itemData?.startTime ?? 0) * playerTimescale), timescale: CMTimeScale(playerTimescale)))
+            avPlayer.play()
+            itemData?.isPlaying = true
+
+            currentPlayData = itemData
+        } else if itemData != nil, avPlayer.rate == 0.0 {
+            avPlayer.play()
+            itemData?.isPlaying = true
+        } else {
+            avPlayer.pause()
+            itemData?.isPlaying = false
+      
+        }
+        if isClearCurrentMusic {
+            avPlayer.pause()
+            currentPlayData = nil
+        }
+    }
+    
+    //暂停播放音乐 并刷新 UI
+    func pausePlayer() {
+        
+        playStuckPointMusic(itemData: currentPlayData)
+        selectMusicCollection.reloadData()
+    }
+   
+}
+
+extension PQSelecteMusicView {
+    override func observeValue(forKeyPath keyPath: String?, of object: Any?, change _: [NSKeyValueChangeKey: Any]?, context _: UnsafeMutableRawPointer?) {
+        if object is AVPlayerItem, keyPath == "status" {
+            BFLog(message: "AVPlayerItem - status = \((object as! AVPlayerItem).status.rawValue)")
+            switch (object as! AVPlayerItem).status {
+            case .unknown:
+                break
+            case .readyToPlay:
+                break
+            case .failed:
+                break
+            default:
+                break
+            }
+        } else if object is AVPlayerItem, keyPath == "error" {
+            BFLog(message: "AVPlayerItem - error = \(String(describing: (object as! AVPlayerItem).error))")
+        }
+    }
+}
+
+/// 卡点音乐相关代理
+extension PQSelecteMusicView: UICollectionViewDelegate, UICollectionViewDataSource, UICollectionViewDelegateFlowLayout, UIScrollViewDelegate {
+    func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection _: Int) -> Int {
+        if collectionView == selectMusicCollection {
+            return musicDatas.count
+        }
+        return catageryDatas.count
+    }
+
+    func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
+        if collectionView == selectMusicCollection {
+            let itemData: Any = musicDatas[indexPath.item]
+            let cell = collectionView.dequeueReusableCell(withReuseIdentifier: String(describing: PQSelectMusicCell.self), for: indexPath) as! PQSelectMusicCell
+            cell.bgmData = itemData as? PQVoiceModel
+            cell.btnClickHandle = { [weak self] sender, bgmData in
+                
+                //暂停播放音乐
+                self?.musicDatas[indexPath.item].isSelected = true
+                self?.playStuckPointMusic(itemData:  self?.musicDatas[indexPath.item])
+                self?.selectMusicCollection.reloadData()
+                
+                if self?.btnClickHandle != nil {
+                    self?.btnClickHandle!(sender, bgmData)
+                    
+                }
+            }
+         
+            return cell
+        }
+        let itemData: Any = catageryDatas[indexPath.item]
+        let cell = collectionView.dequeueReusableCell(withReuseIdentifier: String(describing: PQSelectMusicTagsCell.self), for: indexPath) as! PQSelectMusicTagsCell
+        cell.tagData = itemData as? PQStuckPointMusicTagsModel
+
+        return cell
+    }
+
+    func collectionView(_ collectionView: UICollectionView, layout _: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
+        if collectionView == selectMusicCollection {
+            return CGSize(width: 60 + 20, height: 131)
+        }
+        // 音乐分类要根据文字自适应宽度
+        let textSize = sizeWithText(text: catageryDatas[indexPath.item].tagName ?? "", font: UIFont.systemFont(ofSize: 14, weight: .regular), size: CGSize(width: CGFloat.greatestFiniteMagnitude, height: 20.0))
+
+        return CGSize(width: textSize.width + 26, height: collectionView.frame.height)
+    }
+
+    func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
+        
+        //歌曲列表
+        if (collectionView == selectMusicCollection ){
+            musicDatas.forEach { item in
+                item.isSelected = false
+            }
+            musicDatas[indexPath.item].isSelected = true
+            playStuckPointMusic(itemData: musicDatas[indexPath.item])
+            selectMusicCollection.reloadData()
+
+            if didSelectItemHandle != nil {
+                didSelectItemHandle!(musicDatas[indexPath.item].isPlaying)
+            }
+         
+        }else{
+    
+            if !isNetConnected() {
+                cShowHUB(superView: nil, msg: "请有网时再试")
+                return
+            }
+
+            catageryDatas.forEach { item in
+                item.isSelected = false
+            }
+            catageryDatas[indexPath.item].isSelected = true
+            categoryCollection.reloadData()
+        }
+   
+    }
+
+    func collectionView(_: UICollectionView, willDisplay _: UICollectionViewCell, forItemAt indexPath: IndexPath) {}
+}
+
+// 分类 cell
+class PQSelectMusicTagsCell: UICollectionViewCell {
+    lazy var titleLab: UILabel = {
+        let titleLab = UILabel()
+        titleLab.font = UIFont.boldSystemFont(ofSize: 14)
+        titleLab.textColor = UIColor.hexColor(hexadecimal: "#959595")
+        titleLab.textAlignment = .center
+        titleLab.backgroundColor = PQBFConfig.shared.styleBackGroundColor
+        return titleLab
+    }()
+
+    override init(frame: CGRect) {
+        super.init(frame: frame)
+        contentView.addSubview(titleLab)
+    }
+
+    required init?(coder _: NSCoder) {
+        fatalError("init(coder:) has not been implemented")
+    }
+
+    var tagData: PQStuckPointMusicTagsModel? {
+        didSet {
+            addData()
+            addLayout()
+        }
+    }
+
+    func addData() {
+        titleLab.text = "\(tagData?.tagName ?? "")"
+        if tagData?.isSelected ?? false {
+            titleLab.textColor = UIColor.hexColor(hexadecimal: PQBFConfig.shared.styleColor.rawValue)
+
+        } else {
+            titleLab.textColor = UIColor.hexColor(hexadecimal: "#959595")
+        }
+    }
+
+    func addLayout() {
+        titleLab.snp.makeConstraints { make in
+            make.size.equalToSuperview()
+        }
+    }
+}
+
+// 歌曲cell PQSelectMusicCell
+class PQSelectMusicCell: UICollectionViewCell {
+    // 按钮点击的回调
+    var btnClickHandle: ((_ sender: UIButton, _ bgmData: Any?) -> Void)?
+    var contentType: stuckPointMusicContentType = .catagery
+
+    lazy var audioImageView: UIImageView = {
+        let audioImageView = UIImageView(image: UIImage().BF_Image(named: "videomk_music_default"))
+        audioImageView.addCorner(corner: 4)
+        audioImageView.contentMode = .scaleAspectFill
+        return audioImageView
+    }()
+
+    lazy var imageMaskView: UIView = {
+        let imageMaskView = UIView()
+        imageMaskView.backgroundColor = UIColor.hexColor(hexadecimal: PQBFConfig.shared.styleColor.rawValue,alpha: 0.76)
+        imageMaskView.addCorner(corner: 4)
+        return imageMaskView
+    }()
+
+    lazy var playImageView: UIImageView = {
+        let playImageView = UIImageView()
+        playImageView.image = UIImage().BF_Image(named: "stuckPoint_music_pause")
+        return playImageView
+    }()
+
+    lazy var titleLab: UILabel = {
+        let titleLab = UILabel()
+        titleLab.font = UIFont.systemFont(ofSize: 14)
+        titleLab.textColor = PQBFConfig.shared.styleTitleColor
+        return titleLab
+    }()
+
+    /// 音乐歌曲名称
+    lazy var musicNameLab: UILabel = {
+        let musicNameLab = UILabel()
+        musicNameLab.textColor = UIColor.hexColor(hexadecimal: "#959595")
+        musicNameLab.font = UIFont.systemFont(ofSize: 12)
+        musicNameLab.textAlignment = .center
+        musicNameLab.lineBreakMode = .byTruncatingTail
+        musicNameLab.numberOfLines = 2
+        return musicNameLab
+    }()
+
+    // 使用按钮
+    lazy var confirmBtn: UIButton = {
+        let confirmBtn = UIButton(type: .custom)
+        confirmBtn.setTitle("使用", for: .normal)
+        confirmBtn.setTitleColor(UIColor.white, for: .normal)
+        confirmBtn.titleLabel?.font = UIFont.systemFont(ofSize: 14, weight: .medium)
+        confirmBtn.addTarget(self, action: #selector(confirmClick(sender:)), for: .touchUpInside)
+        confirmBtn.addCorner(corner: 4)
+        confirmBtn.backgroundColor = UIColor.hexColor(hexadecimal: PQBFConfig.shared.styleColor.rawValue)
+        return confirmBtn
+    }()
+
+    lazy var remindView: UIView = {
+        let remindView = UIView()
+        remindView.backgroundColor = UIColor.hexColor(hexadecimal: PQBFConfig.shared.styleColor.rawValue)
+        remindView.addCorner(corner: 3)
+        return remindView
+    }()
+
+    @objc class func stuckPointMusicContentCell(collectionView: UICollectionView, indexPath: IndexPath) -> PQStuckPointMusicContentCell {
+        let cell: PQStuckPointMusicContentCell = collectionView.dequeueReusableCell(withReuseIdentifier: String(describing: PQStuckPointMusicContentCell.self), for: indexPath) as! PQStuckPointMusicContentCell
+        return cell
+    }
+
+    override init(frame: CGRect) {
+        super.init(frame: frame)
+        contentView.addSubview(audioImageView)
+        audioImageView.addSubview(imageMaskView)
+        audioImageView.addSubview(playImageView)
+        contentView.addSubview(titleLab)
+        contentView.addSubview(musicNameLab)
+        contentView.addSubview(remindView)
+        contentView.addSubview(confirmBtn)
+        
+        
+    }
+
+    required init?(coder _: NSCoder) {
+        fatalError("init(coder:) has not been implemented")
+    }
+
+    var bgmData: PQVoiceModel? {
+        didSet {
+            addData()
+            addLayout()
+        }
+    }
+
+    func addData() {
+        audioImageView.setNetImage(url: "\(bgmData?.avatarUrl ?? "")", placeholder: UIImage().BF_Image(named: "videomk_music_default"))
+        
+        musicNameLab.text = bgmData?.musicName ?? ""
+        
+        if bgmData?.isSelected ?? false {
+            playImageView.isHidden = false
+            if bgmData?.isPlaying ?? false {
+                playImageView.image = nil
+                playImageView.kf.setImage(with: URL(fileURLWithPath: Bundle().BF_mainbundle().path(forResource: "stuckPoint_music_playing", ofType: ".gif")!))
+
+            } else {
+                playImageView.image = UIImage().BF_Image(named: "stuckPoint_music_pause")
+            }
+            imageMaskView.isHidden = false
+        } else {
+            playImageView.isHidden = true
+            playImageView.image = nil
+            
+            imageMaskView.isHidden = true
+        }
+        
+        confirmBtn.isHidden = !(bgmData?.isSelected ?? false)
+
+        musicNameLab.textColor = (bgmData?.isSelected ?? false) ? UIColor.hexColor(hexadecimal: PQBFConfig.shared.styleColor.rawValue):  UIColor.hexColor(hexadecimal: "#959595")
+
+    }
+
+    func addLayout() {
+      
+        audioImageView.snp.remakeConstraints { make in
+            make.left.top.equalToSuperview()
+            make.width.height.equalTo(60)
+        }
+        imageMaskView.snp.makeConstraints { make in
+            make.size.equalTo(audioImageView)
+        }
+        playImageView.snp.remakeConstraints { make in
+            make.center.equalToSuperview()
+            make.width.height.equalTo(cDefaultMargin * 2)
+        }
+
+        musicNameLab.snp.remakeConstraints { make in
+            make.width.equalTo(60)
+            make.height.equalTo(30)
+            make.top.equalTo(audioImageView.snp_bottom).offset(6)
+        }
+ 
+        confirmBtn.snp.remakeConstraints { make in
+            make.width.equalTo(54)
+            make.height.equalTo(29)
+            make.top.equalTo(musicNameLab.snp_bottom).offset(6)
+            make.left.equalToSuperview()
+          
+        }
+        audioImageView.addCorner(corner: 60 / 2)
+        imageMaskView.addCorner(corner: 60 / 2)
+    }
+
+    @objc func confirmClick(sender: UIButton) {
+        if btnClickHandle != nil {
+            btnClickHandle!(confirmBtn, bgmData)
+        }
+    }
+}
+
+