|
@@ -0,0 +1,282 @@
|
|
|
+//
|
|
|
+// PQEditMusicSearchController.swift
|
|
|
+// BFFramework
|
|
|
+//
|
|
|
+// Created by ak on 2021/8/7.
|
|
|
+//
|
|
|
+
|
|
|
+import Foundation
|
|
|
+
|
|
|
+class PQEditMusicSearchController: PQBaseViewController {
|
|
|
+ // 当前播放的音乐
|
|
|
+ var currentPlayData: PQVoiceModel?
|
|
|
+ // 当前播放的视频
|
|
|
+ var playerItem: AVPlayerItem?
|
|
|
+ // 左边距离
|
|
|
+ let leftMargin: CGFloat = 47
|
|
|
+ // 搜索拦高度
|
|
|
+ let searchTFH: CGFloat = 37
|
|
|
+ // 热搜数据
|
|
|
+ var hotList: [Any] = Array<Any>.init()
|
|
|
+ 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 clearBtn: UIButton = {
|
|
|
+ let clearBtn = UIButton(type: .custom)
|
|
|
+ clearBtn.setImage(UIImage().BF_Image(named: "icon_search_delete"), for: .normal)
|
|
|
+ clearBtn.frame = CGRect(x: 0, y: 0, width: 28, height: 32)
|
|
|
+ clearBtn.tag = 1
|
|
|
+ clearBtn.addTarget(self, action: #selector(btnClick(sender:)), for: .touchUpInside)
|
|
|
+ clearBtn.isHidden = true
|
|
|
+ return clearBtn
|
|
|
+ }()
|
|
|
+ // 搜索框
|
|
|
+ lazy var searchTF: UITextField = {
|
|
|
+ let searchTF = UITextField(frame: CGRect(x: leftMargin, y: cDevice_iPhoneStatusBarHei, width: cScreenWidth - leftMargin * 2, height: searchTFH))
|
|
|
+ searchTF.font = UIFont.systemFont(ofSize: 17)
|
|
|
+ searchTF.backgroundColor = PQBFConfig.shared.otherTintColor
|
|
|
+ searchTF.attributedPlaceholder = NSAttributedString(string: "搜索歌曲名称/歌手", attributes: [.foregroundColor: UIColor.hexColor(hexadecimal: "#BDBDBD"), .font: UIFont.systemFont(ofSize: 14)])
|
|
|
+ searchTF.textColor = PQBFConfig.shared.styleTitleColor
|
|
|
+ searchTF.addCorner(corner: searchTFH / 2)
|
|
|
+
|
|
|
+ searchTF.leftViewMode = .always
|
|
|
+ let leftView = UIView(frame: CGRect(x: 0, y: 0, width: 35, height: 32))
|
|
|
+ let imageView = UIImageView(image: UIImage().BF_Image(named: "icon_search_s"))
|
|
|
+ imageView.frame = CGRect(x: 15, y: 8, width: 16, height: 16)
|
|
|
+ leftView.addSubview(imageView)
|
|
|
+ searchTF.leftView = leftView
|
|
|
+ searchTF.delegate = self
|
|
|
+
|
|
|
+ searchTF.rightViewMode = .always
|
|
|
+ let rightView = UIView(frame: CGRect(x: 0, y: 0, width: 40, height: 32))
|
|
|
+ rightView.addSubview(clearBtn)
|
|
|
+ searchTF.rightView = rightView
|
|
|
+ searchTF.delegate = self
|
|
|
+ searchTF.returnKeyType = .search
|
|
|
+ searchTF.addTarget(self, action: #selector(editingChanged), for: .editingChanged)
|
|
|
+ return searchTF
|
|
|
+ }()
|
|
|
+
|
|
|
+ /// 搜索控制器
|
|
|
+ lazy var searchController: PQStuckPointMusicSearchController = {
|
|
|
+ let searchController = PQStuckPointMusicSearchController()
|
|
|
+ searchController.cellHight = cDefaultMargin * 8
|
|
|
+
|
|
|
+ searchController.updateViewFrame(newFrame: CGRect(x: 0, y: cDevice_iPhoneNavBarAndStatusBarHei + cDefaultMargin * 2, width: view.frame.width, height: view.frame.height - (cDevice_iPhoneNavBarAndStatusBarHei + cDefaultMargin * 2)))
|
|
|
+ searchController.didSelectedHandle = { [weak self] isTagsClick, _, _, itemData in
|
|
|
+ if !isTagsClick {
|
|
|
+ self?.view.endEditing(true)
|
|
|
+ if !(itemData is PQEmptyModel) {
|
|
|
+ self?.playStuckPointMusic(itemData: itemData as? PQVoiceModel)
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ searchController.btnClickHandle = { [weak self] _, bgmData in
|
|
|
+ // 使用音乐
|
|
|
+// self?.userstuckPointMusic(musicData: bgmData as? PQVoiceModel)
|
|
|
+ }
|
|
|
+ searchController.scroDidScroHandle = { [weak self] in
|
|
|
+ self?.view.endEditing(true)
|
|
|
+ }
|
|
|
+ searchController.contentType = .serach
|
|
|
+ return searchController
|
|
|
+ }()
|
|
|
+ override func viewDidLoad() {
|
|
|
+ super.viewDidLoad()
|
|
|
+ view.addSubview(searchTF)
|
|
|
+
|
|
|
+ addChild(searchController)
|
|
|
+ view.addSubview(searchController.view)
|
|
|
+
|
|
|
+ leftButton(image: "upload_delete", tintColor: PQBFConfig.shared.styleTitleColor)
|
|
|
+ PQStuckPointViewModel.stuckPointMusicPageList(tagId: 999, parentTagId: 0, pageNum: 1, videoCount: 0, imageCount: 0, totalDuration: 0) { [weak self] musicInfo, _ in
|
|
|
+
|
|
|
+ if musicInfo.count > 0 {
|
|
|
+ self?.searchController.hotList = musicInfo
|
|
|
+ }
|
|
|
+
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ /// 按钮点击事件
|
|
|
+ /// - Parameter sender: <#sender description#>
|
|
|
+ /// - Returns: <#description#>
|
|
|
+ @objc func btnClick(sender: UIButton) {
|
|
|
+ switch sender.tag {
|
|
|
+ case 1: // 清除
|
|
|
+ searchTF.text = nil
|
|
|
+// emptyRemindView.isHidden = true
|
|
|
+ clearBtn.isHidden = true
|
|
|
+ default:
|
|
|
+ break
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ /// 播放音乐
|
|
|
+ /// - 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()
|
|
|
+// let player = TXVodPlayer()
|
|
|
+// let config = TXVodPlayConfig()
|
|
|
+// config.cacheFolderPath = videoCacheDirectory
|
|
|
+// config.maxCacheItems = 0
|
|
|
+// player.config = config
|
|
|
+ //// player.vodDelegate = self
|
|
|
+// player.setRenderMode(.RENDER_MODE_FILL_EDGE)
|
|
|
+// player.startPlay("https://clipres.yishihui.com/longvideo/material/voice/prod/20210512/MUSIC_QQ_000T1Ws32MWrUj")
|
|
|
+ currentPlayData = itemData
|
|
|
+ } else if itemData != nil, avPlayer.rate == 0.0 {
|
|
|
+ avPlayer.play()
|
|
|
+ } else {
|
|
|
+ avPlayer.pause()
|
|
|
+
|
|
|
+ }
|
|
|
+ if isClearCurrentMusic {
|
|
|
+ avPlayer.pause()
|
|
|
+ currentPlayData = nil
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+/// 音乐搜索相关
|
|
|
+extension PQEditMusicSearchController: UITextFieldDelegate {
|
|
|
+ /// 点击输入框
|
|
|
+ @objc func editingChanged() {
|
|
|
+ if searchTF.text != nil, (searchTF.text?.count ?? 0) > 0, searchTF.markedTextRange == nil {
|
|
|
+ if searchTF.text?.isSpace ?? false {
|
|
|
+ return
|
|
|
+ }
|
|
|
+// loadSearchData()
|
|
|
+ clearBtn.isHidden = false
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ /// 搜索
|
|
|
+ @objc func loadSearchData() {
|
|
|
+ if searchTF.text != nil, (searchTF.text?.count ?? 0) > 0, searchTF.text?.isSpace ?? false {
|
|
|
+ cShowHUB(superView: nil, msg: "搜索内容不能为空")
|
|
|
+ return
|
|
|
+ }
|
|
|
+ if searchTF.text != nil, (searchTF.text?.count ?? 0) > 0 {
|
|
|
+ BFLog(message: "背景音乐--开始搜索背景音乐-1")
|
|
|
+ searchController.loadSearchData(keyword: searchTF.text)
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ /// 添加键盘监听
|
|
|
+ /// - Returns: <#description#>
|
|
|
+ func addKeyboardObserver() {
|
|
|
+ // 监听键盘的显示和隐藏
|
|
|
+ PQNotification.addObserver(self, selector: #selector(keyboardWillShow(notification:)), name: UIResponder.keyboardWillShowNotification, object: nil)
|
|
|
+ PQNotification.addObserver(self, selector: #selector(keyboardWillHidden), name: UIResponder.keyboardWillHideNotification, object: nil)
|
|
|
+ }
|
|
|
+
|
|
|
+ /// 键盘显示
|
|
|
+ /// - Parameter notification: <#notification description#>
|
|
|
+ @objc func keyboardWillShow(notification: Notification) {
|
|
|
+ let duration: TimeInterval = TimeInterval("\(notification.userInfo?["UIKeyboardAnimationDurationUserInfoKey"] ?? "1")") ?? 1
|
|
|
+ UIView.animate(withDuration: duration) { [weak self] in
|
|
|
+ self?.navTitleLabel?.alpha = 0
|
|
|
+ self?.searchTF.frame = CGRect(x: cDefaultMargin * 5, y: (cDevice_iPhoneNavBarHei - (self?.searchTFH ?? 37.0)) / 2 + cDevice_iPhoneStatusBarHei, width: cScreenWidth - cDefaultMargin * 7, height: self?.searchTFH ?? 37.0)
|
|
|
+ } completion: { _ in
|
|
|
+ }
|
|
|
+ searchController.view.isHidden = false
|
|
|
+ hotList.forEach { item in
|
|
|
+ if item is PQVoiceModel {
|
|
|
+ (item as? PQVoiceModel)?.isSelected = false
|
|
|
+ (item as? PQVoiceModel)?.isPlaying = false
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ searchController.hotList = hotList
|
|
|
+ playStuckPointMusic(itemData: nil)
|
|
|
+
|
|
|
+ }
|
|
|
+
|
|
|
+ /// 键盘将要隐藏
|
|
|
+ @objc func keyboardWillHidden() {}
|
|
|
+
|
|
|
+ /// 隐藏搜索界面
|
|
|
+ /// - Returns: <#description#>
|
|
|
+ func hiddenSearchController() {
|
|
|
+ view.endEditing(true)
|
|
|
+ UIView.animate(withDuration: 0.3) { [weak self] in
|
|
|
+ self?.navTitleLabel?.alpha = 1
|
|
|
+ self?.searchTF.frame = CGRect(x: self?.leftMargin ?? 0, y: cDevice_iPhoneNavBarAndStatusBarHei, width: cScreenWidth - (self?.leftMargin ?? 0) * 2, height: self?.searchTFH ?? 0)
|
|
|
+ } completion: { _ in
|
|
|
+ }
|
|
|
+ clearBtn.isHidden = true
|
|
|
+ searchController.view.isHidden = true
|
|
|
+ playStuckPointMusic(itemData: nil)
|
|
|
+ }
|
|
|
+
|
|
|
+ override func touchesBegan(_: Set<UITouch>, with _: UIEvent?) {
|
|
|
+ view.endEditing(true)
|
|
|
+ }
|
|
|
+
|
|
|
+ func textFieldShouldReturn(_ textField: UITextField) -> Bool {
|
|
|
+ loadSearchData()
|
|
|
+ view.endEditing(true)
|
|
|
+ if textField.text == nil || (textField.text?.count ?? 0) <= 0 {
|
|
|
+ cShowHUB(superView: nil, msg: "请先输入搜索内容")
|
|
|
+ }
|
|
|
+ return true
|
|
|
+ }
|
|
|
+}
|
|
|
+extension PQEditMusicSearchController {
|
|
|
+ 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))")
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|
|
|
+
|